PocketAccountant: custom ledger UI + deterministic agent (engine, ledger, retrieval, classifier)
c55ab5e verified | """Financial-health formulas — regime-agnostic, useful for any small business. | |
| These are the numbers a good accountant brings up unprompted: am I liquid, am I | |
| profitable, when do I break even, how long does my cash last. All deterministic. | |
| """ | |
| from __future__ import annotations | |
| from decimal import Decimal | |
| from .money import D, money | |
| from .result import CalcResult | |
| def _ratio(numerator: Decimal, denominator: Decimal) -> Decimal: | |
| if denominator == 0: | |
| return D(0) | |
| return numerator / denominator | |
| def current_ratio(current_assets, current_liabilities) -> CalcResult: | |
| """Liquidity: can short-term assets cover short-term debts? (>1 is healthy.)""" | |
| ca, cl = D(current_assets), D(current_liabilities) | |
| r = _ratio(ca, cl) | |
| notes = [] | |
| if cl == 0: | |
| notes.append("No current liabilities — ratio undefined, reported as 0.") | |
| elif r < 1: | |
| notes.append("Below 1.0 — short-term obligations exceed liquid assets.") | |
| return CalcResult( | |
| amount=r.quantize(Decimal("0.01")), | |
| label="Razón circulante (current ratio)", | |
| breakdown=[("Activo circulante", money(ca)), ("Pasivo circulante", money(cl))], | |
| notes=notes, | |
| ) | |
| def profit_margin(net_profit, revenue) -> CalcResult: | |
| """Net margin as a fraction of revenue.""" | |
| np_, rev = D(net_profit), D(revenue) | |
| r = _ratio(np_, rev) | |
| return CalcResult( | |
| amount=r.quantize(Decimal("0.0001")), | |
| label="Margen de utilidad neta", | |
| breakdown=[("Utilidad neta", money(np_)), ("Ingresos", money(rev))], | |
| notes=[f"≈ {(r * 100).quantize(Decimal('0.01'))}% of revenue is profit."], | |
| ) | |
| def break_even_units(fixed_costs, price_per_unit, variable_cost_per_unit) -> CalcResult: | |
| """Units to sell to cover all costs: FC / (price − variable cost).""" | |
| fc = D(fixed_costs) | |
| contribution = D(price_per_unit) - D(variable_cost_per_unit) | |
| if contribution <= 0: | |
| return CalcResult( | |
| amount=D(0), | |
| label="Punto de equilibrio (unidades)", | |
| breakdown=[ | |
| ("Costos fijos", money(fc)), | |
| ("Margen de contribución por unidad", money(contribution)), | |
| ], | |
| notes=["Contribution margin ≤ 0 — break-even impossible at this price."], | |
| ) | |
| units = fc / contribution | |
| return CalcResult( | |
| amount=units.quantize(Decimal("0.01")), | |
| label="Punto de equilibrio (unidades)", | |
| breakdown=[ | |
| ("Costos fijos", money(fc)), | |
| ("Margen de contribución por unidad", money(contribution)), | |
| ], | |
| ) | |
| def cash_runway_months(cash_on_hand, monthly_net_burn) -> CalcResult: | |
| """How many months the cash lasts at the current net burn rate.""" | |
| cash = D(cash_on_hand) | |
| burn = D(monthly_net_burn) | |
| if burn <= 0: | |
| return CalcResult( | |
| amount=D(0), | |
| label="Meses de pista (runway)", | |
| breakdown=[("Efectivo disponible", money(cash)), ("Quema neta mensual", money(burn))], | |
| notes=["Non-positive burn — cash-flow positive, runway effectively infinite."], | |
| ) | |
| months = cash / burn | |
| return CalcResult( | |
| amount=months.quantize(Decimal("0.1")), | |
| label="Meses de pista (runway)", | |
| breakdown=[("Efectivo disponible", money(cash)), ("Quema neta mensual", money(burn))], | |
| ) | |