From c0ebdf099afc7db6b9465e5ed79b5f52cd25e2d7 Mon Sep 17 00:00:00 2001 From: Roger Oriol Date: Sun, 21 Dec 2025 12:21:08 +0100 Subject: [PATCH] 21 desembre 2025 --- commands/balance-sheet | 86 ++++--- ledger/transactions/2025/12.beancount | 35 ++- reports/balance-sheet-report-2025-12-21.txt | 71 ++++++ reports/balsheet/20231217/balsheet.html | 259 -------------------- 4 files changed, 160 insertions(+), 291 deletions(-) create mode 100644 reports/balance-sheet-report-2025-12-21.txt delete mode 100644 reports/balsheet/20231217/balsheet.html diff --git a/commands/balance-sheet b/commands/balance-sheet index d09513c..d7be5ed 100755 --- a/commands/balance-sheet +++ b/commands/balance-sheet @@ -26,7 +26,7 @@ def draw_line(): print('─' * 30) -def get_last_month_timestamps(date): +def get_month_to_date_timestamps(date): month = int(date.split("-")[1]) year = int(date.split("-")[0]) d = datetime(year, month, 1) @@ -35,6 +35,14 @@ def get_last_month_timestamps(date): return start_date, end_date.strftime("%Y-%m-%d") +def get_last_year_timestamps(date): + date_parts = date.split("-") + day = int(date_parts[2]) + month = int(date_parts[1]) + year = int(date_parts[0]) + return f"{year-1}-{month:02d}-{day:02d}", date + + def get_sum_balances(balances, account_prefix): sum = 0 for account, balance in balances.items(): @@ -64,7 +72,8 @@ def get_debt_to_assets_ratio(balances, max): def get_emergency_fund_ratio(balances, expenses, low, mid): liquid = 0 - living_expenses = expenses[0].position.get_only_position().units.number + living_expenses = expenses[0].position.get_only_position( + ).units.number / 12 for account, balance in balances.items(): if account.startswith("Assets:Liquid"): liquid = balance if liquid == 0 else liquid + balance @@ -72,7 +81,7 @@ def get_emergency_fund_ratio(balances, expenses, low, mid): ) == None else liquid.get_only_position().units result = round(total_liquid.number / living_expenses, 2) color = bcolors.FAIL if result < low else bcolors.OKGREEN if result > mid else bcolors.WARNING - return f"{color}{result}{bcolors.ENDC}" + return f"{color}{result} mth{bcolors.ENDC}" def get_investment_assets_to_net_worth_ratio(balances, min): @@ -95,18 +104,19 @@ def get_liquid_assets_to_net_worth_ratio(balances, min): return f"{bcolors.FAIL if result < min else bcolors.OKGREEN}{result} %{bcolors.ENDC}" -def get_savings_ratio(balances, gross_monthly_income, monthly_savings, min): - result = round((monthly_savings.number / gross_monthly_income) * 100, 2) +def get_savings_ratio(balances, net_yearly_income, yearly_savings, min): + result = round((yearly_savings.number / + net_yearly_income) * 100, 2) return f"{bcolors.FAIL if result < min else bcolors.OKGREEN}{result} %{bcolors.ENDC}" -def get_debt_service_ratio(balances, gross_monthly_income, debt_payments, max): - result = round((debt_payments.number / gross_monthly_income) * 100, 2) +def get_debt_service_ratio(balances, net_yearly_income, debt_payments, max): + result = round((debt_payments.number / net_yearly_income) * 100, 2) return f"{bcolors.FAIL if result >= max else bcolors.OKGREEN}{result} %{bcolors.ENDC}" -def get_non_mortgage_debt_service_ratio(balances, gross_monthly_income, mortgage_payments, max): - result = round((mortgage_payments.number / gross_monthly_income) * 100, 2) +def get_non_mortgage_debt_service_ratio(balances, net_yearly_income, mortgage_payments, max): + result = round((mortgage_payments.number / net_yearly_income) * 100, 2) return f"{bcolors.FAIL if result >= max else bcolors.OKGREEN}{result} %{bcolors.ENDC}" @@ -117,11 +127,11 @@ def get_solvency_ratio(balances, min): return f"{bcolors.FAIL if result < min else bcolors.OKGREEN}{result} %{bcolors.ENDC}" -def get_interest_coverage_ratio(gross_monthly_income, expenses, debt_payments, mortgage_payments, min): +def get_interest_coverage_ratio(net_monthly_income, expenses, debt_payments, mortgage_payments, min): living_expenses = expenses[0].position.get_only_position().units.number interest = debt_payments.number + mortgage_payments.number interest = interest if interest > 0 else 1 - result = round((gross_monthly_income - living_expenses) / interest, 2) + result = round((net_monthly_income - living_expenses) / interest, 2) return f"{bcolors.FAIL if result < min else bcolors.OKGREEN}{result}{bcolors.ENDC}" @@ -138,7 +148,7 @@ def get_position_as_str(inventory): return Amount(Decimal(round(position.units.number, 2)), position.units.currency).to_string() -def print_report(date, balances, expenses, income, debt_payments, mortgage_payments, savings): +def print_report(date, balances, expenses, net_monthly_income, net_yearly_income, debt_payments, mortgage_payments, savings): print(f"{bcolors.BOLD}Balance Sheet (date={date}){bcolors.ENDC}") draw_line() print(f"{bcolors.BOLD}Assets{bcolors.ENDC}") @@ -202,8 +212,10 @@ def print_report(date, balances, expenses, income, debt_payments, mortgage_payme balances["Liabilities:Hipoteca:VivendaPrincipal"] * Decimal(-1))], ["Hipoteques en vivenda d'inversió", Amount(Decimal(0), "EUR").to_string()], - ["Crèdit", get_position_as_str( + ["Targetes de crèdit", get_position_as_str( balances["Liabilities:Credit:Caixabank:TargetaCredit"] * Decimal(-1))], + ["Línies de crèdit per inversió", get_position_as_str( + balances["Liabilities:Credit:Renta4:PolissaCredit"] * Decimal(-1))], ["Factures impagades", get_position_as_str( balances["Liabilities:Factures:FacturesPendents"] * Decimal(-1))], ["Préstecs personals", Amount(Decimal(0), "EUR").to_string()], @@ -225,19 +237,19 @@ def print_report(date, balances, expenses, income, debt_payments, mortgage_payme ["Debt-to-Assets Ratio", get_debt_to_assets_ratio(balances, 50), "50 %"], ["Emergency Fund", get_emergency_fund_ratio( - balances, expenses, 3, 6), "3-6"], + balances, expenses, 3, 6), "3-6 mth"], ["Investment Assets to Net Worth Ratio", get_investment_assets_to_net_worth_ratio(balances, 50), "50 %"], ["Liquid Assets to Net Worth Ratio", get_liquid_assets_to_net_worth_ratio(balances, 15), "15 %"], ["Savings Ratio", get_savings_ratio( - balances, income, savings, 20), "20 %"], + balances, net_yearly_income, savings, 20), "20 %"], ["Debt-Service Ratio", - get_debt_service_ratio(balances, income, debt_payments, 35), "35 %"], + get_debt_service_ratio(balances, net_yearly_income, debt_payments, 35), "35 %"], ["Non-Mortgage Debt-Service Ratio", - get_non_mortgage_debt_service_ratio(balances, income, mortgage_payments, 15), "15 %"], + get_non_mortgage_debt_service_ratio(balances, net_yearly_income, mortgage_payments, 15), "15 %"], ["Interest Coverage Ratio", get_interest_coverage_ratio( - income, expenses, debt_payments, mortgage_payments, 1.5), "1.5"] + net_yearly_income, expenses, debt_payments, mortgage_payments, 1.5), "1.5"] ])) @@ -253,7 +265,7 @@ def get_balances(entries, options, date): def get_expenses(entries, options, date): - start_date, end_date = get_last_month_timestamps(date) + start_date, end_date = get_last_year_timestamps(date) expenses_query = f"SELECT convert(sum(position), \"EUR\") as position FROM date <= { end_date} WHERE account ~ 'Expenses:' AND date >= {start_date}" rtypes, rrows = query.run_query( @@ -262,17 +274,27 @@ def get_expenses(entries, options, date): def get_income(entries, options, date): - start_date, end_date = get_last_month_timestamps(date) + start_date, end_date = get_month_to_date_timestamps(date) income_query = f"SELECT convert(sum(position), \"EUR\") as position FROM date <= { end_date} WHERE account ~ '^(Income:Work|Income:Savings|Income:Invest)' AND date >= {start_date}" rtypes, rrows = query.run_query( entries, options, income_query) - return rrows + net_monthly_income = rrows[0].position.get_only_position( + ).units.number * -1 + + start_date, end_date = get_last_year_timestamps(date) + income_query = f"SELECT convert(sum(position), \"EUR\") as position FROM date <= { + end_date} WHERE account ~ '^(Income:Work|Income:Savings|Income:Invest)' AND date >= {start_date}" + rtypes, rrows = query.run_query( + entries, options, income_query) + net_yearly_income = rrows[0].position.get_only_position( + ).units.number * -1 + return net_monthly_income, net_yearly_income def get_debt_payments(entries, options, date): # FIX: Agafar nomes els pagaments de deute, enlloc de també les addicions de deute - start_date, end_date = get_last_month_timestamps(date) + start_date, end_date = get_last_year_timestamps(date) debt_payments_query = f"SELECT convert(sum(position), \"EUR\") as position FROM date <= { end_date} WHERE account ~ 'Expenses:R4:Interessos' AND date >= {start_date}" mortgage_payments_query = f"SELECT convert(sum(position), \"EUR\") as position FROM date <= { @@ -289,13 +311,20 @@ def get_debt_payments(entries, options, date): def get_savings(entries, options, date): - start_date, end_date = get_last_month_timestamps(date) - savings_query = f"SELECT convert(sum(position), \"EUR\") as position FROM date <= { + start_date, end_date = get_last_year_timestamps(date) + investments_query = f"SELECT convert(sum(position), \"EUR\") as position FROM date <= { end_date} WHERE account ~ '^Assets:Invest:' AND date >= {start_date}" rtypes, rrows = query.run_query( - entries, options, savings_query) + entries, options, investments_query) result = rrows[0].position.get_only_position().units if len( rrows) > 0 else Amount(Decimal(0), "EUR") + liabilities_query = f"SELECT convert(sum(position), \"EUR\") as position FROM date <= { + end_date} WHERE account ~ '^Liabilities:Credit:Renta4:' AND date >= {start_date}" + rtypes, rrows = query.run_query( + entries, options, liabilities_query) + liabilities = rrows[0].position.get_only_position().units if len( + rrows) > 0 else Amount(Decimal(0), "EUR") + result = add(result, liabilities) return result @@ -316,13 +345,12 @@ def main(): balances = get_balances(entries, options, date) expenses = get_expenses(entries, options, date) - income = get_income(entries, options, date) - gross_monthly_income = income[0].position.get_only_position( - ).units.number * -1 + net_monthly_income, net_yearly_income = get_income( + entries, options, date) debt_payments, mortgage_payments = get_debt_payments( entries, options, date) savings = get_savings(entries, options, date) - print_report(date, balances, expenses, gross_monthly_income, + print_report(date, balances, expenses, net_monthly_income, net_yearly_income, debt_payments, mortgage_payments, savings) diff --git a/ledger/transactions/2025/12.beancount b/ledger/transactions/2025/12.beancount index 6641f99..f4f57ce 100644 --- a/ledger/transactions/2025/12.beancount +++ b/ledger/transactions/2025/12.beancount @@ -127,8 +127,37 @@ 2025-12-14 * "La Marató" "Donació La Marató de TV3" Expenses:Donatiu 20 EUR Assets:Liquid:Caixabank:Corrent +2025-12-14 * "Miquel Albareda" "Factures novembre" + Income:Other:Caixabank:Transferencia -49.23 EUR + Assets:Liquid:Caixabank:Corrent 49.23 EUR + Expenses:FacturesUtilitats -49.23 EUR + Equity:FacturesUtilitatsMiquel 49.23 EUR +2025-12-15 * "Plusfresc" "Compra de la setmana" + Expenses:Supermercat 30.09 EUR + Assets:Liquid:Caixabank:Corrent +2025-12-18 * "Naturgy" "Factura gas" + Expenses:FacturesUtilitats 29.66 EUR + Assets:Liquid:Caixabank:Corrent +2025-12-18 * "Don Zangano" "Esmorzar" + Expenses:MenjarFora 5.10 EUR + Assets:Benefits:Edenred:TicketsRestaurant +2025-12-18 * "Aerobus" "Bitllet anada i tornada aeroport" + Expenses:Mobilitat 12.85 EUR + Assets:Benefits:Edenred:TargetaTransport +2025-12-18 * "Burger King" "Sopar aeroport" + Expenses:MenjarFora 12.15 EUR + Assets:Benefits:Edenred:TicketsRestaurant +2025-12-19 * "TradeRepublic" "Tancament compte TradeRepublic" + Income:Savings:TradeRepublic:RentabilitatEstalvis -0.01 EUR + Assets:Liquid:Caixabank:Corrent +2025-12-20 * "Amazon" "Valissa DGT" + Expenses:Altres 41.99 EUR + Assets:Liquid:Caixabank:Corrent +2025-12-20 * "Che Argentino" "Sopar asador argentino palma" + Expenses:MenjarFora 51.70 EUR + Assets:Benefits:Edenred:TicketsRestaurant -2026-01-01 balance Assets:Liquid:Caixabank:Corrent 11919.33 EUR +2026-01-01 balance Assets:Liquid:Caixabank:Corrent 11866.83 EUR 2026-01-01 balance Assets:Liquid:R4:EUR 0 EUR 2026-01-01 balance Assets:Invest:Fund:Vanguard:EMMK 14.99 VANEMMK 2026-01-01 balance Assets:Invest:Fund:Vanguard:GL 776.93 VANGL @@ -136,8 +165,8 @@ 2026-01-01 balance Assets:Invest:ETF:IWVL 430 IWVL 2026-01-01 balance Assets:Invest:Fixed:R4RF 1518.57004 R4RF 2026-01-01 balance Assets:Invest:ETF:XDEQ 264 XDEQ -2026-01-01 balance Assets:Benefits:Edenred:TicketsRestaurant 114.87 EUR -2026-01-01 balance Assets:Benefits:Edenred:TargetaTransport 76.50 EUR +2026-01-01 balance Assets:Benefits:Edenred:TicketsRestaurant 45.92 EUR +2026-01-01 balance Assets:Benefits:Edenred:TargetaTransport 63.65 EUR 2026-01-01 balance Assets:Benefits:DZP:PPEZurich 4048.45 EUR 2026-01-01 balance Assets:PersonalProperty:VivendaPrincipal 0 EUR 2026-01-01 balance Assets:PersonalProperty:Cotxe 8174 EUR diff --git a/reports/balance-sheet-report-2025-12-21.txt b/reports/balance-sheet-report-2025-12-21.txt new file mode 100644 index 0000000..7bcbb03 --- /dev/null +++ b/reports/balance-sheet-report-2025-12-21.txt @@ -0,0 +1,71 @@ +Balance Sheet (date=2025-12-21) +────────────────────────────── +Assets + Liquids +----------------- ------------ +Corrent 11866.83 EUR +Estalvi 0 EUR +Compte d'inversió 0 EUR +Total líquids 11866.83 EUR +----------------- ------------ + Inversions +---------------- ------------- +Fons d'inversió 70353.30 EUR +ETFs 39129.40 EUR +Accions 0 EUR +Renta fixa 23712.25 EUR +Total inversions 133194.95 EUR +---------------- ------------- + Propietat personal +---------------------------- ----------- +Vivenda principal 0 EUR +Cotxes 8174.00 EUR +Joies, Art, Col·leccionables 50.00 EUR +Metalls preciosos 0 EUR +Altres propietats 0 EUR +Total propietats 8224.00 EUR +---------------------------- ----------- + Deutes +----------------- ----- +Deutes per cobrar +Total deutes 0 EUR +----------------- ----- + Beneficis laborals +----------------------------- ----------- +Tickets Restaurant 45.92 EUR +Targeta Transport 63.65 EUR +Pla Pensions Empleados Zurich 4048.45 EUR +Total beneficis 4158.02 EUR +----------------------------- ----------- +------------ ------------- +Total Assets 157443.80 EUR +------------ ------------- +────────────────────────────── +Liabilites +-------------------------------- ------------ +Hipoteques en vivenda principal +Hipoteques en vivenda d'inversió 0 EUR +Targetes de crèdit 445.91 EUR +Línies de crèdit per inversió 19971.26 EUR +Factures impagades +Préstecs personals 0 EUR +Impostos no pagats +Altres passius 0 EUR +-------------------------------- ------------ +------------- ------------- +Total passius -20417.17 EUR +------------- ------------- +────────────────────────────── +Net Worth 137026.63 EUR +────────────────────────────── +Financial Ratios +------------------------------------ -------- ------- +Debt-to-Assets Ratio 12.97 % 50 % +Emergency Fund 4.18 mth 3-6 mth +Investment Assets to Net Worth Ratio 97.20 % 50 % +Liquid Assets to Net Worth Ratio 105.86 % 15 % +Savings Ratio 35.58 % 20 % +Debt-Service Ratio 0.96 % 35 % +Non-Mortgage Debt-Service Ratio 0.00 % 15 % +Interest Coverage Ratio 33.34 1.5 +------------------------------------ -------- ------- diff --git a/reports/balsheet/20231217/balsheet.html b/reports/balsheet/20231217/balsheet.html deleted file mode 100644 index 51f490c..0000000 --- a/reports/balsheet/20231217/balsheet.html +++ /dev/null @@ -1,259 +0,0 @@ - - - - - - - - - - - -
- -
-

Assets

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AccountEUROther
Assets
Assets:Benefits
Assets:Benefits:Edenred
Assets:Benefits:Edenred:TarjetaTransport40
Assets:Benefits:Edenred:TicketsRestaurant209
Assets:Debt
Assets:Debt:DeutesPerCobrar
Assets:Invest
Assets:Invest:R4
Assets:Invest:R4:Amundi
Assets:Invest:Fund:Amundi:MSCIWRLD20436.50810
Assets:Invest:Fund:Amundi:SUSTINC709.77780
Assets:Invest:R4:BNP
Assets:Invest:Fund:BNP:DISTECH788.20245 USD
Assets:Invest:R4:Fidelity
Assets:Invest:Fund:Fidelity:GLTECH14143.9382
Assets:Invest:Stock:MSFT1367.2 USD
Assets:Invest:Stock:PLTR160.250 USD
Assets:Invest:R4:Vanguard
Assets:Invest:Fund:Vanguard:EMMK2664.81727
Assets:Liquid
Assets:Liquid:Caixabank
Assets:Liquid:Caixabank:Corrent18903.80
Assets:Liquid:Estalvi:Caixabank12666.49
Assets:Liquid:R4
Assets:Liquid:R4:EUR44.04
Assets:PersonalProperty
Assets:PersonalProperty:AltresPropietats
Assets:PersonalProperty:Cotxe10000
Assets:PersonalProperty:JoiesArtCollecionables1250
Assets:PersonalProperty:MetallsPreciosos
Assets:PersonalProperty:VivendaPrincipal
81068.371372315.65245 USD
- -
- -
-
- -
-

Liabilities

- - - - - - - - - - - - - - - - - - -
AccountEUROther
Liabilities
- -
-
-
-
-

Equity

- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AccountEUROther
Equity
Equity:Opening-Balances-80819.37
Equity:Opening-Balances:USD-2315.652 USD
-80819.37-2315.652 USD
- -
- -
- - - -