Пример #1
0
 def processStockDividend(self, ledger):
     asset_amount = ledger.getAmount(BookAccount.Assets, self._account,
                                     self._asset)
     if asset_amount < -Setup.CALC_TOLERANCE:
         raise NotImplemented(
             self.tr(
                 "Not supported action: stock dividend closes short trade.")
             + f" Operation: {self.dump()}")
     quote = JalDB().get_quote(self._asset,
                               JalDB().get_account_currency(self._account),
                               self._timestamp)
     if quote is None:
         raise ValueError(
             self.tr("No stock quote for stock dividend.") +
             f" Operation: {self.dump()}")
     _ = executeSQL(
         "INSERT INTO open_trades(timestamp, op_type, operation_id, account_id, asset_id, price, remaining_qty) "
         "VALUES(:timestamp, :type, :operation_id, :account_id, :asset_id, :price, :remaining_qty)",
         [(":timestamp", self._timestamp), (":type", self._otype),
          (":operation_id", self._oid), (":account_id", self._account),
          (":asset_id", self._asset), (":price", quote),
          (":remaining_qty", self._amount)])
     ledger.appendTransaction(self,
                              BookAccount.Assets,
                              self._amount,
                              asset_id=self._asset,
                              value=self._amount * quote)
     if self._tax:
         ledger.appendTransaction(self, BookAccount.Money, -self._tax)
         ledger.appendTransaction(self,
                                  BookAccount.Costs,
                                  self._tax,
                                  category=PredefinedCategory.Taxes,
                                  peer=self._broker)
Пример #2
0
 def _import_asset_payments(self, payments):
     for payment in payments:
         if payment['account'] > 0:
             raise Statement_ImportError(
                 self.tr("Unmatched account for payment: ") + f"{payment}")
         if payment['asset'] > 0:
             raise Statement_ImportError(
                 self.tr("Unmatched asset for payment: ") + f"{payment}")
         tax = payment['tax'] if 'tax' in payment else 0
         if payment['type'] == FOF.PAYMENT_DIVIDEND:
             if payment['id'] > 0:  # New dividend
                 JalDB().add_dividend(DividendSubtype.Dividend,
                                      payment['timestamp'],
                                      -payment['account'],
                                      -payment['asset'],
                                      payment['amount'],
                                      payment['description'],
                                      tax=tax)
             else:  # Dividend exists, only tax to be updated
                 JalDB().update_dividend_tax(-payment['id'], payment['tax'])
         elif payment['type'] == FOF.PAYMENT_INTEREST:
             if 'number' not in payment:
                 payment['number'] = ''
             JalDB().add_dividend(DividendSubtype.BondInterest,
                                  payment['timestamp'],
                                  -payment['account'],
                                  -payment['asset'],
                                  payment['amount'],
                                  payment['description'],
                                  payment['number'],
                                  tax=tax)
         else:
             raise Statement_ImportError(
                 self.tr("Unsupported payment type: ") + f"{payment}")
Пример #3
0
Файл: jal.py Проект: flmnvd/jal
def main():
    sys.excepthook = exception_logger
    os.environ[
        'QT_MAC_WANTS_LAYER'] = '1'  # Workaround for https://bugreports.qt.io/browse/QTBUG-87014

    error = JalDB().init_db(get_app_path())

    app = QApplication([])
    language = JalDB().get_language_code(JalSettings().getValue('Language',
                                                                default=1))
    translator = QTranslator(app)
    language_file = get_app_path(
    ) + Setup.LANG_PATH + os.sep + language + '.qm'
    translator.load(language_file)
    app.installTranslator(translator)

    if error.code == JalDBError.OutdatedDbSchema:
        error = JalDB().update_db_schema(get_app_path())

    if error.code != JalDBError.NoError:
        window = QMessageBox()
        window.setAttribute(Qt.WA_DeleteOnClose)
        window.setWindowTitle("JAL: Start-up aborted")
        window.setIcon(QMessageBox.Critical)
        window.setText(error.message)
        window.setInformativeText(error.details)
    else:
        window = MainWindow(language)
    window.show()

    app.exec()
    app.removeTranslator(translator)
