def extractRow(self, row, meta):
        trans_date = self.getDate(row)
        trans_desc = self.getDesc(row)
        trans_amt  = self.getAmt(row)
        account = self.getAccount(row)

        txn = data.Transaction(
            meta=meta,
            date=trans_date,
            flag=flags.FLAG_OKAY,
            payee=trans_desc,
            narration=self.getMemo(row),
            tags=set(),
            links=set(),
            postings=[
                data.Posting(
                    self.account,
                    amount.Amount(-1*D(trans_amt), 'USD'),
                    None, None, None, None
                ),
            ],
        )
        if account is not None:
            txn.postings.append(data.Posting(
                account,
                amount.Amount(D(trans_amt), 'USD'),
                None, None, None, None
            ))
        return txn
Exemplo n.º 2
0
    def extract(self, file):
        entries = []
        with open(file.name) as f:
            for index, row in enumerate(csv.DictReader(islice(f, 6, None))):
                if index == 0:
                    if 'Beginning balance' in row['Description']:
                        continue
                    else:
                        logging.error(
                            "Missing 'Beginning balance' in '{}'".format(
                                row['Description']))

                meta = data.new_metadata(file.name, index)
                trans_date = parse(row['Date']).date()
                trans_desc = titlecase(row['Description'])
                trans_amt = row['Amount']
                units = amount.Amount(D(row['Amount']), self.currency)

                txn = data.Transaction(
                    meta, trans_date, self.FLAG, trans_desc, None,
                    data.EMPTY_SET, data.EMPTY_SET, [
                        data.Posting(self.account_root, units, None, None,
                                     None, None),
                        data.Posting(self.account2, -units, None, None, None,
                                     None),
                    ])

                entries.append(txn)

        return entries
Exemplo n.º 3
0
    def test_get_pholding_market_value(self):
        posting = data.Posting('Account',
                               position.from_string('100 MSFT {54.34 USD}'),
                               A('60.00 USD'),
                               None, None)
        self.assertEqual(A('6000.00 USD'),
                         holdings.get_pholding_market_value(posting))

        posting = data.Posting('Account',
                               position.from_string('100 MSFT {54.34 USD}'),
                               None,
                               None, None)
        self.assertEqual(A('5434.00 USD'),
                         holdings.get_pholding_market_value(posting))

        posting = data.Posting('Account',
                               position.from_string('1000.00 USD'),
                               None,
                               None, None)
        self.assertEqual(A('1000.00 USD'),
                         holdings.get_pholding_market_value(posting))

        with self.assertRaises(AssertionError):
            posting = data.Posting('Account',
                                   position.from_string('1000.00 USD'),
                                   A('60.00 USD'),
                                   None, None)
            holdings.get_pholding_market_value(posting)

        with self.assertRaises(AssertionError):
            posting = data.Posting('Account',
                                   position.from_string('1000.00 USD {1.25 CAD}'),
                                   A('60.00 USD'),
                                   None, None)
            holdings.get_pholding_market_value(posting)
    def addPaymentFor(self, txn, trans_date, trans_amt):
        months_to_add = self.paymentMonthOffset + (
            1 if trans_date.day > self.statementCloseDay else 0)
        payment_date = set_days(add_months(trans_date, months_to_add),
                                self.paymentDay)

        paymentTxn = self.payments[payment_date.isoformat(
        )] if payment_date.isoformat() in self.payments else data.Transaction(
            meta=txn.meta,
            date=payment_date,
            flag=flags.FLAG_OKAY,
            payee=self.account + " Payment",
            narration="",
            tags=set(),
            links=set(),
            postings=[
                data.Posting(self.account, None, None, None, None, None)
            ])
        paymentTxn.postings.extend([
            data.Posting(self.autoPayAccount,
                         amount.Amount(-1 * D(trans_amt), 'USD'), None, None,
                         None, None),
        ])

        self.payments[payment_date.isoformat()] = paymentTxn
Exemplo n.º 5
0
    def Deposits(self, dep):
        # creates deposit transactions from IBKR Data

        depTransactions=[]
        # assumes you figured out how to deposit/ withdrawal without fees
        if len(self.depositAccount) == 0: # control this from the config file
            return []
        for idx, row in dep.iterrows():
            currency=row['currency']
            amount_=amount.Amount(row['amount'],currency)
            
            # make the postings. two for deposits
            postings=[data.Posting(self.depositAccount,
                                    -amount_, None, None, None, None),
                        data.Posting(self.getLiquidityAccount(currency),
                                    amount_,None, None, None, None)
                        ]
            meta=data.new_metadata('deposit/withdrawel',0)
            depTransactions.append(
                data.Transaction(meta, # could add div per share, ISIN,....
                            row['reportDate'],
                            self.flag,
                            'self',     # payee
                            "deposit / withdrawal",
                            data.EMPTY_SET,
                            data.EMPTY_SET,
                            postings
                            ))
        return depTransactions
