21 desembre 2025
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user