Пример #4
0
 def _import_imcomes_and_spendings(self, actions):
     for action in actions:
         if action['account'] > 0:
             raise Statement_ImportError(
                 self.tr("Unmatched account for income/spending: ") +
                 f"{action}")
         if action['peer'] > 0:
             raise Statement_ImportError(
                 self.tr("Unmatched peer for income/spending: ") +
                 f"{action}")
         peer = JalDB().get_account_bank(
             -action['account']) if action['peer'] == 0 else -action['peer']
         if len(action['lines']
                ) != 1:  # FIXME - need support for multilines here
             raise Statement_ImportError(
                 self.tr("Unsupported income/spending: ") + f"{action}")
         amount = action['lines'][0]['amount']
         category = -action['lines'][0]['category']
         if category <= 0:
             raise Statement_ImportError(
                 self.tr("Unmatched category for income/spending: ") +
                 f"{action}")
         description = action['lines'][0]['description']
         JalDB().add_cash_transaction(-action['account'], peer,
                                      action['timestamp'], amount, category,
                                      description)
Пример #5
0
    def load(self):
        try:
            data = pandas.read_html(self._filename, encoding='cp1251',
                                    converters={self.Qty: convert_amount, self.Amount: convert_amount,
                                                self.Price: convert_amount, self.Coupon: convert_amount})
        except:
            logging.error(self.tr("Can't read statement file"))
            return False

        report_info = data[0]
        deals_info = data[1]
        parts = re.match(self.ClientPattern, report_info[0][2])
        if parts:
            account_id = JalDB().get_account_id(parts.group(1))
        else:
            logging.error(self.tr("Can't get account number from the statement."))
            return False
        if account_id is None:
            logging.error(self.tr("Account with number ") + f"{parts.group(1)}" +
                          self.tr(" not found. Import cancelled."))
            return False

        for index, row in deals_info.iterrows():
            if row[self.Type] == self.Buy:
                qty = int(row[self.Qty])
            elif row[self.Type] == self.Sell:
                qty = -int(row[self.Qty])
            elif row[self.Type][:len(self.Total)] == self.Total:
                break  # End of statement reached
            else:
                logging.warning(self.tr("Unknown operation type ") + f"'{row[self.Type]}'")
                continue
            asset_id = JalDB().get_asset_id(row[self.Symbol])
            if asset_id is None:
                logging.warning(self.tr("Unknown asset ") + f"'{row[self.Symbol]}'")
                continue
            timestamp = int(
                datetime.strptime(row[self.DateTime], "%d.%m.%Y %H:%M:%S").replace(tzinfo=timezone.utc).timestamp())
            settlement = int(
                datetime.strptime(row[self.SettleDate], "%d.%m.%Y").replace(tzinfo=timezone.utc).timestamp())
            number = row[self.TradeNumber]
            price = row[self.Price]
            amount = row[self.Amount]
            lot_size = math.pow(10, round(math.log10(amount / (price * abs(qty)))))
            qty = qty * lot_size
            fee = float(row[self.Fee])
            if self.FeeEx in row:  # Broker dependent fee import
                fee = fee + float(row[self.FeeEx])
            else:
                fee = fee + float(row[self.FeeEx1]) + float(row[self.FeeEx2]) + float(row[self.FeeEx3])
            bond_interest = float(row[self.Coupon])
            JalDB().add_trade(account_id, asset_id, timestamp, settlement, number, qty, price, fee)
            if bond_interest != 0:
                JalDB().add_dividend(Dividend.BondInterest, timestamp, account_id, asset_id,
                                     bond_interest, "НКД", number)
        return True
Пример #6
0
 def _import_trades(self, trades):
     for trade in trades:
         if trade['account'] > 0:
             raise Statement_ImportError(self.tr("Unmatched account for trade: ") + f"{trade}")
         if trade['asset'] > 0:
             raise Statement_ImportError(self.tr("Unmatched asset for trade: ") + f"{trade}")
         note = trade['note'] if 'note' in trade else ''
         if 'cancelled' in trade and trade['cancelled']:
             JalDB().del_trade(-trade['account'], -trade['asset'], trade['timestamp'], trade['settlement'],
                               trade['number'], trade['quantity'], trade['price'], trade['fee'])
             continue
         JalDB().add_trade(-trade['account'], -trade['asset'], trade['timestamp'], trade['settlement'],
                           trade['number'], trade['quantity'], trade['price'], trade['fee'], note)