Exemplo n.º 6
0
 def Balances(self,cr):
     # generate Balance statements from IBKR Cash reports 
     # balances 
     crTransactions = []
     for idx, row in cr.iterrows():
         currency=row['currency']
         if currency == 'BASE_SUMMARY':
             continue # this is a summary balance that is not needed for beancount
         amount_=amount.Amount(row['endingCash'].__round__(2),currency)
         
         # make the postings. two for deposits
         postings=[data.Posting(self.depositAccount,
                                 -amount_, None, None, None, None),
                     data.Posting(self.getLiquidityAccount(currency),
                                 amount_,None, None, None, None)
                     ]
         meta=data.new_metadata('balance',0)
         
         crTransactions.append(data.Balance(
                         meta,
                         row['toDate'] + timedelta(days=1), # see tariochtools EC imp.
                         self.getLiquidityAccount(currency),
                         amount_,
                         None,
                         None))
     return crTransactions
Exemplo n.º 7
0
 def Fee(self,fee):
     # calculates fees from IBKR data
     feeTransactions=[]
     for idx, row in fee.iterrows():
         currency=row['currency']
         amount_=amount.Amount(row['amount'],currency)
         text=row['description']
         month=re.findall('\w{3} \d{4}',text)[0]
         
         # make the postings, two for fees
         postings=[data.Posting(self.getFeesAccount(currency),
                                -amount_, None, None, None, None),
                   data.Posting(self.getLiquidityAccount(currency),
                                amount_,None, None, None, None)]
         meta=data.new_metadata(__file__,0, {}) # actually no metadata
         feeTransactions.append(
             data.Transaction(meta,
                              row['reportDate'],
                              self.flag,
                              'IB',     # payee
                              ' '.join(['Fee', currency , month]),
                              data.EMPTY_SET,
                              data.EMPTY_SET,
                              postings))
     return feeTransactions
Exemplo n.º 8
0
 def Interest(self,int_):
     # calculates interest payments from IBKR data
     intTransactions=[]
     for idx, row in int_.iterrows():
         currency=row['currency']
         amount_=amount.Amount(row['amount'],currency)
         text=row['description']
         month=re.findall('\w{3}-\d{4}',text)[0]
         
         # make the postings, two for interest payments
         # received and paid interests are booked on the same account
         postings=[data.Posting(self.getInterestIncomeAcconut(currency),
                                 -amount_, None, None, None, None),
                     data.Posting(self.getLiquidityAccount(currency),
                                 amount_,None, None, None, None)
                     ]
         meta=data.new_metadata('Interest',0)
         intTransactions.append(
             data.Transaction(meta, # could add div per share, ISIN,....
                         row['reportDate'],
                         self.flag,
                         'IB',     # payee
                         ' '.join(['Interest ', currency , month]),
                         data.EMPTY_SET,
                         data.EMPTY_SET,
                         postings
                         ))
     return intTransactions
Exemplo n.º 9
0
    def createSingle(self, payout, withholding, quantity, assetAccount, asset, currency, date, priceLookup, description):
        narration = "Dividend for " + str(quantity) + " : " + description
        liquidityAccount = self.getLiquidityAccount(assetAccount, asset, currency)
        incomeAccount = self.getIncomeAccount(assetAccount, asset)

        price = priceLookup.fetchPrice(currency, date)

        postings = [
            data.Posting(assetAccount, amount.Amount(D(0), asset), None, None, None, None),
            data.Posting(liquidityAccount, amount.Amount(payout, currency), None, price, None, None),
        ]
        if withholding > 0:
            receivableAccount = self.getReceivableAccount(assetAccount, asset)
            postings.append(
                data.Posting(receivableAccount, amount.Amount(withholding, currency), None, None, None, None)
            )
        postings.append(
            data.Posting(incomeAccount, None, None, None, None, None)
        )

        meta = data.new_metadata('dividend', 0)
        return data.Transaction(
            meta,
            date,
            '*',
            '',
            narration,
            data.EMPTY_SET,
            data.EMPTY_SET,
            postings
        )
