File size: 2,192 Bytes
c55ab5e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
"""RESICO — Régimen Simplificado de Confianza (Mexico), personas físicas.

The simplest and (for most freelancers) cheapest regime. ISR is a flat rate on
*total monthly income* — no deductions enter the ISR calculation. The rate is
chosen by an income bracket (Art. 113-E LISR), and the whole income is taxed at
that single rate (not marginally).

Eligibility caps annual income at $3,500,000 MXN; the engine flags when a user is
near or over the cap.
"""

from __future__ import annotations

from .money import D, money
from .result import CalcResult
from .tax_tables import (
    RESICO_ANNUAL_INCOME_CAP_MX,
    RESICO_MONTHLY_MX,
    TaxTable,
)


def resico_isr_monthly(
    monthly_income, table: TaxTable = RESICO_MONTHLY_MX
) -> CalcResult:
    """Flat-rate ISR on total monthly income under RESICO."""
    income = D(monthly_income)
    if income <= 0:
        return CalcResult(
            amount=money(0),
            label="ISR RESICO (mensual)",
            breakdown=[("Ingresos del mes", money(income))],
            source=table.source,
            effective_year=table.effective_year,
            notes=["No income → no ISR this month."],
        )

    bracket = next(
        b for b in table.brackets if b.upper is None or income <= b.upper
    )
    tax = income * bracket.rate

    notes = []
    # Projected annual income vs the eligibility cap (rough 12× signal).
    projected_annual = income * 12
    if projected_annual > RESICO_ANNUAL_INCOME_CAP_MX:
        notes.append(
            "At this monthly rate, projected annual income exceeds the "
            f"${RESICO_ANNUAL_INCOME_CAP_MX:,.0f} RESICO cap — eligibility at risk."
        )

    return CalcResult(
        amount=money(tax),
        label="ISR RESICO (mensual)",
        breakdown=[
            ("Ingresos del mes (amparados por CFDI)", money(income)),
            ("Tasa aplicable", bracket.rate),
        ],
        source=table.source,
        effective_year=table.effective_year,
        notes=notes,
    )


def resico_eligible(annual_income) -> bool:
    """True if annual income is within the RESICO eligibility cap."""
    return D(annual_income) <= RESICO_ANNUAL_INCOME_CAP_MX