Пример #7
0
 def __init__(self, operation_id=None):
     super().__init__(operation_id)
     self._table = "trades"
     self._otype = LedgerTransaction.Trade
     self._view_rows = 2
     self._data = readSQL(
         "SELECT t.timestamp, t.number, t.account_id, t.asset_id, t.qty, t.price AS price, "
         "t.fee, t.note FROM trades AS t WHERE t.id=:oid",
         [(":oid", self._oid)],
         named=True)
     self._label, self._label_color = (
         'S', CustomColor.DarkRed) if self._data['qty'] < 0 else (
             'B', CustomColor.DarkGreen)
     self._timestamp = self._data['timestamp']
     self._account = JalDB().get_account_name(self._data['account_id'])
     self._account = self._data['account_id']
     self._account_name = JalDB().get_account_name(self._account)
     self._account_currency = JalDB().get_asset_name(
         JalDB().get_account_currency(self._account))
     self._reconciled = JalDB().account_reconciliation_timestamp(
         self._account) >= self._timestamp
     self._asset = self._data['asset_id']
     self._asset_symbol = JalDB().get_asset_name(self._asset)
     self._asset_name = JalDB().get_asset_name(self._asset, full=True)
     self._number = self._data['number']
     self._qty = self._data['qty']
     self._price = self._data['price']
     self._fee = self._data['fee']
     self._note = self._data['note']
     self._broker = JalDB().get_account_bank(self._account)
Пример #8
0
 def onStatementImport(self, timestamp, totals):
     self.ledger.rebuild()
     for account_id in totals:
         for asset_id in totals[account_id]:
             amount = JalDB().get_asset_amount(timestamp, account_id, asset_id)
             if amount is not None:
                 if abs(totals[account_id][asset_id] - amount) <= Setup.DISP_TOLERANCE:
                     JalDB().reconcile_account(account_id, timestamp)
                     self.updateWidgets()
                 else:
                     account = JalDB().get_account_name(account_id)
                     asset = JalDB().get_asset_name(asset_id)
                     logging.warning(self.tr("Statement ending balance doesn't match: ") +
                                     f"{account} / {asset} / {amount} <> {totals[account_id][asset_id]}")
Пример #9
0
    def _import_transfers(self, transfers):
        for transfer in transfers:
            for account in transfer['account']:
                if account > 0:
                    raise Statement_ImportError(
                        self.tr("Unmatched account for transfer: ") +
                        f"{transfer}")
            for asset in transfer['asset']:
                if asset > 0:
                    raise Statement_ImportError(
                        self.tr("Unmatched asset for transfer: ") +
                        f"{transfer}")
            if transfer['account'][0] == 0 or transfer['account'][1] == 0:
                text = ''
                pair_account = 1
                if transfer['account'][0] == 0:  # Deposit
                    text = self.tr("Deposit of ") + f"{transfer['deposit']:.2f} " + \
                           f"{JalDB().get_asset_name(-transfer['asset'][1])} " + \
                           f"@{datetime.utcfromtimestamp(transfer['timestamp']).strftime('%d.%m.%Y')}\n" + \
                           self.tr("Select account to withdraw from:")
                    pair_account = -transfer['account'][1]
                if transfer['account'][1] == 0:  # Withdrawal
                    text = self.tr("Withdrawal of ") + f"{transfer['withdrawal']:.2f} " + \
                           f"{JalDB().get_asset_name(-transfer['asset'][0])} " + \
                           f"@{datetime.utcfromtimestamp(transfer['timestamp']).strftime('%d.%m.%Y')}\n" + \
                           self.tr("Select account to deposit to:")
                    pair_account = -transfer['account'][0]
                try:
                    chosen_account = self._previous_accounts[
                        JalDB().get_account_currency(pair_account)]
                except KeyError:
                    chosen_account = self.select_account(
                        text, pair_account, self._last_selected_account)
                if chosen_account == 0:
                    raise Statement_ImportError(
                        self.tr("Account not selected"))
                self._last_selected_account = chosen_account
                if transfer['account'][0] == 0:
                    transfer['account'][0] = -chosen_account
                if transfer['account'][1] == 0:
                    transfer['account'][1] = -chosen_account

            description = transfer[
                'description'] if 'description' in transfer else ''
            JalDB().add_transfer(transfer['timestamp'],
                                 -transfer['account'][0],
                                 transfer['withdrawal'],
                                 -transfer['account'][1], transfer['deposit'],
                                 -transfer['account'][2], transfer['fee'],
                                 description)
