diff --git a/.gitignore b/.gitignore
index bfd854c..f08a12f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,4 @@
venv/
-.DS_Store
\ No newline at end of file
+env/
+.DS_Store
+**/__pycache__
\ No newline at end of file
diff --git a/commands/balance-sheet b/commands/balance-sheet
index 7410ab3..7a31fcf 100755
--- a/commands/balance-sheet
+++ b/commands/balance-sheet
@@ -1,2 +1,4 @@
#!/usr/bin/env bash
-echo "TO DO"
\ No newline at end of file
+now="$(date +'%Y%m%d')"
+mkdir -p reports/balsheet/$now
+bean-report ledger/main.beancount balsheet > reports/balsheet/$now/balsheet.html
\ No newline at end of file
diff --git a/commands/budget b/commands/budget
new file mode 100755
index 0000000..4a23991
--- /dev/null
+++ b/commands/budget
@@ -0,0 +1,100 @@
+#!/usr/bin/env python3
+from beancount import loader
+from beancount.query import query
+from beancount.core.data import Custom
+from beancount.core.amount import Amount, add, sub
+from beancount.parser import printer
+import argparse
+from datetime import date
+from dateutil.relativedelta import relativedelta
+from tabulate import tabulate
+from decimal import Decimal
+from functools import reduce
+
+class bcolors:
+ HEADER = '\033[95m'
+ OKBLUE = '\033[94m'
+ OKCYAN = '\033[96m'
+ OKGREEN = '\033[92m'
+ WARNING = '\033[93m'
+ FAIL = '\033[91m'
+ ENDC = '\033[0m'
+ BOLD = '\033[1m'
+ UNDERLINE = '\033[4m'
+
+def get_budget_entries(entries, period, start_date):
+ budgets = []
+ for entry in entries:
+ if isinstance(entry, Custom) and entry.values[1].value == period and entry.date <= date.fromisoformat(start_date):
+ budgets.append({ "date": entry.date, "account": entry.values[0].value, "period": entry.values[1].value, "budget": entry.values[2].value })
+ return budgets
+
+def get_expenses(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, sum(position) FROM OPEN ON {start_date} CLOSE ON {end_date.isoformat()} WHERE account ~ \"Expenses\""
+ rtypes, rrows = query.run_query(
+ entries, options, expenses_query)
+ expenses = {}
+ for row in rrows:
+ expenses[row.account] = row.sum_position
+ return expenses
+
+def build_budget(budget_entries, expenses):
+ result = []
+ for entry in budget_entries:
+ expense = Amount(Decimal(0), entry["budget"].currency)
+ expense_perc = 0
+ remaining = entry["budget"]
+ if entry["account"] in expenses:
+ expense = expenses[entry["account"]].get_only_position()
+ expense_perc = (expense.units.number / entry["budget"].number) * 100
+ remaining = sub(remaining, expense.units)
+ result.append({
+ "Account": entry["account"],
+ "Budget": entry["budget"].to_string(),
+ "Expense": expense,
+ "Expense (%)": "{}{:,.2f}%{}".format(bcolors.FAIL if expense_perc >= 100 else '', expense_perc, bcolors.ENDC),
+ "Remaining": remaining
+ })
+ return result
+
+def print_report(budget_report, period, start_date, budget_sum, expenses_sum):
+ print(f"Budget Report (period={period}, start_date={start_date})")
+ print(f"Budget: {budget_sum}")
+ print(f"{bcolors.FAIL if expenses_sum >= budget_sum else ''}Expenses: {expenses_sum}{bcolors.ENDC}")
+ headings = ['Account', 'Budget', 'Expense', '(%)', 'Remaining',]
+ print(tabulate(budget_report, headers="keys", numalign="right", floatfmt=".2f"))
+
+def main():
+ parser = argparse.ArgumentParser(description='Generate budget report')
+ 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)')
+ parser.add_argument('-p', metavar='period', type=str, choices=["monthly", "yearly"], default="monthly", required=False,
+ help='Period (monthly or yearly)')
+
+ args = parser.parse_args()
+ start_date = args.start_date[0]
+ period = args.p
+
+ filename = "ledger/main.beancount"
+ entries, errors, options = loader.load_file(filename)
+
+ if errors:
+ printer.print_errors(errors)
+
+ budget_entries = get_budget_entries(entries, period, start_date)
+ # TODO: Multiple currencies
+ budget_sum = reduce(lambda a, b: add(a, b["budget"]), budget_entries, Amount(Decimal(0), budget_entries[0]["budget"].currency))
+ expenses = get_expenses(entries, options, period, start_date)
+ filtered_expenses = {}
+ for entry in budget_entries:
+ if entry["account"] in expenses:
+ filtered_expenses[entry["account"]] = expenses[entry["account"]]
+ expenses_sum = reduce(lambda a, b: add(a, b.get_only_position().units),
+ filtered_expenses.values(),
+ Amount(Decimal(0), budget_entries[0]["budget"].currency))
+ budget_report = build_budget(budget_entries, expenses)
+ print_report(budget_report, period, start_date, budget_sum, expenses_sum)
+
+main()
\ No newline at end of file
diff --git a/commands/income-statement b/commands/income-statement
index 7410ab3..085782c 100755
--- a/commands/income-statement
+++ b/commands/income-statement
@@ -1,2 +1,4 @@
#!/usr/bin/env bash
-echo "TO DO"
\ No newline at end of file
+now="$(date +'%Y%m%d')"
+mkdir -p reports/income/$now
+bean-report ledger/main.beancount income > reports/income/$now/income.html
\ No newline at end of file
diff --git a/commands/net-worth b/commands/net-worth
new file mode 100755
index 0000000..176987a
--- /dev/null
+++ b/commands/net-worth
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+bean-report ledger/main.beancount networth
\ No newline at end of file
diff --git a/commands/objectives b/commands/objectives
new file mode 100644
index 0000000..e69de29
diff --git a/ledger/budget.md b/ledger/budget.md
new file mode 100644
index 0000000..dc7fdc1
--- /dev/null
+++ b/ledger/budget.md
@@ -0,0 +1,9 @@
+# Budget
+
+## Menjar fora
+4.5 x 5.45
+4.5 x 16.5
+4.5 x 50
+= 323.78
+- 209 (Targ. Restaurant)
+= 114.78
\ No newline at end of file
diff --git a/ledger/plugins/__pycache__/amortize_over.cpython-311.pyc b/ledger/plugins/__pycache__/amortize_over.cpython-311.pyc
deleted file mode 100644
index 79aff24..0000000
Binary files a/ledger/plugins/__pycache__/amortize_over.cpython-311.pyc and /dev/null differ
diff --git a/reports/balsheet/20231217/balsheet.html b/reports/balsheet/20231217/balsheet.html
new file mode 100644
index 0000000..5960612
--- /dev/null
+++ b/reports/balsheet/20231217/balsheet.html
@@ -0,0 +1,259 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Assets
+
+
+
+| Account |
+EUR |
+Other |
+
+
+
+| Assets |
+ |
+ |
+
+
+| Assets:Benefits |
+ |
+ |
+
+
+| Assets:Benefits:Edenred |
+ |
+ |
+
+
+| Assets:Benefits:Edenred:TarjetaTransport |
+40 |
+ |
+
+
+| Assets:Benefits:Edenred:TicketsRestaurant |
+209 |
+ |
+
+
+| Assets:Debt |
+ |
+ |
+
+
+| Assets:Debt:DeutesPerCobrar |
+ |
+ |
+
+
+| Assets:Invest |
+ |
+ |
+
+
+| Assets:Invest:R4 |
+ |
+ |
+
+
+| Assets:Invest:R4:Amundi |
+ |
+ |
+
+
+| Assets:Invest:R4:Amundi:MSCIWRLD |
+20436.50810 |
+ |
+
+
+| Assets:Invest:R4:Amundi:SUSTINC |
+709.77780 |
+ |
+
+
+| Assets:Invest:R4:BNP |
+ |
+ |
+
+
+| Assets:Invest:R4:BNP:DISTECH |
+ |
+788.20245 USD |
+
+
+| Assets:Invest:R4:Fidelity |
+ |
+ |
+
+
+| Assets:Invest:R4:Fidelity:GLTECH |
+14143.9382 |
+ |
+
+
+| Assets:Invest:R4:MSFT |
+ |
+1367.2 USD |
+
+
+| Assets:Invest:R4:PLTR |
+ |
+160.250 USD |
+
+
+| Assets:Invest:R4:Vanguard |
+ |
+ |
+
+
+| Assets:Invest:R4:Vanguard:EMMK |
+2664.81727 |
+ |
+
+
+| Assets:Liquid |
+ |
+ |
+
+
+| Assets:Liquid:Caixabank |
+ |
+ |
+
+
+| Assets:Liquid:Caixabank:Corrent |
+18903.80 |
+ |
+
+
+| Assets:Liquid:Caixabank:Estalvi |
+12666.49 |
+ |
+
+
+| Assets:Liquid:R4 |
+ |
+ |
+
+
+| Assets:Liquid:R4:EUR |
+44.04 |
+ |
+
+
+| Assets:PersonalProperty |
+ |
+ |
+
+
+| Assets:PersonalProperty:AltresPropietats |
+ |
+ |
+
+
+| Assets:PersonalProperty:Cotxe |
+10000 |
+ |
+
+
+| Assets:PersonalProperty:JoiesArtCollecionables |
+1250 |
+ |
+
+
+| Assets:PersonalProperty:MetallsPreciosos |
+ |
+ |
+
+
+| Assets:PersonalProperty:VivendaPrincipal |
+ |
+ |
+
+
+ |
+81068.37137 |
+2315.65245 USD |
+
+
+
+
+
+
+
+
+
+
Liabilities
+
+
+
+| Account |
+EUR |
+Other |
+
+
+
+| Liabilities |
+ |
+ |
+
+
+ |
+ |
+ |
+
+
+
+
+
+
+
+
Equity
+
+
+
+| Account |
+EUR |
+Other |
+
+
+
+| Equity |
+ |
+ |
+
+
+| Equity:Opening-Balances |
+-80819.37 |
+ |
+
+
+| Equity:Opening-Balances:USD |
+ |
+-2315.652 USD |
+
+
+ |
+-80819.37 |
+-2315.652 USD |
+
+
+
+
+
+
+
+
+
+
diff --git a/reports/income/2023/12.html b/reports/income/20231217/income.html
similarity index 100%
rename from reports/income/2023/12.html
rename to reports/income/20231217/income.html
diff --git a/requirements.txt b/requirements.txt
index 750fb45..973d349 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,6 +3,7 @@ beancount==2.3.6
beautifulsoup4==4.12.2
blinker==1.7.0
bottle==0.12.25
+budget-report==0.4
cachetools==5.3.2
certifi==2023.11.17
chardet==5.2.0
@@ -45,6 +46,7 @@ rsa==4.9
simplejson==3.19.2
six==1.16.0
soupsieve==2.5
+tabulate==0.9.0
uritemplate==4.1.1
urllib3==2.1.0
Werkzeug==3.0.1