diff --git a/banking_breakdown/__main__.py b/banking_breakdown/__main__.py index fbc4ed7..8f3af0c 100644 --- a/banking_breakdown/__main__.py +++ b/banking_breakdown/__main__.py @@ -1,48 +1,9 @@ from banking_breakdown import document_builder -import pandas as pd -from banking_breakdown import types -import numpy as np - - -def _generate_dummy_data() -> types.ReportData: - categories = ["A", "B", "C", "D", "E", "F", "G"] - values = np.array([10, 12, 53, 12, 90, 23, 32]) - values = values / values.sum() * 100 - values = np.round(values, decimals=1) - values[-1] += 100 - np.sum(values) - - category_overview_df = pd.DataFrame( - {"category": categories, "value": values}) - - t = ["2023-01-01", - "2023-02-01", - "2023-03-01", - "2023-04-01", - "2023-05-01", - "2023-06-01", - "2023-07-01", - "2023-08-01", - "2023-09-01", - "2023-10-01", - "2023-11-01", - "2023-12-01"] - - net_income = 200 * np.random.normal(size=len(t)) + 100 - net_income_df = pd.DataFrame({"t": t, "value": net_income}) - - total_value = np.cumsum(net_income) - - total_value_df = pd.DataFrame({"t": t, "value": total_value}) - - report_data = types.ReportData(category_overview=category_overview_df, - net_income=net_income_df, - total_value=total_value_df) - - return report_data +from banking_breakdown import statement_parser def main(): - report_data = _generate_dummy_data() + report_data = statement_parser.parse_statement("res/banking_statement_2023.csv") document_builder.build_document(report_data) diff --git a/banking_breakdown/document_builder.py b/banking_breakdown/document_builder.py index f223266..fe460a5 100644 --- a/banking_breakdown/document_builder.py +++ b/banking_breakdown/document_builder.py @@ -15,6 +15,8 @@ def _serialize_report_data(report_data: types.ReportData): report_data.category_overview.to_csv('build/category_overview.csv', index=False) report_data.total_value.to_csv('build/total_value.csv', index=False) + report_data.detailed_balance.to_csv('build/detailed_balance.csv', + index=False) def _compile_document(): diff --git a/banking_breakdown/statement_parser.py b/banking_breakdown/statement_parser.py new file mode 100644 index 0000000..175c5da --- /dev/null +++ b/banking_breakdown/statement_parser.py @@ -0,0 +1,80 @@ +import typing +import pandas as pd +from banking_breakdown import types +import json +import re +import numpy as np + + +def _read_regex_dict(regex_file: str = "res/category_regexes.json"): + with open(regex_file, 'r') as f: + return json.load(f) + + +def _tag_with_category(df: pd.DataFrame) -> pd.DataFrame: + regex_dict = _read_regex_dict() + + return df + + +def _compute_total_balance(df: pd.DataFrame) -> pd.DataFrame: + stripped_df = pd.DataFrame( + {'t': df["Buchungstag"], 'value': df["Saldo nach Buchung"]}) + + stripped_df.index = stripped_df['t'] + gb = stripped_df.groupby(pd.Grouper(freq='M')) + + result = gb.tail(1)['value'].reset_index() + #result['t'] = result['t'].apply(lambda dt: dt.replace(day=1)) + + return result + + +def _compute_net_income(df: pd.DataFrame) -> pd.DataFrame: + stripped_df = pd.DataFrame({'t': df["Buchungstag"], 'value': df["Betrag"]}) + + result = stripped_df.resample(rule='M', on="t").sum().reset_index() + #result['t'] = result['t'].apply(lambda dt: dt.replace(day=1)) + + return result + + +def _compute_category_overview(df: pd.DataFrame) -> pd.DataFrame: + categories = ["A", "B", "C", "D", "E", "F", "G"] + values = np.array([10, 12, 53, 12, 90, 23, 32]) + values = values / values.sum() * 100 + values = np.round(values, decimals=1) + values[-1] += 100 - np.sum(values) + + category_overview_df = pd.DataFrame( + {"category": categories, "value": values}) + + return category_overview_df + + +def _compute_detailed_balance(df: pd.DataFrame) -> pd.DataFrame: + return pd.DataFrame({'t': df["Buchungstag"], + 'value': df["Saldo nach Buchung"]}) + + +def parse_statement(filename: str) -> types.ReportData: + df = pd.read_csv(filename, delimiter=';', decimal=",") + df["Buchungstag"] = pd.to_datetime(df["Buchungstag"], format='%d.%m.%Y') + + category_overview_df = _compute_category_overview(df) + total_balance_df = _compute_total_balance(df) + net_income_df = _compute_net_income(df) + detailed_balance_df = _compute_detailed_balance(df) + + return types.ReportData(category_overview_df, + net_income_df, + total_balance_df, + detailed_balance_df) + + +def main(): + report_data = parse_statement("../res/banking_statement_2023.csv") + + +if __name__ == "__main__": + main() diff --git a/banking_breakdown/types.py b/banking_breakdown/types.py index c314506..1ded89a 100644 --- a/banking_breakdown/types.py +++ b/banking_breakdown/types.py @@ -7,3 +7,4 @@ class ReportData: category_overview: pd.DataFrame net_income: pd.DataFrame total_value: pd.DataFrame + detailed_balance: pd.DataFrame diff --git a/res/report.tex b/res/report.tex index 9a040e7..2d286e2 100644 --- a/res/report.tex +++ b/res/report.tex @@ -153,12 +153,18 @@ anchor=near xticklabel, }, grid, + enlarge x limits=0.03, ] - % Dummy plot to set x axis labels + % Dummy plot to set x axis ticks \addplot[draw=none] table[col sep=comma, x=t, y=value] {net_income.csv}; + % Dummy plot to set x axis scale + \addplot[draw=none] + table[col sep=comma, x=t, y=value] + {detailed_balance.csv}; + \addplot[ybar, color=scol2, fill=scol2, line width=1pt] table[col sep=comma, x=t, y=value, discard if lt={value}{0}] {net_income.csv}; @@ -176,20 +182,28 @@ date coordinates in=x, width=\textwidth, height=0.375\textwidth, - area style, ylabel={Total balance in €}, y label style={at={(-0.1,0.5)},anchor=south}, xticklabel=\month.\shortyear{\year}, xtick=data, + enlarge x limits=0.03, xticklabel style={ rotate=60, anchor=near xticklabel, }, grid, ] - \addplot+[mark=none, color=scol1, line width=1pt] + % Dummy plot to set x axis ticks + \addplot[draw=none] table[col sep=comma, x=t, y=value] - {total_value.csv} \closedcycle; + {total_value.csv}; + + \addplot[scol3, mark=none, line width=1pt] + table[col sep=comma, x=t, y=value] + {detailed_balance.csv}; + \addplot[scol1, mark=none, line width=1pt] + table[col sep=comma, x=t, y=value] + {total_value.csv}; \end{axis} \end{tikzpicture} \end{subfigure} @@ -197,5 +211,6 @@ \caption{Development of account balance over time} \end{figure} + \end{document}