Пример #10
0
 def refreshAssetPrice(self):
     if self.type.currentIndex() == Dividend.StockDividend:
         price = JalDB().get_quote(self.asset_widget.selected_id,
                                   JalDB().get_account_currency(self.account_widget.selected_id),
                                   self.timestamp_editor.dateTime().toSecsSinceEpoch())
         if price is not None:
             self.price_edit.setText(str(price))
             self.price_edit.setStyleSheet('')
             self.price_edit.setToolTip("")
         else:
             self.price_edit.setText(self.tr("No quote"))
             self.price_edit.setStyleSheet("color: red")
             self.price_edit.setToolTip(
                 self.tr("You should set quote via Data->Quotes menu for Date/Time of the dividend"))
Пример #11
0
    def prepare_chart_data(self):
        min_price = max_price = 0
        min_ts = max_ts = 0

        self.currency_name = JalDB().get_asset_name(JalDB().get_account_currency(self.account_id))
        start_time = readSQL("SELECT MAX(ts) FROM "  # Take either last "empty" timestamp
                             "(SELECT coalesce(MAX(timestamp), 0) AS ts "
                             "FROM ledger_sums WHERE account_id=:account_id AND asset_id=:asset_id "
                             "AND book_account=:assets_book AND sum_amount==0 "
                             "UNION "  # or first timestamp where position started to appear
                             "SELECT coalesce(MIN(timestamp), 0) AS ts "
                             "FROM ledger_sums WHERE account_id=:account_id AND asset_id=:asset_id "
                             "AND book_account=:assets_book AND sum_amount!=0)",
                             [(":account_id", self.account_id), (":asset_id", self.asset_id),
                              (":assets_book", BookAccount.Assets)])
        # Get quotes quotes
        query = executeSQL("SELECT timestamp, quote FROM quotes WHERE asset_id=:asset_id AND timestamp>:last",
                           [(":asset_id", self.asset_id), (":last", start_time)])
        while query.next():
            quote = readSQLrecord(query, named=True)
            self.quotes.append({'timestamp': quote['timestamp'] * 1000, 'quote': quote['quote']})  # timestamp to ms
            min_price = quote['quote'] if min_price == 0 or quote['quote'] < min_price else min_price
            max_price = quote['quote'] if quote['quote'] > max_price else max_price
            min_ts = quote['timestamp'] if min_ts == 0 or quote['timestamp'] < min_ts else min_ts
            max_ts = quote['timestamp'] if quote['timestamp'] > max_ts else max_ts

        # Get deals quotes
        query = executeSQL("SELECT timestamp, price, qty FROM trades "
                           "WHERE account_id=:account_id AND asset_id=:asset_id AND timestamp>=:last",
                           [(":account_id", self.account_id), (":asset_id", self.asset_id), (":last", start_time)])
        while query.next():
            trade = readSQLrecord(query, named=True)
            self.trades.append({'timestamp': trade['timestamp'] * 1000, 'price': trade['price'], 'qty': trade['qty']})
            min_price = trade['price'] if min_price == 0 or trade['price'] < min_price else min_price
            max_price = trade['price'] if trade['price'] > max_price else max_price
            min_ts = trade['timestamp'] if min_ts == 0 or trade['timestamp'] < min_ts else min_ts
            max_ts = trade['timestamp'] if trade['timestamp'] > max_ts else max_ts

        # Round min/max values to near "round" values in order to have 10 nice intervals
        step = 10 ** floor(log10(max_price - min_price))
        min_price = floor(min_price / step) * step
        max_price = ceil(max_price / step) * step

        # Add a gap at the beginning and end
        min_ts -= 86400 * 3
        max_ts += 86400 * 3

        self.range = [min_ts, max_ts, min_price, max_price]