def generate_transaction(
    meta,
    trans_date,
    trans_payee,
    trans_description,
    trans_account,
    trans_amount,
    trans_second_posting_account,
):
    txn = data.Transaction(
        meta=meta,
        date=trans_date,
        flag=flags.FLAG_OKAY,
        payee=trans_payee,
        narration=trans_description,
        tags=set(),
        links=set(),
        postings=[],
    )

    txn.postings.append(
        data.Posting(trans_account,
                     amount.Amount(round(D(trans_amount), 2), 'EUR'), None,
                     None, None, None))
    txn.postings.append(
        data.Posting(trans_second_posting_account, None, None, None, None,
                     None))

    return txn
Exemplo n.º 11
0
    def extract(self, file, existing_entries=None):
        entries = []
        meta = data.new_metadata(file.name, 0)
        txn = data.Transaction(
            meta,
            parse('2017-11-20').date(),
            '*',
            None,
            'Two Postings',
            data.EMPTY_SET,
            data.EMPTY_SET,
            [
                data.Posting('Assets:Patrick:CHF', amount.Amount(D('12'), 'CHF'), None, None, None, None),
                data.Posting('Assets:Patrick:USD', amount.Amount(D('12'), 'CHF'), None, None, None, None),
            ]
        )

        entries.append(txn)
        txn = data.Transaction(
            meta,
            parse('2017-11-20').date(),
            '*',
            None,
            'Single Posting',
            data.EMPTY_SET,
            data.EMPTY_SET,
            [
                data.Posting('Assets:Patrick:CHF', amount.Amount(D('12'), 'CHF'), None, None, None, None),
            ]
        )

        entries.append(txn)

        return entries
Exemplo n.º 12
0
    def __txn_common(self,
                     meta,
                     date,
                     acc_in,
                     acc_out,
                     units_common,
                     payee="",
                     desc=""):
        """Return a transaction object for simple transactions."""
        self.logger.debug("Entering Function")

        self.logger.debug("Receiving account: %s", acc_in)
        self.logger.debug("Sending account: %s", acc_out)

        txn = data.Transaction(
            meta, date, self.FLAG, payee, desc, data.EMPTY_SET, data.EMPTY_SET,
            [
                data.Posting(acc_in, units_common, None, None, None, None),
                data.Posting(acc_out, -units_common, None, None, None, None)
            ])

        self.logger.debug('Transaction to be recorded: %s', str(txn))
        self.logger.debug("Leaving Function")

        return txn
Exemplo n.º 13
0
    def extract(self, file):
        entries = []
        with open(file.name) as file:
            for index, row in enumerate(csv.DictReader(file)):
                trans_date = parse(row['date']).date()
                trans_desc = titlecase(row['name'].rstrip())
                trans_amt = row['amount']
                meta = data.new_metadata(file.name, index)
                txn = data.Transaction(meta=meta,
                                       date=trans_date,
                                       flag=flags.FLAG_OKAY,
                                       payee=trans_desc,
                                       narration="",
                                       tags=set(),
                                       links=set(),
                                       postings=[])

                if D(trans_amt) > 0:
                    txn.postings.append(
                        data.Posting('Assets:VSCU:Savings',
                                     amount.Amount(D(trans_amt), 'USD'), None,
                                     None, None, None))
                    txn.postings.append(
                        data.Posting('FIXME', None, None, None, None, None))
                else:
                    txn.postings.append(
                        data.Posting('FIXME',
                                     amount.Amount(D(trans_amt), 'USD'), None,
                                     None, None, None))
                    txn.postings.append(
                        data.Posting('Assets:VSCU:Savings', None, None, None,
                                     None, None))

                entries.append(txn)
        return entries
Exemplo n.º 14
0
def test_insert_entry_align(tmpdir):
    file_content = dedent("""
        2016-02-26 * "Uncle Boons" "Eating out alone"
            Liabilities:US:Chase:Slate                       -24.84 USD
            Expenses:Food:Restaurant                          24.84 USD

    """)
    samplefile = tmpdir.mkdir('fava_util_file3').join('example.beancount')
    samplefile.write(file_content)

    postings = [
        data.Posting('Liabilities:US:Chase:Slate',
                     amount.Amount(D('-10.00'), 'USD'), None, None, None,
                     None),
        data.Posting('Expenses:Food', amount.Amount(D('10.00'), 'USD'), None,
                     None, None, None),
    ]

    transaction = data.Transaction(None, datetime.date(2016, 1, 1), '*',
                                   'new payee', 'narr', None, None, postings)

    fava_options = {
        'currency-column': 50,
    }
    insert_entry(transaction, [str(samplefile)], fava_options)
    assert samplefile.read() == dedent("""
        2016-02-26 * "Uncle Boons" "Eating out alone"
            Liabilities:US:Chase:Slate                       -24.84 USD
            Expenses:Food:Restaurant                          24.84 USD

        2016-01-01 * "new payee" "narr"
          Liabilities:US:Chase:Slate              -10.00 USD
          Expenses:Food                            10.00 USD

    """)
