upgrade to beancount v3
This commit is contained in:
@@ -1,12 +1,11 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from beancount import loader
|
from beancount import loader
|
||||||
from beancount.query import query
|
from beanquery import query
|
||||||
from beancount.parser import printer
|
from beancount.parser import printer
|
||||||
import argparse
|
import argparse
|
||||||
from tabulate import tabulate
|
from tabulate import tabulate
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from beancount.core.amount import Amount, add, sub, mul
|
from beancount.core.amount import Amount, add, sub
|
||||||
from math import floor
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
|
||||||
@@ -72,7 +71,7 @@ def get_debt_to_assets_ratio(balances, max):
|
|||||||
|
|
||||||
def get_emergency_fund_ratio(balances, expenses, low, mid):
|
def get_emergency_fund_ratio(balances, expenses, low, mid):
|
||||||
liquid = 0
|
liquid = 0
|
||||||
living_expenses = expenses[0].position.get_only_position(
|
living_expenses = expenses[0][0].get_only_position(
|
||||||
).units.number / 12
|
).units.number / 12
|
||||||
for account, balance in balances.items():
|
for account, balance in balances.items():
|
||||||
if account.startswith("Assets:Liquid"):
|
if account.startswith("Assets:Liquid"):
|
||||||
@@ -129,7 +128,7 @@ def get_solvency_ratio(balances, min):
|
|||||||
|
|
||||||
|
|
||||||
def get_interest_coverage_ratio(net_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
|
living_expenses = expenses[0][0].get_only_position().units.number
|
||||||
interest = debt_payments.number + mortgage_payments.number
|
interest = debt_payments.number + mortgage_payments.number
|
||||||
interest = interest if interest > 0 else 1
|
interest = interest if interest > 0 else 1
|
||||||
result = round((net_monthly_income - living_expenses) / interest, 2)
|
result = round((net_monthly_income - living_expenses) / interest, 2)
|
||||||
@@ -265,7 +264,7 @@ def get_balances(entries, options, date):
|
|||||||
entries, options, balance_query)
|
entries, options, balance_query)
|
||||||
balances = {}
|
balances = {}
|
||||||
for row in rrows:
|
for row in rrows:
|
||||||
balances[row.account] = row.position
|
balances[row[0]] = row[1]
|
||||||
return balances
|
return balances
|
||||||
|
|
||||||
|
|
||||||
@@ -284,7 +283,7 @@ def get_income(entries, options, date):
|
|||||||
end_date} WHERE account ~ '^(Income:Work|Income:Savings|Income:Invest)' AND date >= {start_date}"
|
end_date} WHERE account ~ '^(Income:Work|Income:Savings|Income:Invest)' AND date >= {start_date}"
|
||||||
rtypes, rrows = query.run_query(
|
rtypes, rrows = query.run_query(
|
||||||
entries, options, income_query)
|
entries, options, income_query)
|
||||||
net_monthly_income = rrows[0].position.get_only_position(
|
net_monthly_income = rrows[0][0].get_only_position(
|
||||||
).units.number * -1
|
).units.number * -1
|
||||||
|
|
||||||
start_date, end_date = get_last_year_timestamps(date)
|
start_date, end_date = get_last_year_timestamps(date)
|
||||||
@@ -292,7 +291,7 @@ def get_income(entries, options, date):
|
|||||||
end_date} WHERE account ~ '^(Income:Work|Income:Savings|Income:Invest)' AND date >= {start_date}"
|
end_date} WHERE account ~ '^(Income:Work|Income:Savings|Income:Invest)' AND date >= {start_date}"
|
||||||
rtypes, rrows = query.run_query(
|
rtypes, rrows = query.run_query(
|
||||||
entries, options, income_query)
|
entries, options, income_query)
|
||||||
net_yearly_income = rrows[0].position.get_only_position(
|
net_yearly_income = rrows[0][0].get_only_position(
|
||||||
).units.number * -1
|
).units.number * -1
|
||||||
return net_monthly_income, net_yearly_income
|
return net_monthly_income, net_yearly_income
|
||||||
|
|
||||||
@@ -308,7 +307,7 @@ def get_debt_payments(entries, options, date):
|
|||||||
entries, options, debt_payments_query)
|
entries, options, debt_payments_query)
|
||||||
rtypes, rrows_mortgage = query.run_query(
|
rtypes, rrows_mortgage = query.run_query(
|
||||||
entries, options, mortgage_payments_query)
|
entries, options, mortgage_payments_query)
|
||||||
debt_payments = rrows_debt[0].position.get_only_position().units if len(
|
debt_payments = rrows_debt[0][0].get_only_position().units if len(
|
||||||
rrows_debt) > 0 else Amount(Decimal(0), "EUR")
|
rrows_debt) > 0 else Amount(Decimal(0), "EUR")
|
||||||
mortgage_payments = rrows_mortgage[0].position.get_only_position(
|
mortgage_payments = rrows_mortgage[0].position.get_only_position(
|
||||||
).units if len(rrows_mortgage) > 0 else Amount(Decimal(0), "EUR")
|
).units if len(rrows_mortgage) > 0 else Amount(Decimal(0), "EUR")
|
||||||
@@ -321,13 +320,13 @@ def get_savings(entries, options, date):
|
|||||||
end_date} WHERE account ~ '^Assets:Invest:' AND date >= {start_date}"
|
end_date} WHERE account ~ '^Assets:Invest:' AND date >= {start_date}"
|
||||||
rtypes, rrows = query.run_query(
|
rtypes, rrows = query.run_query(
|
||||||
entries, options, investments_query)
|
entries, options, investments_query)
|
||||||
result = rrows[0].position.get_only_position().units if len(
|
result = rrows[0][0].get_only_position().units if len(
|
||||||
rrows) > 0 else Amount(Decimal(0), "EUR")
|
rrows) > 0 else Amount(Decimal(0), "EUR")
|
||||||
liabilities_query = f"SELECT convert(sum(position), \"EUR\") as position FROM date <= {
|
liabilities_query = f"SELECT convert(sum(position), \"EUR\") as position FROM date <= {
|
||||||
end_date} WHERE account ~ '^Liabilities:Credit:Renta4:' AND date >= {start_date}"
|
end_date} WHERE account ~ '^Liabilities:Credit:Renta4:' AND date >= {start_date}"
|
||||||
rtypes, rrows = query.run_query(
|
rtypes, rrows = query.run_query(
|
||||||
entries, options, liabilities_query)
|
entries, options, liabilities_query)
|
||||||
liabilities = rrows[0].position.get_only_position().units if len(
|
liabilities = rrows[0][0].get_only_position().units if len(
|
||||||
rrows) > 0 else Amount(Decimal(0), "EUR")
|
rrows) > 0 else Amount(Decimal(0), "EUR")
|
||||||
result = add(result, liabilities)
|
result = add(result, liabilities)
|
||||||
return result
|
return result
|
||||||
@@ -345,7 +344,7 @@ def get_assets_pignorats(entries, options, date):
|
|||||||
date}) as price"
|
date}) as price"
|
||||||
rtypes, rrows = query.run_query(
|
rtypes, rrows = query.run_query(
|
||||||
entries, options, pignorat_query)
|
entries, options, pignorat_query)
|
||||||
result = result + rrows[0].price * assets_pignorats[curr]
|
result = result + rrows[0][0] * assets_pignorats[curr]
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from beancount import loader
|
from beancount import loader
|
||||||
from beancount.query import query
|
from beanquery import query
|
||||||
from beancount.core.data import Custom
|
from beancount.core.data import Custom
|
||||||
from beancount.core.amount import Amount, add, sub
|
from beancount.core.amount import Amount, add, sub
|
||||||
from beancount.parser import printer
|
from beancount.parser import printer
|
||||||
@@ -61,7 +61,7 @@ WHERE account ~ \"Equity:(LloguerMiquel|FacturesUtilitatsMiquel)\""""
|
|||||||
entries, options, equity_query)
|
entries, options, equity_query)
|
||||||
equity = {}
|
equity = {}
|
||||||
for row in rrows:
|
for row in rrows:
|
||||||
equity[row.account] = row.sum_position
|
equity[row[0]] = row[1]
|
||||||
return equity
|
return equity
|
||||||
|
|
||||||
|
|
||||||
@@ -77,7 +77,7 @@ WHERE account ~ \"Expenses\" OR account ~ \"Liabilities\""""
|
|||||||
entries, options, expenses_query)
|
entries, options, expenses_query)
|
||||||
expenses = {}
|
expenses = {}
|
||||||
for row in rrows:
|
for row in rrows:
|
||||||
expenses[row.account] = row.sum_position
|
expenses[row[0]] = row[1]
|
||||||
return expenses
|
return expenses
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from beancount import loader
|
from beancount import loader
|
||||||
from beancount.query import query
|
from beanquery import query
|
||||||
from beancount.parser import printer
|
from beancount.parser import printer
|
||||||
import argparse
|
import argparse
|
||||||
from tabulate import tabulate
|
from tabulate import tabulate
|
||||||
@@ -9,6 +9,7 @@ from beancount.core.amount import Amount, add, sub, mul
|
|||||||
from datetime import date
|
from datetime import date
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
|
|
||||||
|
|
||||||
class bcolors:
|
class bcolors:
|
||||||
HEADER = '\033[95m'
|
HEADER = '\033[95m'
|
||||||
OKBLUE = '\033[94m'
|
OKBLUE = '\033[94m'
|
||||||
@@ -20,156 +21,189 @@ class bcolors:
|
|||||||
BOLD = '\033[1m'
|
BOLD = '\033[1m'
|
||||||
UNDERLINE = '\033[4m'
|
UNDERLINE = '\033[4m'
|
||||||
|
|
||||||
|
|
||||||
def draw_line():
|
def draw_line():
|
||||||
print('─' * 30)
|
print('─' * 30)
|
||||||
|
|
||||||
|
|
||||||
def get_income_val(obj, key):
|
def get_income_val(obj, key):
|
||||||
if key in obj:
|
if key in obj:
|
||||||
amount = obj[key].get_only_position().units
|
amount = obj[key].get_only_position().units
|
||||||
amount = mul(amount, Decimal(-1.0))
|
amount = mul(amount, Decimal(-1.0))
|
||||||
return amount.to_string()
|
return amount.to_string()
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def get_expense_val(obj, key):
|
def get_expense_val(obj, key):
|
||||||
if key in obj:
|
if key in obj:
|
||||||
amount = obj[key].get_only_position().units
|
amount = obj[key].get_only_position().units
|
||||||
return amount.to_string()
|
return amount.to_string()
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def print_expenses_table(expenses):
|
def print_expenses_table(expenses):
|
||||||
table = []
|
table = []
|
||||||
for key, expense in expenses.items():
|
for key, expense in expenses.items():
|
||||||
parts = key.split(":", 1)
|
parts = key.split(":", 1)
|
||||||
table.append([parts[1], get_expense_val(expenses, key)])
|
table.append([parts[1], get_expense_val(expenses, key)])
|
||||||
print(tabulate(table))
|
print(tabulate(table))
|
||||||
|
|
||||||
|
|
||||||
def get_total_inflows(income):
|
def get_total_inflows(income):
|
||||||
sum = 0
|
sum = 0
|
||||||
for account, balance in income.items():
|
for account, balance in income.items():
|
||||||
sum = balance if sum == 0 else sum + balance
|
sum = balance if sum == 0 else sum + balance
|
||||||
if sum != 0 and sum.get_only_position() != None:
|
if sum != 0 and sum.get_only_position() != None:
|
||||||
result = sum.get_only_position().units
|
result = sum.get_only_position().units
|
||||||
return Amount(Decimal(round(result.number, 2) * Decimal(-1.0)), result.currency)
|
return Amount(Decimal(round(result.number, 2) * Decimal(-1.0)), result.currency)
|
||||||
else:
|
else:
|
||||||
return Amount(Decimal(0), "EUR")
|
return Amount(Decimal(0), "EUR")
|
||||||
|
|
||||||
|
|
||||||
def get_total_outflows(expenses, total_investments):
|
def get_total_outflows(expenses, total_investments):
|
||||||
sum = 0
|
sum = 0
|
||||||
for account, balance in expenses.items():
|
for account, balance in expenses.items():
|
||||||
sum = balance if sum == 0 else sum + balance
|
sum = balance if sum == 0 else sum + balance
|
||||||
if sum != 0 and sum.get_only_position() != None:
|
if sum != 0 and sum.get_only_position() != None:
|
||||||
result = sum.get_only_position().units
|
result = sum.get_only_position().units
|
||||||
return add(Amount(Decimal(round(result.number, 2)), result.currency), total_investments)
|
return add(Amount(Decimal(round(result.number, 2)), result.currency), total_investments)
|
||||||
else:
|
else:
|
||||||
return total_investments
|
return total_investments
|
||||||
|
|
||||||
|
|
||||||
def get_total_investments(investments):
|
def get_total_investments(investments):
|
||||||
sum = Amount(Decimal(0), "EUR")
|
sum = Amount(Decimal(0), "EUR")
|
||||||
for inv in investments:
|
for inv in investments:
|
||||||
sum = inv.cost_position if sum == Amount(Decimal(0), "EUR") else add(sum, inv.cost_position)
|
sum = inv.cost_position if sum == Amount(
|
||||||
if sum != 0 and sum != None:
|
Decimal(0), "EUR") else add(sum, inv.cost_position)
|
||||||
return Amount(Decimal(round(sum.number, 2)), sum.currency)
|
if sum != 0 and sum != None:
|
||||||
else:
|
return Amount(Decimal(round(sum.number, 2)), sum.currency)
|
||||||
return Amount(Decimal(0), "EUR")
|
else:
|
||||||
|
return Amount(Decimal(0), "EUR")
|
||||||
|
|
||||||
|
|
||||||
def print_report(start_date, period, income, expenses, investments):
|
def print_report(start_date, period, income, expenses, investments):
|
||||||
print(f"{bcolors.BOLD}Cash Flow Statement (period={period}, start_date={start_date}){bcolors.ENDC}")
|
print(f"{bcolors.BOLD}Cash Flow Statement (period={
|
||||||
draw_line()
|
period}, start_date={start_date}){bcolors.ENDC}")
|
||||||
print(f"{bcolors.BOLD}Inflows{bcolors.ENDC}")
|
draw_line()
|
||||||
print(f"\t{bcolors.BOLD}Income{bcolors.ENDC}")
|
print(f"{bcolors.BOLD}Inflows{bcolors.ENDC}")
|
||||||
print(tabulate([
|
print(f"\t{bcolors.BOLD}Income{bcolors.ENDC}")
|
||||||
["Salari", get_income_val(income,"Income:Work:Zurich:Salari")],
|
print(tabulate([
|
||||||
["Tickets Restaurant", get_income_val(income,"Income:Work:Zurich:TicketsRestaurant")],
|
["Salari", get_income_val(income, "Income:Work:Zurich:Salari")],
|
||||||
["Targeta Transport", get_income_val(income,"Income:Work:Zurich:TargetaTransport")],
|
["Tickets Restaurant", get_income_val(
|
||||||
["Pla pensions Empleats Zurich", get_income_val(income,"Income:Work:Zurich:DZP")],
|
income, "Income:Work:Zurich:TicketsRestaurant")],
|
||||||
["Seguro Mèdic", get_income_val(income,"Income:Work:Zurich:SeguroMedic")],
|
["Targeta Transport", get_income_val(
|
||||||
["Gimnàs", get_income_val(income,"Income:Work:Zurich:Gimnas")]
|
income, "Income:Work:Zurich:TargetaTransport")],
|
||||||
]))
|
["Pla pensions Empleats Zurich", get_income_val(
|
||||||
print(f"\t{bcolors.BOLD}Income from Investment{bcolors.ENDC}")
|
income, "Income:Work:Zurich:DZP")],
|
||||||
print(tabulate([
|
["Seguro Mèdic", get_income_val(
|
||||||
["Capital Gains", get_income_val(income,"Income:Invest:R4:CapitalGains")],
|
income, "Income:Work:Zurich:SeguroMedic")],
|
||||||
["Untaxable Capital Gains", get_income_val(income,"Income:Invest:R4:CapitalGains:Untaxable")],
|
["Gimnàs", get_income_val(income, "Income:Work:Zurich:Gimnas")]
|
||||||
["Dividends", get_income_val(income,"Income:Invest:R4:Dividends")],
|
]))
|
||||||
["Rentabilitat Estalvis", get_income_val(income,"Income:Savings:Caixabank:RentabilitatEstalvis")]
|
print(f"\t{bcolors.BOLD}Income from Investment{bcolors.ENDC}")
|
||||||
]))
|
print(tabulate([
|
||||||
print(f"\t{bcolors.BOLD}Other Inflows{bcolors.ENDC}")
|
["Capital Gains", get_income_val(
|
||||||
print(tabulate([
|
income, "Income:Invest:R4:CapitalGains")],
|
||||||
["Transferències", get_income_val(income,"Income:Other:Caixabank:Transferencia")],
|
["Untaxable Capital Gains", get_income_val(
|
||||||
["Bizum", get_income_val(income,"Income:Other:Caixabank:Bizum")],
|
income, "Income:Invest:R4:CapitalGains:Untaxable")],
|
||||||
["Devolucions", get_income_val(income,"Income:Other:Devolucions")]
|
["Dividends", get_income_val(income, "Income:Invest:R4:Dividends")],
|
||||||
]))
|
["Rentabilitat Estalvis", get_income_val(
|
||||||
print(tabulate([
|
income, "Income:Savings:Caixabank:RentabilitatEstalvis")]
|
||||||
["Total Inflows", f"{bcolors.BOLD}{get_total_inflows(income).to_string()}{bcolors.ENDC}"]
|
]))
|
||||||
]))
|
print(f"\t{bcolors.BOLD}Other Inflows{bcolors.ENDC}")
|
||||||
draw_line()
|
print(tabulate([
|
||||||
print(f"{bcolors.BOLD}Outflows{bcolors.ENDC}")
|
["Transferències", get_income_val(
|
||||||
print_expenses_table(expenses)
|
income, "Income:Other:Caixabank:Transferencia")],
|
||||||
print(f"{bcolors.BOLD}Outflows from Investment{bcolors.ENDC}")
|
["Bizum", get_income_val(income, "Income:Other:Caixabank:Bizum")],
|
||||||
total_investments = get_total_investments(investments)
|
["Devolucions", get_income_val(income, "Income:Other:Devolucions")]
|
||||||
print(tabulate([
|
]))
|
||||||
["Compra de fons i accions", total_investments.to_string()]
|
print(tabulate([
|
||||||
]))
|
["Total Inflows", f"{bcolors.BOLD}{get_total_inflows(income).to_string()}{
|
||||||
print(tabulate([
|
bcolors.ENDC}"]
|
||||||
["Total Outflows", f"{bcolors.BOLD}{get_total_outflows(expenses, total_investments).to_string()}{bcolors.ENDC}"]
|
]))
|
||||||
]))
|
draw_line()
|
||||||
draw_line()
|
print(f"{bcolors.BOLD}Outflows{bcolors.ENDC}")
|
||||||
net_cash_flow = sub(get_total_inflows(income), get_total_outflows(expenses, total_investments))
|
print_expenses_table(expenses)
|
||||||
print(tabulate([
|
print(f"{bcolors.BOLD}Outflows from Investment{bcolors.ENDC}")
|
||||||
["NET CASH FLOW", f"{bcolors.BOLD}{bcolors.OKGREEN if net_cash_flow.number >= 0 else bcolors.FAIL}{net_cash_flow.to_string()}{bcolors.ENDC}"]
|
total_investments = get_total_investments(investments)
|
||||||
]))
|
print(tabulate([
|
||||||
|
["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, 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}"]
|
||||||
|
]))
|
||||||
|
|
||||||
|
|
||||||
def get_income(entries, options, period, start_date):
|
def get_income(entries, options, period, start_date):
|
||||||
period_delta = relativedelta(months=1) if period == "monthly" else relativedelta(years=1)
|
period_delta = relativedelta(
|
||||||
end_date = date.fromisoformat(start_date) + period_delta
|
months=1) if period == "monthly" else relativedelta(years=1)
|
||||||
income_query = f"SELECT account, convert(sum(position), \"EUR\") as sum_position FROM OPEN ON {start_date} CLOSE ON {end_date.isoformat()} WHERE account ~ \"Income\""
|
end_date = date.fromisoformat(start_date) + period_delta
|
||||||
rtypes, rrows = query.run_query(
|
income_query = f"SELECT account, convert(sum(position), \"EUR\") as sum_position FROM OPEN ON {
|
||||||
entries, options, income_query)
|
start_date} CLOSE ON {end_date.isoformat()} WHERE account ~ \"Income\""
|
||||||
income = {}
|
rtypes, rrows = query.run_query(
|
||||||
for row in rrows:
|
entries, options, income_query)
|
||||||
income[row.account] = row.sum_position
|
income = {}
|
||||||
return income
|
for row in rrows:
|
||||||
|
income[row[0]] = row[1]
|
||||||
|
return income
|
||||||
|
|
||||||
|
|
||||||
def get_expenses(entries, options, period, start_date):
|
def get_expenses(entries, options, period, start_date):
|
||||||
period_delta = relativedelta(months=1) if period == "monthly" else relativedelta(years=1)
|
period_delta = relativedelta(
|
||||||
end_date = date.fromisoformat(start_date) + period_delta
|
months=1) if period == "monthly" else relativedelta(years=1)
|
||||||
expenses_query = f"SELECT account, convert(sum(position), \"EUR\") as sum_position FROM OPEN ON {start_date} CLOSE ON {end_date.isoformat()} WHERE account ~ \"Expenses\""
|
end_date = date.fromisoformat(start_date) + period_delta
|
||||||
rtypes, rrows = query.run_query(
|
expenses_query = f"SELECT account, convert(sum(position), \"EUR\") as sum_position FROM OPEN ON {
|
||||||
entries, options, expenses_query)
|
start_date} CLOSE ON {end_date.isoformat()} WHERE account ~ \"Expenses\""
|
||||||
expenses = {}
|
rtypes, rrows = query.run_query(
|
||||||
for row in rrows:
|
entries, options, expenses_query)
|
||||||
expenses[row.account] = row.sum_position
|
expenses = {}
|
||||||
return expenses
|
for row in rrows:
|
||||||
|
expenses[row[0]] = row[1]
|
||||||
|
return expenses
|
||||||
|
|
||||||
|
|
||||||
def get_investments(entries, options, period, start_date):
|
def get_investments(entries, options, period, start_date):
|
||||||
period_delta = relativedelta(months=1) if period == "monthly" else relativedelta(years=1)
|
period_delta = relativedelta(
|
||||||
end_date = date.fromisoformat(start_date) + period_delta
|
months=1) if period == "monthly" else relativedelta(years=1)
|
||||||
expenses_query = f"SELECT account, convert(cost(position), \"EUR\") as cost_position, currency, date WHERE account ~ \"Assets:Invest:R4:\" AND NOT currency ~ '^(EUR|USD)' AND date >= {start_date} AND date < {end_date.isoformat()}"
|
end_date = date.fromisoformat(start_date) + period_delta
|
||||||
rtypes, rrows = query.run_query(
|
expenses_query = f"SELECT account, convert(cost(position), \"EUR\") as cost_position, currency, date WHERE account ~ \"Assets:Invest:R4:\" AND NOT currency ~ '^(EUR|USD)' AND date >= {
|
||||||
entries, options, expenses_query)
|
start_date} AND date < {end_date.isoformat()}"
|
||||||
return rrows
|
rtypes, rrows = query.run_query(
|
||||||
|
entries, options, expenses_query)
|
||||||
|
return rrows
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description='Generate cash flow report')
|
parser = argparse.ArgumentParser(description='Generate cash flow report')
|
||||||
parser.add_argument('start_date', metavar='start_date', type=str, nargs=1,
|
parser.add_argument('start_date', metavar='start_date', type=str, nargs=1,
|
||||||
help='Start date (end date will be one month after if monthly report or one year after if yearly report)')
|
help='Start date (end date will be one month after if monthly report or one year after if yearly report)')
|
||||||
parser.add_argument('-p', metavar='period', type=str, choices=["monthly", "yearly"], default="monthly", required=False,
|
parser.add_argument('-p', metavar='period', type=str, choices=["monthly", "yearly"], default="monthly", required=False,
|
||||||
help='Period (monthly or yearly)')
|
help='Period (monthly or yearly)')
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
start_date = args.start_date[0]
|
start_date = args.start_date[0]
|
||||||
period = args.p
|
period = args.p
|
||||||
|
|
||||||
filename = "ledger/main.beancount"
|
filename = "ledger/main.beancount"
|
||||||
entries, errors, options = loader.load_file(filename)
|
entries, errors, options = loader.load_file(filename)
|
||||||
|
|
||||||
if errors:
|
if errors:
|
||||||
printer.print_errors(errors)
|
printer.print_errors(errors)
|
||||||
|
|
||||||
income = get_income(entries, options, period, start_date)
|
income = get_income(entries, options, period, start_date)
|
||||||
expenses = get_expenses(entries, options, period, start_date)
|
expenses = get_expenses(entries, options, period, start_date)
|
||||||
investments = get_investments(entries, options, period, start_date)
|
investments = get_investments(entries, options, period, start_date)
|
||||||
print_report(start_date, period, income, expenses, investments)
|
print_report(start_date, period, income, expenses, investments)
|
||||||
|
|
||||||
main()
|
|
||||||
|
main()
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ readme = "README.md"
|
|||||||
requires-python = ">=3.13"
|
requires-python = ">=3.13"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"babel==2.13.1",
|
"babel==2.13.1",
|
||||||
"beancount==2.3.6",
|
|
||||||
"beautifulsoup4==4.12.3",
|
"beautifulsoup4==4.12.3",
|
||||||
"blinker==1.7.0",
|
"blinker==1.7.0",
|
||||||
"bottle==0.12.25",
|
"bottle==0.12.25",
|
||||||
|
|||||||
Reference in New Issue
Block a user