Пример #12
0
    def __init__(self,
                 account_id,
                 asset_id,
                 currency_id,
                 _asset_qty,
                 parent=None):
        super().__init__(parent)

        self.account_id = account_id
        self.asset_id = asset_id
        self.currency_id = currency_id if asset_id != currency_id else 1  # Check whether we have currency or asset
        self.asset_name = JalDB().get_asset_name(self.asset_id)
        self.quotes = []
        self.trades = []
        self.currency_name = ''
        self.range = [0, 0, 0, 0]

        self.prepare_chart_data()

        self.chart = ChartWidget(self, self.quotes, self.trades, self.range,
                                 self.currency_name)

        self.layout = QHBoxLayout(self)
        self.layout.setContentsMargins(0, 0, 0,
                                       0)  # Remove extra space around layout
        self.layout.addWidget(self.chart)
        self.setLayout(self.layout)

        self.setWindowTitle(self.tr("Price chart for ") + self.asset_name)

        self.ready = True
Пример #13
0
 def setEditorData(self, editor, index):
     account_currency = JalDB().get_account_currency(index.model().data(
         index.sibling(index.row(),
                       index.model().fieldIndex('account_id')),
         Qt.EditRole))
     editor.setFilterValue(account_currency)
     QStyledItemDelegate.setEditorData(self, editor, index)
Пример #14
0
def test_backup_load(tmp_path, project_root):
    # Prepare environment
    src_path = project_root + os.sep + 'jal' + os.sep + Setup.INIT_SCRIPT_PATH
    target_path = str(tmp_path) + os.sep + Setup.INIT_SCRIPT_PATH
    copyfile(src_path, target_path)
    JalDB().init_db(str(tmp_path) + os.sep)

    # Here backup is created without parent window - need to use with care
    db_file_name = get_dbfilename(str(tmp_path) + os.sep)
    backup = JalBackup(None, db_file_name)
    backup.backup_name = project_root + os.sep + "tests" + os.sep + "test_data" + os.sep + "deals_set.tgz"

    assert backup.validate_backup()
    # Check validation
    assert backup._backup_label_date == '2021/01/01 00:00:00+0300'

    backup.do_restore()

    # Check restoration
    db = sqlite3.connect(db_file_name)
    cursor = db.cursor()
    cursor.execute("SELECT COUNT(*) FROM settings")
    assert cursor.fetchone()[0] == 7
    db.close()

    os.remove(target_path)  # Clean db init script
    os.remove(get_dbfilename(str(tmp_path) + os.sep))  # Clean db file
Пример #15
0
 def _match_account_ids(self):
     for account in self._data[FOF.ACCOUNTS]:
         account_id = JalDB().find_account(account['number'],
                                           -account['currency'])
         if account_id:
             old_id, account['id'] = account['id'], -account_id
             self._update_id("account", old_id, account_id)
Пример #16
0
 def _import_assets(self, assets):
     for asset in assets:
         isin = asset['isin'] if 'isin' in asset else ''
         name = asset['name'] if 'name' in asset else ''
         country_code = asset['country'] if 'country' in asset else ''
         if asset['id'] < 0:
             JalDB().update_asset_data(-asset['id'], {'isin': isin, 'name': name, 'country': country_code})
             continue
         asset_id = JalDB().add_asset(self._asset_types[asset['type']], name, isin, country_code=country_code)
         if asset_id:
             old_id, asset['id'] = asset['id'], -asset_id
             self._update_id("asset", old_id, asset_id)
             if asset['type'] == FOF.ASSET_MONEY:
                 self._update_id("currency", old_id, asset_id)
         else:
             raise Statement_ImportError(self.tr("Can't create asset: ") + f"{asset}")
Пример #17
0
 def setId(self, account_id):
     self.p_account_id = account_id
     if self.p_account_id:
         self.setText(JalDB().get_account_name(account_id))
     else:
         self.setText(self.tr("ANY"))
     self.changed.emit(self.p_account_id)