Exemplo n.º 15
0
def test__render_transaction():
    postings = [
        data.Posting('Liabilities:US:Chase:Slate',
                     amount.Amount(D('-10.00'), 'USD'), None, None, None,
                     None),
        data.Posting('Expenses:Food', amount.Amount(None, None), None, None,
                     None, None),
    ]

    transaction = data.Transaction(None, datetime.date(2016, 1, 1), '*',
                                   'new payee', 'narr', None, None, postings)

    assert '\n' + _render_transaction(transaction) == dedent("""
    2016-01-01 * "new payee" "narr"
        Liabilities:US:Chase:Slate                    -10.00 USD
        Expenses:Food""")

    postings = [
        data.Posting('Liabilities:US:Chase:Slate',
                     amount.Amount(D('-10.00'), 'USD'), None, None, None,
                     None),
        data.Posting('Expenses:Food', amount.Amount(D('10.00'), 'USD'), None,
                     None, None, None),
    ]

    transaction = data.Transaction(None, datetime.date(2016, 1, 1), '*',
                                   'new payee', 'narr', None, None, postings)

    print(_render_transaction(transaction))
    assert '\n' + _render_transaction(transaction) == dedent("""
    2016-01-01 * "new payee" "narr"
        Liabilities:US:Chase:Slate                    -10.00 USD
        Expenses:Food                                  10.00 USD""")
Exemplo n.º 16
0
def get_holdings_entries(entries, options_map):
    """Summarizes the entries to list of entries representing the final holdings..

    This list includes the latest prices entries as well. This can be used to
    load a full snapshot of holdings without including the entire history. This
    is a way of summarizing a balance sheet in a way that filters away history.

    Args:
      entries: A list of directives.
      options_map: A dict of parsed options.
    Returns:
      A string, the entries to print out.
    """

    # The entries will be created at the latest date, against an equity account.
    latest_date = entries[-1].date
    _, equity_account, _ = options.get_previous_accounts(options_map)

    # Get all the assets.
    holdings_list, _ = holdings.get_assets_holdings(entries, options_map)

    # Create synthetic entries for them.
    holdings_entries = []

    for index, holding in enumerate(holdings_list):
        meta = data.new_metadata('report_holdings_print', index)
        entry = data.Transaction(meta, latest_date, flags.FLAG_SUMMARIZE, None,
                                 "", None, None, [])

        # Convert the holding to a position.
        pos = holdings.holding_to_position(holding)
        entry.postings.append(
            data.Posting(holding.account, pos.units, pos.cost, None, None,
                         None))

        cost = -convert.get_cost(pos)
        entry.postings.append(
            data.Posting(equity_account, cost, None, None, None, None))

        holdings_entries.append(entry)

    # Get opening directives for all the accounts.
    used_accounts = {holding.account for holding in holdings_list}
    open_entries = summarize.get_open_entries(entries, latest_date)
    used_open_entries = [
        open_entry for open_entry in open_entries
        if open_entry.account in used_accounts
    ]

    # Add an entry for the equity account we're using.
    meta = data.new_metadata('report_holdings_print', -1)
    used_open_entries.insert(
        0, data.Open(meta, latest_date, equity_account, None, None))

    # Get the latest price entries.
    price_entries = prices.get_last_price_entries(entries, None)

    return used_open_entries + holdings_entries + price_entries
Exemplo n.º 17
0
def test_insert_entry_align(tmpdir):
    file_content = dedent(
        """
        2016-02-26 * "Uncle Boons" "Eating out alone"
            Liabilities:US:Chase:Slate                       -24.84 USD
            Expenses:Food:Restaurant                          24.84 USD

    """
    )
    samplefile = tmpdir.mkdir("fava_util_file3").join("example.beancount")
    samplefile.write(file_content)

    postings = [
        data.Posting(
            "Liabilities:US:Chase:Slate",
            amount.Amount(D("-10.00"), "USD"),
            None,
            None,
            None,
            None,
        ),
        data.Posting(
            "Expenses:Food",
            amount.Amount(D("10.00"), "USD"),
            None,
            None,
            None,
            None,
        ),
    ]

    transaction = data.Transaction(
        {},
        datetime.date(2016, 1, 1),
        "*",
        "new payee",
        "narr",
        None,
        None,
        postings,
    )

    fava_options = {"currency-column": 50}
    insert_entry(transaction, [str(samplefile)], fava_options)
    assert samplefile.read() == dedent(
        """
        2016-02-26 * "Uncle Boons" "Eating out alone"
            Liabilities:US:Chase:Slate                       -24.84 USD
            Expenses:Food:Restaurant                          24.84 USD

        2016-01-01 * "new payee" "narr"
          Liabilities:US:Chase:Slate              -10.00 USD
          Expenses:Food                            10.00 USD

    """
    )
