"""ISR — Impuesto Sobre la Renta (Mexico), general regime for personas físicas. Monthly provisional payment under the Régimen de Actividades Empresariales y Profesionales: tax is computed on a *taxable base* (income minus authorized deductions) using the progressive Article-96 tariff. This module also computes the standard withholdings (retenciones) a persona moral applies when paying a persona física for professional services. """ from __future__ import annotations from decimal import Decimal from .money import D, money from .result import CalcResult from .tax_tables import ( ISR_MONTHLY_MX_2024, ISR_RETENTION_PROF_SERVICES_MX, IVA_RETENTION_PROF_SERVICES_MX, TaxTable, ) def isr_provisional_monthly( taxable_base, table: TaxTable = ISR_MONTHLY_MX_2024 ) -> CalcResult: """ISR for one month given an already-computed taxable base. taxable_base = monthly income − authorized deductions (computed elsewhere). """ base = D(taxable_base) # Below the first bracket floor (which starts at 0.01) there is no ISR. if base <= 0: note = ( "Negative base → no ISR this month (carry the loss forward)." if base < 0 else "Zero base → no ISR this month." ) return CalcResult( amount=money(0), label="ISR provisional (mensual)", breakdown=[("Base gravable", money(base))], source=table.source, effective_year=table.effective_year, notes=[note], ) bracket = next(b for b in table.brackets if b.contains(base)) excess = base - bracket.lower tax_on_excess = excess * bracket.rate tax = bracket.fixed_fee + tax_on_excess return CalcResult( amount=money(tax), label="ISR provisional (mensual)", breakdown=[ ("Base gravable", money(base)), ("Límite inferior", money(bracket.lower)), ("Excedente sobre límite inferior", money(excess)), ("Tasa marginal", bracket.rate), ("Impuesto sobre excedente", money(tax_on_excess)), ("Cuota fija", money(bracket.fixed_fee)), ], source=table.source, effective_year=table.effective_year, ) def taxable_base(income, deductions) -> Decimal: """income − deductions, floored at zero.""" base = D(income) - D(deductions) return base if base > 0 else D(0) def retenciones_servicios_profesionales(amount) -> CalcResult: """Withholdings on professional fees: 10% ISR + 10.6667% IVA (two-thirds of 16%). Applies when a persona física invoices a persona moral for professional services. The persona moral retains these and the persona física credits them later. """ base = D(amount) isr_ret = base * ISR_RETENTION_PROF_SERVICES_MX iva_ret = base * IVA_RETENTION_PROF_SERVICES_MX total = isr_ret + iva_ret return CalcResult( amount=money(total), label="Retenciones por servicios profesionales", breakdown=[ ("Monto del servicio (base)", money(base)), ("Retención ISR (10%)", money(isr_ret)), ("Retención IVA (2/3 de 16%)", money(iva_ret)), ], source="LISR Art. 106 / LIVA Art. 1-A (verify)", notes=["These retentions are credited against your own monthly ISR/IVA."], )