Пример #18
0
    def __init__(self, account_id, asset_id, asset_qty, parent=None):
        super(TaxEstimator, self).__init__(parent)
        self.setupUi(self)

        self.account_id = account_id
        self.asset_id = asset_id
        self.asset_name = JalDB().get_asset_name(self.asset_id)
        self.asset_qty = asset_qty
        self.dataframe = None
        self.ready = False

        self.setWindowTitle(self.tr("Tax estimation for ") + self.asset_name)

        font = self.DealsView.horizontalHeader().font()
        font.setBold(True)
        self.DealsView.horizontalHeader().setFont(font)

        self.quote = 0
        self.rate = 1
        self.currency_name = ''
        self.prepare_tax()
        if self.dataframe is None:
            return

        self.QuoteLbl.setText(f"{self.quote:.4f}")
        self.RateLbl.setText(f"{self.rate:.4f} {self.currency_name}/RUB")

        self.model = TaxEstimatorModel(self.dataframe, self.currency_name)
        self.DealsView.setModel(self.model)
        self.ready = True
Пример #19
0
 def setId(self, new_value):
     if self._id == new_value:
         return
     self._id = new_value
     self.updateView()
     name = JalDB().get_asset_name(self._id)
     self.name_updated.emit('' if name is None else name)
Пример #20
0
    def __init__(self, account_id, asset_id, _asset_qty, position, parent=None):
        super().__init__(parent)

        self.account_id = account_id
        self.asset_id = asset_id
        self.asset_name = JalDB().get_asset_name(self.asset_id)
        self.quotes = []
        self.trades = []
        self.currency_name = ''
        self.range = [0, 0, 0, 0]

        self.prepare_chart_data()

        self.chart = ChartWidget(self, self.quotes, self.trades, self.range, self.currency_name)

        self.layout = QHBoxLayout(self)
        self.layout.setContentsMargins(0, 0, 0, 0)  # Remove extra space around layout
        self.layout.addWidget(self.chart)
        self.setLayout(self.layout)

        self.setWindowTitle(self.tr("Price chart for ") + self.asset_name)
        self.setWindowFlag(Qt.Tool)
        self.setGeometry(position.x(), position.y(), self.width(), self.height())

        self.ready = True
Пример #21
0
 def _import_corporate_actions(self, actions):
     for action in actions:
         if action['account'] > 0:
             raise Statement_ImportError(
                 self.tr("Unmatched account for corporate action: ") +
                 f"{action}")
         if type(action['asset']) == list:
             asset_old = -action['asset'][0]
             asset_new = -action['asset'][1]
         else:
             asset_old = asset_new = -action['asset']
         if asset_old < 0 or asset_new < 0:
             raise Statement_ImportError(
                 self.tr("Unmatched asset for corporate action: ") +
                 f"{action}")
         if type(action['quantity']) == list:
             qty_old = action['quantity'][0]
             qty_new = action['quantity'][1]
         else:
             qty_old = -1
             qty_new = action['quantity']
         try:
             action_type = self._corp_actions[action['type']]
         except KeyError:
             raise Statement_ImportError(
                 self.tr("Unsupported corporate action: ") + f"{action}")
         JalDB().add_corporate_action(-action['account'], action_type,
                                      action['timestamp'], action['number'],
                                      asset_old, qty_old, asset_new,
                                      qty_new, action['cost_basis'],
                                      action['description'])
Пример #22
0
 def _import_assets(self, assets):
     for asset in assets:
         if asset['id'] < 0:
             continue
         isin = asset['isin'] if 'isin' in asset else ''
         reg_code = asset['reg_code'] if 'reg_code' in asset else ''
         name = asset['name'] if 'name' in asset else ''
         country_code = asset['country'] if 'country' in asset else ''
         expiry = asset['expiry'] if 'expiry' in asset else 0
         try:
             source = self._sources[asset['exchange']]
         except KeyError:
             source = MarketDataFeed.NA
         asset_id = JalDB().add_asset(asset['symbol'],
                                      name,
                                      self._asset_types[asset['type']],
                                      isin,
                                      expiry=expiry,
                                      data_source=source,
                                      reg_code=reg_code,
                                      country_code=country_code)
         if asset_id:
             old_id, asset['id'] = asset['id'], -asset_id
             self._update_id("asset", old_id, asset_id)
             if asset['type'] == FOF.ASSET_MONEY:
                 self._update_id("currency", old_id, asset_id)
         else:
             raise Statement_ImportError(
                 self.tr("Can't create asset: ") + f"{asset}")