Exemplo n.º 18
0
def create_entries_from_balances(balances, date, source_account, direction,
                                 meta, flag, narration_template):
    """"Create a list of entries from a dict of balances.

    This method creates a list of new entries to transfer the amounts in the
    'balances' dict to/from another account specified in 'source_account'.

    The balancing posting is created with the equivalent at cost. In other
    words, if you attempt to balance 10 HOOL {500 USD}, this will synthesize a
    posting with this position on one leg, and with 5000 USD on the
    'source_account' leg.

    Args:
      balances: A dict of account name strings to Inventory instances.
      date: A datetime.date object, the date at which to create the transaction.
      source_account: A string, the name of the account to pull the balances
        from. This is the magician's hat to pull the rabbit from.
      direction: If 'direction' is True, the new entries transfer TO the
        balances account from the source account; otherwise the new entries
        transfer FROM the balances into the source account.
      meta: A dict to use as metadata for the transactions.
      flag: A string, the flag to use for the transactinos.
      narration_template: A format string for creating the narration. It is
        formatted with 'account' and 'date' replacement variables.
    Returns:
      A list of newly synthesizes Transaction entries.
    """
    new_entries = []
    for account, account_balance in sorted(balances.items()):

        # Don't create new entries where there is no balance.
        if account_balance.is_empty():
            continue

        narration = narration_template.format(account=account, date=date)

        if not direction:
            account_balance = -account_balance

        postings = []
        new_entry = Transaction(meta, date, flag, None, narration,
                                data.EMPTY_SET, data.EMPTY_SET, postings)

        for position in account_balance.get_positions():
            postings.append(
                data.Posting(account, position.units, position.cost, None,
                             None, None))
            cost = -convert.get_cost(position)
            postings.append(
                data.Posting(source_account, cost, None, None, None, None))

        new_entries.append(new_entry)

    return new_entries
Exemplo n.º 19
0
def remove_commissions(entries, unused_options_map, config):
    """Remove the commissions from the P/L of closing/sales transactions."""

    try:
        commission_regexp, income_regexp, outgoing_account = parse_config(
            config)
    except ValueError:
        return [], [
            Error(None, "Invalid configuration for {} plugin".format(__file__),
                  None)
        ]

    new_entries = []
    for entry in entries:
        # Match the transaction.
        if (isinstance(entry, data.Transaction) and any(
                income_regexp.match(posting.account)
                for posting in entry.postings) and any(
                    commission_regexp.match(posting.account)
                    for posting in entry.postings)):

            # Find the commissions amounts.
            commissions = inventory.Inventory()
            for posting in entry.postings:
                if commission_regexp.match(posting.account):
                    commissions.add_amount(posting.units)

            # Find the first income account.
            for posting in entry.postings:
                if income_regexp.match(posting.account):
                    income_account = posting.account
                    break
            assert income_account, "Income account not found."

            # Insert the new legs.
            new_postings = []
            for cposition in commissions:
                new_postings.extend([
                    data.Posting(income_account, cposition.units, None, None,
                                 None, None),
                    data.Posting(outgoing_account, -cposition.units, None,
                                 None, None, None),
                ])

                # Distribute the commission.
                distribute_commission_on_metadata(cposition.units,
                                                  entry.postings)

            entry = entry._replace(postings=entry.postings + new_postings)

        new_entries.append(entry)

    return new_entries, []
Exemplo n.º 20
0
    def extract(self, file, existing_entries=None) -> list:
        # TODO: check for duplicates
        with open(file.name, "rb") as _file:
            transactions = pickle.load(_file)
        entries = []
        transactions = sorted(transactions, key=lambda tx: (tx["time"], tx["tx_id"]))
        for tx_id, transfers in groupby(transactions, lambda tx: tx["tx_id"]):
            tx_date = None
            metadata = {"txid": tx_id}
            postings = []
            for transfer in transfers:
                if tx_date is None:
                    tx_date = transfer["time"].date()
                if transfer["value"] == 0:
                    continue
                account_from = self._find_account(
                    transfer["from"], -transfer["value"], transfer["currency"],
                )
                posting_from = data.Posting(
                    account_from,
                    amount.Amount(D(-transfer["value"]), transfer["currency"]),
                    None,
                    None,
                    None,
                    None,
                )
                postings.append(posting_from)
                account_to = self._find_account(
                    transfer["to"], transfer["value"], transfer["currency"],
                )
                posting_to = data.Posting(
                    account_to,
                    amount.Amount(D(transfer["value"]), transfer["currency"]),
                    None,
                    None,
                    None,
                    None,
                )
                postings.append(posting_to)

            entry = data.Transaction(
                data.new_metadata("", 0, metadata),
                tx_date,
                "*",
                "",
                "",
                data.EMPTY_SET,
                data.EMPTY_SET,
                postings,
            )
            entries.append(entry)

        return entries
