From fe8e87ad0ea273833e67f88b480d153839ebb160 Mon Sep 17 00:00:00 2001 From: Roger Oriol Date: Wed, 27 Dec 2023 12:10:09 +0100 Subject: [PATCH] add outflows from investment to cash flow statement report --- commands/cash-flow-statement | 37 ++++++++++++++++++++++----- ledger/transactions/2024/01.beancount | 6 ++--- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/commands/cash-flow-statement b/commands/cash-flow-statement index 2fd8644..5540d32 100755 --- a/commands/cash-flow-statement +++ b/commands/cash-flow-statement @@ -5,7 +5,7 @@ from beancount.parser import printer import argparse from tabulate import tabulate from decimal import Decimal -from beancount.core.amount import Amount, sub, mul +from beancount.core.amount import Amount, add, sub, mul from datetime import date from dateutil.relativedelta import relativedelta @@ -55,17 +55,26 @@ def get_total_inflows(income): else: return Amount(Decimal(0), "EUR") -def get_total_outflows(expenses): +def get_total_outflows(expenses, total_investments): sum = 0 for account, balance in expenses.items(): sum = balance if sum == 0 else sum + balance if sum != 0 and sum.get_only_position() != None: result = sum.get_only_position().units - return Amount(Decimal(round(result.number, 2)), result.currency) + return add(Amount(Decimal(round(result.number, 2)), result.currency), total_investments) + else: + return total_investments + +def get_total_investments(investments): + sum = 0 + for inv in investments: + sum = inv.cost_position if sum == 0 else sum + inv.cost_position + if sum != 0 and sum != None: + return Amount(Decimal(round(sum.number, 2)), sum.currency) else: return Amount(Decimal(0), "EUR") -def print_report(start_date, period, income, expenses): +def print_report(start_date, period, income, expenses, investments): print(f"{bcolors.BOLD}Cash Flow Statement (period={period}, start_date={start_date}){bcolors.ENDC}") draw_line() print(f"{bcolors.BOLD}Inflows{bcolors.ENDC}") @@ -95,11 +104,16 @@ def print_report(start_date, period, income, expenses): draw_line() print(f"{bcolors.BOLD}Outflows{bcolors.ENDC}") print_expenses_table(expenses) + print(f"{bcolors.BOLD}Outflows from Investment{bcolors.ENDC}") + total_investments = get_total_investments(investments) print(tabulate([ - ["Total Outflows", f"{bcolors.BOLD}{get_total_outflows(expenses).to_string()}{bcolors.ENDC}"] + ["Compra de fons i accions", total_investments.to_string()] + ])) + print(tabulate([ + ["Total Outflows", f"{bcolors.BOLD}{get_total_outflows(expenses, total_investments).to_string()}{bcolors.ENDC}"] ])) draw_line() - net_cash_flow = sub(get_total_inflows(income), get_total_outflows(expenses)) + net_cash_flow = sub(get_total_inflows(income), get_total_outflows(expenses, total_investments)) print(tabulate([ ["NET CASH FLOW", f"{bcolors.BOLD}{bcolors.OKGREEN if net_cash_flow.number >= 0 else bcolors.FAIL}{net_cash_flow.to_string()}{bcolors.ENDC}"] ])) @@ -126,6 +140,14 @@ def get_expenses(entries, options, period, start_date): expenses[row.account] = row.sum_position return expenses +def get_investments(entries, options, period, start_date): + period_delta = relativedelta(months=1) if period == "monthly" else relativedelta(years=1) + end_date = date.fromisoformat(start_date) + period_delta + expenses_query = f"SELECT account, cost(position), currency, date WHERE account ~ \"Assets:Invest:R4:\" AND NOT currency ~ '^(EUR|USD)' AND date >= {start_date} AND date < {end_date.isoformat()}" + rtypes, rrows = query.run_query( + entries, options, expenses_query) + return rrows + def main(): parser = argparse.ArgumentParser(description='Generate cash flow report') parser.add_argument('start_date', metavar='start_date', type=str, nargs=1, @@ -145,6 +167,7 @@ def main(): income = get_income(entries, options, period, start_date) expenses = get_expenses(entries, options, period, start_date) - print_report(start_date, period, income, expenses) + investments = get_investments(entries, options, period, start_date) + print_report(start_date, period, income, expenses, investments) main() \ No newline at end of file diff --git a/ledger/transactions/2024/01.beancount b/ledger/transactions/2024/01.beancount index 3787274..d795645 100644 --- a/ledger/transactions/2024/01.beancount +++ b/ledger/transactions/2024/01.beancount @@ -46,11 +46,9 @@ 2024-01-01 balance Assets:Debt:DeutesPerCobrar 0 EUR 2024-01-01 * "Zurich" "Cuota gimnàs Andjoy" - ;amortize_months: 12 Expenses:Gimnàs 508.80 EUR Income:Work:Zurich:Gimnas 2024-01-01 * "Zurich" "Cuota seguro salut Cigna Salud OPT (solo cobertura extra hospitalaria)" - ;amortize_months: 12 Expenses:Medic 414.60 EUR Income:Work:Zurich:SeguroMedic 2024-01-01 * "Zurich" "Targeta Transport" @@ -62,14 +60,14 @@ 2024-02-01 balance Assets:Liquid:Caixabank:Corrent 18903.80 EUR 2024-02-01 balance Assets:Liquid:Caixabank:Estalvi 12666.49 EUR -;2024-02-01 balance Assets:Liquid:R4:EUR 44.04 EUR +2024-02-01 balance Assets:Liquid:R4:EUR 44.04 EUR 2024-02-01 balance Assets:Invest:R4:Amundi:MSCIWRLD 86.005 AMNDMSCIWRLD 2024-02-01 balance Assets:Invest:R4:Vanguard:EMMK 14.99 VANEMMK 2024-02-01 balance Assets:Invest:R4:Fidelity:GLTECH 344.47 FIGLTECH 2024-02-01 balance Assets:Invest:R4:Amundi:SUSTINC 11.295 AMNDSUSINC 2024-02-01 balance Assets:Invest:R4:BNP:DISTECH 0.359 BNPDISTECH 2024-02-01 balance Assets:Invest:R4:PLTR 10 PLTR -;2024-02-01 balance Assets:Invest:R4:MSFT 4 MSFT +2024-02-01 balance Assets:Invest:R4:MSFT 4 MSFT 2024-02-01 balance Assets:Benefits:Edenred:TicketsRestaurant 209 EUR 2024-02-01 balance Assets:Benefits:Edenred:TargetaTransport 40 EUR 2024-02-01 balance Assets:PersonalProperty:VivendaPrincipal 0 EUR