Пример #23
0
 def __init__(self, operation_id=None):
     labels = {
         CorporateAction.Merger: ('â­ƒ', CustomColor.Black),
         CorporateAction.SpinOff: ('⎇', CustomColor.DarkGreen),
         CorporateAction.Split: ('á—•', CustomColor.Black),
         CorporateAction.SymbolChange: ('🡘', CustomColor.Black),
         CorporateAction.Delisting: ('✖', CustomColor.DarkRed)
     }
     self.CorpActionNames = {
         CorporateAction.SymbolChange:
         self.tr("Symbol change {old} -> {new}"),
         CorporateAction.Split:
         self.tr("Split {old} {before} into {after}"),
         CorporateAction.SpinOff:
         self.tr("Spin-off {after} {new} from {before} {old}"),
         CorporateAction.Merger:
         self.tr("Merger {before} {old} into {after} {new}"),
         CorporateAction.Delisting:
         self.tr("Delisting of {before} {old}")
     }
     super().__init__(operation_id)
     self._table = "corp_actions"
     self._otype = LedgerTransaction.CorporateAction
     self._view_rows = 2
     self._data = readSQL(
         "SELECT a.type, a.timestamp, a.number, a.account_id, "
         "a.qty, a.asset_id, a.qty_new, a.asset_id_new, a.basis_ratio, a.note "
         "FROM corp_actions AS a WHERE a.id=:oid", [(":oid", self._oid)],
         named=True)
     self._subtype = self._data['type']
     self._label, self._label_color = labels[self._subtype]
     self._timestamp = self._data['timestamp']
     self._account = self._data['account_id']
     self._account_name = JalDB().get_account_name(self._account)
     self._account_currency = JalDB().get_asset_name(
         JalDB().get_account_currency(self._account))
     self._reconciled = JalDB().account_reconciliation_timestamp(
         self._account) >= self._timestamp
     self._asset = self._data['asset_id']
     self._asset_symbol = JalDB().get_asset_name(self._asset)
     self._asset_name = JalDB().get_asset_name(self._asset, full=True)
     self._qty = self._data['qty']
     self._asset_new = self._data['asset_id_new']
     self._asset_new_symbol = JalDB().get_asset_name(self._asset_new)
     self._asset_name_new = JalDB().get_asset_name(self._asset_new,
                                                   full=True)
     self._qty_after = self._data['qty_new']
     self._number = self._data['number']
     self._basis = self._data['basis_ratio']
     self._broker = JalDB().get_account_bank(self._account)
Пример #24
0
 def _match_asset_isin(self):
     for asset in self._data[FOF.ASSETS]:
         if asset['id'] < 0:  # already matched
             continue
         if 'isin' in asset:
             asset_id = JalDB().get_asset_id({'isin': asset['isin']})
             if asset_id is not None:
                 old_id, asset['id'] = asset['id'], -asset_id
                 self._update_id("asset", old_id, asset_id)
Пример #25
0
 def select_account(self, text, account_id, recent_account_id=0):
     if "pytest" in sys.modules:
         return 1    # Always return 1st account if we are in testing mode
     dialog = SelectAccountDialog(text, account_id, recent_account=recent_account_id)
     if dialog.exec() != QDialog.Accepted:
         return 0
     else:
         if dialog.store_account:
             self._previous_accounts[JalDB().get_account_currency(dialog.account_id)] = dialog.account_id
         return dialog.account_id