Exemplo n.º 21
0
    def Dividends(self, match):
        # this function crates Dividend transactions from IBKR data
        # make dividend & WHT transactions

        divTransactions = []
        for idx, row in match.iterrows():
            currency = row['currency_x']
            currency_wht = row['currency_y']
            if currency != currency_wht:
                warnings.warn('Warnging: Dividend currency {} ' +
                              'mismatches WHT currency {}. Skipping this' +
                              'Transaction'.format(currency, currency_wht))
                continue
            symbol = row['symbol']

            amount_div = amount.Amount(row['amount_x'], currency)
            amount_wht = amount.Amount(row['amount_y'], currency)

            text = row['description_x']
            # Find ISIN in description in parentheses
            isin = re.findall('\(([a-zA-Z]{2}[a-zA-Z0-9]{9}\d)\)', text)[0]
            pershare_match = re.search('(\d*[.]\d*)(\D*)(PER SHARE)', text,
                                       re.IGNORECASE)
            # payment in lieu of a dividend does not have a PER SHARE in description
            pershare = pershare_match.group(1) if pershare_match else ''

            # make the postings, three for dividend/ wht transactions
            postings = [
                data.Posting(self.getDivIncomeAcconut(currency, symbol),
                             -amount_div, None, None, None, None),
                data.Posting(self.getWHTAccount(symbol), -amount_wht, None,
                             None, None, None),
                data.Posting(self.getLiquidityAccount(currency),
                             AmountAdd(amount_div, amount_wht), None, None,
                             None, None)
            ]
            meta = data.new_metadata('dividend', 0, {
                'isin': isin,
                'per_share': pershare
            })
            divTransactions.append(
                data.Transaction(
                    meta,  # could add div per share, ISIN,....
                    row['reportDate'],
                    self.flag,
                    symbol,  # payee
                    'Dividend ' + symbol,
                    data.EMPTY_SET,
                    data.EMPTY_SET,
                    postings))

        return divTransactions
 def guess_postings(self, payee, total_transaction_value):
     '''Guess postings based on the previous transactions with the same payee.
     The guess is simply the most recent transaction with the same payee. If the transaction consists of multiple postings, the total_transaction_value is distributed to the postings in the same ratios as in the previous posting. 
     If there is no previous transaction with the same payee, the target account is the default_adjacent_account. 
     
     Parameters
     ----------
     payee:                      string
     total_transaction_value:    float
     '''
     new_postings = []
     if payee in self.posting_dict:
         previous_postings = self.posting_dict[payee][-1]
         accounts = []
         units = []
         for prev_posting in previous_postings:
             accounts.append(prev_posting.account)
             units.append(prev_posting.units)
             if prev_posting.account == self.account:
                 prev_posting_had_reversed_signs = 0 > float(
                     prev_posting.units.number) * total_transaction_value
         s = sum([float(u.number) for u in units if u.number > 0])
         for account, unit in zip(accounts, units):
             share = float(unit.number) / s
             if prev_posting_had_reversed_signs:
                 share = -share
             p = data.Posting(
                 account,
                 amount.Amount(
                     D(str(round(share * abs(total_transaction_value), 2))),
                     self.currency), None, None, None, None)
             new_postings.append(p)
         #move importing_account to the end of the list
         i = 0
         for j, posting in enumerate(new_postings):
             if posting.account == self.account:
                 i = j
         new_postings.append(new_postings.pop(i))
     else:
         new_postings.append(
             data.Posting(
                 self.default_adjacent_account,
                 amount.Amount(D(str(-total_transaction_value)),
                               self.currency), None, None, None, None))
         new_postings.append(
             data.Posting(
                 self.account,
                 amount.Amount(D(str(total_transaction_value)),
                               self.currency), None, None, None, None))
     return new_postings
