"""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))], )