Source code for aoiro.cli
from datetime import datetime
from pathlib import Path
# from rich import print
import attrs
import cyclopts
import networkx as nx
import pandas as pd
from account_codes_jp import (
get_account_type_factory,
get_blue_return_accounts,
get_node_from_label,
)
from networkx.readwrite.text import generate_network_text
from rich import print
from ._ledger import (
generalledger_to_multiledger,
multiledger_to_ledger,
)
from ._multidimensional import multidimensional_ledger_to_ledger
from ._sheets import get_sheets
from .reader._expenses import ledger_from_expenses
from .reader._io import read_general_ledger
from .reader._sales import ledger_from_sales
app = cyclopts.App(name="aoiro")
[docs]
@app.default
def metrics(
path: Path, years: str | None = None, months: str | None = None, drop: bool = True
) -> int:
"""
Calculate metrics needed for tax declaration.
Parameters
----------
path : Path
The path to the directory containing CSV files.
years : str | None, optional
The year to calculate, by default None.
If None, the previous year would be used.
months : str | None, optional
The months to calculate, by default None.
drop : bool, optional
Whether to drop unused accounts, by default True.
"""
if years == "all":
years_ = None
elif years is None:
years_ = [datetime.now().year - 1]
else:
years_ = sorted({int(y) for y in years.split(",")})
months_ = list(range(1, 13))
if months is not None:
months_ = sorted({int(m) for m in months.split(",")})
def patch_G(G: nx.DiGraph) -> nx.DiGraph:
G.add_node(-1, label="為替差益")
G.add_node(-2, label="為替差損")
G.add_edge(next(n for n, d in G.nodes(data=True) if d["label"] == "売上"), -1)
G.add_edge(
next(n for n, d in G.nodes(data=True) if d["label"] == "経費追加"), -2
)
return G
G = get_blue_return_accounts(patch_G)
gledger_vec = (
list(ledger_from_sales(path, G))
+ list(ledger_from_expenses(path))
+ list(read_general_ledger(path))
)
gledger_vec = sorted(gledger_vec, key=lambda x: x.date)
f = get_account_type_factory(G)
def is_debit(x: str) -> bool:
v = getattr(f(x), "debit", None)
if v is None:
raise ValueError(f"Account {x} not recognized")
return v
gledger = multidimensional_ledger_to_ledger(gledger_vec, is_debit=is_debit)
multiledger = generalledger_to_multiledger(gledger, is_debit=is_debit)
ledger = multiledger_to_ledger(multiledger)
ledger_now = [
line
for line in ledger
if (years_ is None or line.date.year in years_) and line.date.month in months_
]
if len(ledger_now) == 0:
print(f"No ledger lines found for year {years}")
return 1
with pd.option_context("display.max_rows", None, "display.max_columns", None):
print(
pd.DataFrame([attrs.asdict(line) for line in ledger_now]) # type: ignore
.set_index("date")
.sort_index(axis=0)
)
gledger_now = [
line
for line in gledger
if (line.date.year in years_ if years_ is not None else True)
and line.date.month in months_
]
G = get_sheets(gledger_now, G, drop=drop)
G_print = G.copy()
for n, d in G_print.nodes(data=True):
G_print.nodes[n]["label"] = f"{d['label']}/{d['sum_natural'].get('', 0)}"
for line in generate_network_text(G_print, with_labels=True):
print(line)
# sales per month
print("Sales per month")
for year in years_ if years_ is not None else [datetime.now().year - 1]:
for month in months_:
G_month = get_sheets(
[
line
for line in gledger_now
if (line.date.year == year if year is not None else True)
and line.date.month == month
],
G,
drop=False,
)
sales_deeper_node = get_node_from_label(
G, "売上", lambda x: not G.nodes[x]["abstract"]
)
sales_deeper = G_month.nodes[sales_deeper_node]["sum_natural"].get("", 0)
print(f"{month}: {sales_deeper}")
return 0