Exemplo n.º 23
0
    def extract(self, file, existing_entries=None):
        # Open the CSV file and create directives.
        entries = []
        with open(file.name, encoding="utf-8") as f:
            for _ in range(16):
                next(f)
            for index, row in enumerate(reversed(list(csv.DictReader(f)))):
                flag = flags.FLAG_WARNING
                dt = parse(row["交易时间"])
                meta = data.new_metadata(
                    file.name, index, kvlist={"time": str(dt.time())}
                )
                amount = Amount(D(row["金额(元)"].lstrip("¥")), self.currency)
                if row["收/支"] in {"支出", "/"}:
                    # 支出
                    amount = -amount
                payee = row["交易对方"]
                narration: str = row["商品"]
                if narration.startswith(_COMMENTS_STR):
                    narration = narration.replace(_COMMENTS_STR, "")
                if narration == "/":
                    narration = ""
                account_1_text = row["支付方式"]
                account_1 = "Assets:FIXME"
                for asset_k, asset_v in self.accountDict.items():
                    if asset_k in account_1_text:
                        account_1 = asset_v
                        flag = flags.FLAG_OKAY

                postings = [data.Posting(account_1, amount, None, None, None, None)]

                if row["当前状态"] == "充值完成":
                    postings.insert(
                        0,
                        data.Posting(self.account, -amount, None, None, None, None),
                    )
                    narration = "微信零钱充值"
                    payee = None
                txn = data.Transaction(
                    meta,
                    dt.date(),
                    flag,
                    payee,
                    narration,
                    self.default_set,
                    data.EMPTY_SET,
                    postings,
                )
                entries.append(txn)
        return entries
Exemplo n.º 24
0
    def Shopping(self, buy):
        # let's go shopping!!

        Shoppingbag = []
        for idx, row in buy.iterrows():
            # continue # debugging
            currency = row['currency']
            currency_IBcommision = row['ibCommissionCurrency']
            symbol = row['symbol']
            proceeds = amount.Amount(row['proceeds'].__round__(2), currency)
            commission = amount.Amount((row['ibCommission'].__round__(2)),
                                       currency_IBcommision)
            quantity = amount.Amount(row['quantity'], symbol)
            price = amount.Amount(row['tradePrice'], currency)
            text = row['description']

            number_per = D(row['tradePrice'])
            currency_cost = currency
            cost = position.CostSpec(number_per=price.number,
                                     number_total=None,
                                     currency=currency,
                                     date=row['tradeDate'],
                                     label=None,
                                     merge=False)

            postings = [
                data.Posting(self.getAssetAccount(symbol), quantity, cost,
                             None, None, None),
                data.Posting(self.getLiquidityAccount(currency), proceeds,
                             None, None, None, None),
                data.Posting(self.getLiquidityAccount(currency_IBcommision),
                             commission, None, None, None, None),
                data.Posting(self.getFeesAccount(currency_IBcommision),
                             minus(commission), None, None, None, None)
            ]

            Shoppingbag.append(
                data.Transaction(
                    data.new_metadata('Buy', 0),
                    row['dateTime'].date(),
                    self.flag,
                    symbol,  # payee
                    ' '.join(
                        ['BUY',
                         quantity.to_string(), '@',
                         price.to_string()]),
                    data.EMPTY_SET,
                    data.EMPTY_SET,
                    postings))
        return Shoppingbag
Exemplo n.º 25
0
    def Forex(self, fx):
        # returns beancount transactions for IBKR forex transactions

        fxTransactions = []
        for idx, row in fx.iterrows():

            symbol = row['symbol']
            curr_prim, curr_sec = getForexCurrencies(symbol)
            currency_IBcommision = row['ibCommissionCurrency']
            proceeds = amount.Amount(row['proceeds'], curr_sec)
            quantity = amount.Amount(row['quantity'], curr_prim)
            price = amount.Amount(row['tradePrice'], curr_sec)
            commission = amount.Amount(row['ibCommission'],
                                       currency_IBcommision)
            buysell = row['buySell'].name

            cost = position.CostSpec(number_per=None,
                                     number_total=None,
                                     currency=None,
                                     date=None,
                                     label=None,
                                     merge=False)

            postings = [
                data.Posting(self.getLiquidityAccount(curr_prim), quantity,
                             None, price, None, None),
                data.Posting(self.getLiquidityAccount(curr_sec), proceeds,
                             None, None, None, None),
                data.Posting(self.getLiquidityAccount(currency_IBcommision),
                             commission, None, None, None, None),
                data.Posting(self.getFeesAccount(currency_IBcommision),
                             minus(commission), None, None, None, None)
            ]

            fxTransactions.append(
                data.Transaction(
                    data.new_metadata('FX Transaction', 0),
                    row['tradeDate'],
                    self.flag,
                    symbol,  # payee
                    ' '.join([
                        buysell,
                        quantity.to_string(), '@',
                        price.to_string()
                    ]),
                    data.EMPTY_SET,
                    data.EMPTY_SET,
                    postings))
        return fxTransactions