Пример #26
0
 def _match_asset_reg_number(self):
     for asset in self._data[FOF.ASSETS_DATA]:
         if asset['asset'] < 0:  # already matched
             continue
         if 'reg_number' in asset:
             asset_id = JalDB().get_asset_id({'reg_number': asset['reg_number']})
             if asset_id is not None:
                 asset = self._find_in_list(self._data[FOF.ASSETS], "id", asset['asset'])
                 old_id, asset['id'] = asset['id'], -asset_id
                 self._update_id("asset", old_id, asset_id)
Пример #27
0
 def _match_asset_ids(self, verbal):
     for asset in self._data[FOF.ASSETS]:
         isin = asset['isin'] if 'isin' in asset else ''
         reg_code = asset['reg_code'] if 'reg_code' in asset else ''
         name = asset['name'] if 'name' in asset else ''
         country_code = asset['country'] if 'country' in asset else ''
         expiry = asset['expiry'] if 'expiry' in asset else 0
         asset_id = JalDB().get_asset_id(asset['symbol'],
                                         isin=isin,
                                         reg_code=reg_code,
                                         name=name,
                                         expiry=expiry,
                                         dialog_new=verbal)
         if asset_id is not None:
             JalDB().update_asset_data(asset_id, asset['symbol'], isin,
                                       reg_code, country_code)
             old_id, asset['id'] = asset['id'], -asset_id
             self._update_id("asset", old_id, asset_id)
             if asset['type'] == FOF.ASSET_MONEY:
                 self._update_id("currency", old_id, asset_id)
Пример #28
0
 def _add_asset(self, isin, reg_code, symbol=''):
     if self._find_asset_id(symbol, isin, reg_code) != 0:
         raise Statement_ImportError(
             self.tr("Attempt to recreate existing asset: ") + f"{isin}/{reg_code}")
     asset_id = JalDB().get_asset_id('', isin=isin, reg_code=reg_code, dialog_new=False)
     if asset_id is None:
         asset = QuoteDownloader.MOEX_info(symbol=symbol, isin=isin, regnumber=reg_code)
         if asset:
             asset['id'] = asset_id = max([0] + [x['id'] for x in self._data[FOF.ASSETS]]) + 1
             asset['exchange'] = "MOEX"
             asset['type'] = FOF.convert_predefined_asset_type(asset['type'])
         else:
             raise Statement_ImportError(self.tr("Can't import asset: ") + f"{isin}/{reg_code}")
     else:
         asset = {"id": -asset_id, "symbol": JalDB().get_asset_name(asset_id),
                  "type": FOF.convert_predefined_asset_type(JalDB().get_asset_type(asset_id)),
                  'name': '', "isin": isin, "reg_code": reg_code}
         asset_id = -asset_id
     self._data[FOF.ASSETS].append(asset)
     return asset_id
Пример #29
0
 def _match_currencies(self):
     for asset in self._data[FOF.ASSETS]:
         if asset['type'] != FOF.ASSET_MONEY:
             continue
         symbol = self._find_in_list(self._data[FOF.SYMBOLS], "asset", asset['id'])
         asset_id = JalDB().get_asset_id({'symbol': symbol['symbol'], 'type': self._asset_types[asset['type']]})
         if asset_id is not None:
             symbol['asset'] = -asset_id
             old_id, asset['id'] = asset['id'], -asset_id
             self._update_id("currency", old_id, asset_id)
             self._update_id("asset", old_id, asset_id)     # TRANSFERS section may have currency in asset list
Пример #30
0
def prepare_db(project_root, tmp_path, data_path):
    # Prepare environment
    src_path = project_root + os.sep + 'jal' + os.sep + Setup.INIT_SCRIPT_PATH
    target_path = str(tmp_path) + os.sep + Setup.INIT_SCRIPT_PATH
    copyfile(src_path, target_path)

    # Activate db connection
    error = JalDB().init_db(str(tmp_path) + os.sep)
    assert error.code == JalDBError.NoError
    error = JalDB().init_db(str(tmp_path) + os.sep)
    assert error.code == JalDBError.NoError
    db = QSqlDatabase.database(Setup.DB_CONNECTION)
    assert db.isValid()
    lang_id = JalDB().get_language_id('en')
    assert lang_id == 1

    yield

    os.remove(target_path)  # Clean db init script
    os.remove(get_dbfilename(str(tmp_path) + os.sep))  # Clean db file