Exemplo n.º 26
0
    def extract(self, f):
        entries = []
        with open(f.name, newline="") as f:
            for index, row in enumerate(csv.DictReader(f, delimiter=",")):
                tx_date = parse(row["date"]).date()
                tx_desc = row["memo"].strip()
                tx_amt = row["amount"].strip()
                tx_payee = row["from"].strip()

                meta = data.new_metadata(f.name, index)
                tx = data.Transaction(
                    meta=meta,
                    date=tx_date,
                    flag=flags.FLAG_OKAY,
                    payee=tx_payee,
                    narration=tx_desc,
                    tags=set(),
                    links=set(),
                    postings=[],
                )

                if row["type"] == "expense":
                    to = row["to"]
                    tx_amt = -D(tx_amt)
                else:
                    to = abbr.abbr[row["to"]]

                tx.postings.append(
                    data.Posting(
                        abbr.abbr[row["from"]],
                        amount.Amount(-D(tx_amt), "TWD"),
                        None,
                        None,
                        None,
                        None,
                    ))
                tx.postings.append(
                    data.Posting(
                        to,
                        None,
                        None,
                        None,
                        None,
                        None,
                    ))

                entries.append(tx)
        return entries
Exemplo n.º 27
0
 def test_render_posting_price(self):
     str_posting = journal_text.render_posting(
         data.Posting('Assets:Something', position.from_string('10 VHT'),
                      A('45.32 USD'), None, None), self.number_format)
     self.assertEqual(
         '  Assets:Something                 10 VHT @ 45.32 USD',
         str_posting)
Exemplo n.º 28
0
    def complete_entry(self, entry):
        """Complete the given entry.

        This method attempts to complete the entry only if it is a transaction
        with a single posting to the account bound to the completer.
        The entry will be completed only if a suitable model transaction can
        be found.
        If multiple model transactions are found that balance the transaction
        against different account, the missing posting will be flagged for
        review.

        Args:
          entry: The entry to be completed.
        Returns: True is the entry was completed; False, otherwise.
        """
        if (isinstance(entry, data.Transaction) and len(entry.postings) == 1
                and entry.postings[0].account == self.account):
            model_txn, model_accounts = self.find_best_model(entry)
            if model_txn:
                # If past transactions similar to this one were posted against
                # different accounts, flag the posting in the new entry.
                flag = flags.FLAG_WARNING if len(model_accounts) > 1 else None
                # Add the missing posting to balance the transaction
                for posting in model_txn.postings:
                    if posting.account != self.account:
                        units = -entry.postings[
                            0].units if self.interpolated else None
                        missing_posting = data.Posting(posting.account, units,
                                                       None, None, flag, None)
                        entry.postings.append(missing_posting)
                return True
        return False
Exemplo n.º 29
0
    def get_postings(self, row: Row):
        if "fee" in row.narration.casefold():
        elif "contribution" in row.narration.casefold():
        postings = [
            data.Posting(
                account=account,
                units=-self.get_amount(row),
                cost=None,
                price=None,
                flag=flag,
                meta={},
            )
        ]
        return postings

    def get_expense_posting(self, row: Row):
        return data.Posting(
            account=self.expense_account,
            units=self.get_amount(row),
            cost=None,
            price=None,
            flag=None,
            meta={},
        )

    def get_amount(self, row: Row):
        total = row.item_total.strip(''.join(self.currency_symbols))
        return data.Amount(number.D(total), row.currency)
Exemplo n.º 30
0
    def __txn_vacation(self, meta, date, desc, units_vac, units_ovt, price):
        """Return a holiday transaction object."""
        self.logger.debug("Entering Function")

        txn =  data.Transaction(
            meta, date, "!", self.employer, desc, data.EMPTY_SET, data.EMPTY_SET, [
                data.Posting(self.account_vacation, units_vac, None, None, None, None),
                data.Posting(self.account_employer_vacation, -units_vac, None, None, None, None),
                data.Posting(self.account_vacation, units_vac, None, price, "!", None),
                data.Posting(self.account_employer_overtime, -units_ovt, None, None, "!", None)
                ])

        self.logger.debug('Transaction to be recorded: %s', str(txn))
        self.logger.debug("Leaving Function")
        
        return txn