Plataforma técnica · Orchestrator
Renta Service
Orchestrator Reportes Renta
RentaService es el wrapper más delgado del dominio reportes: una sola operación pública. Extiende ReportesServiceSupport para reusar buildRenta.
async calcularRenta( ctx: ServiceContext, anio: number, mes: number,): Promise<ServiceResult<BalanceTributario>>const pool = this.getPool(ctx.tenantDb);const raw = await ReportesRepository.calcularRenta(pool, anio, mes);return this.success(this.buildRenta(raw));Una query, una composición, retorno. Sin transacción, sin eventos.
Validaciones
Section titled “Validaciones”anioentero en[2000, 2100]→ValidationError("Año inválido")mesentero en[1, 12]→ValidationError("Mes inválido (1-12)")
Output: BalanceTributario
Section titled “Output: BalanceTributario”interface BalanceTributario { // Ingresos ventas_netas: number; nc_ventas: number; total_ingresos: number; // ventas + nc_ventas
// Deducciones compras_netas: number; nc_compras: number; total_compras: number; // compras + nc_compras honorarios: number; impuesto_tabaco: number; impuesto_bebidas_sin_azucar: number; impuesto_bebidas_con_azucar: number; impuesto_tabacos_elaborados: number; total_deducciones: number; // suma de todo lo anterior
// Resultado base_imponible: number; // total_ingresos - total_deducciones ppm: number; // PPM declarado del año tasa_impuesto: number; // 0.27 impuesto_estimado: number; // max(0, base_imponible) * 0.27 diferencia: number; // impuesto_estimado - ppm (positivo = a pagar)}buildRenta (en Support)
Section titled “buildRenta (en Support)”protected buildRenta(raw): BalanceTributario { const total_ingresos = raw.ventas_netas + raw.nc_ventas; const total_compras = raw.compras_netas + raw.nc_compras; const total_deducciones = total_compras + raw.honorarios + raw.impuesto_tabaco + raw.impuesto_bebidas_sin_azucar + raw.impuesto_bebidas_con_azucar + raw.impuesto_tabacos_elaborados;
const base_imponible = total_ingresos - total_deducciones; const impuesto_estimado = base_imponible > 0 ? Math.round(base_imponible * TASA_IMPUESTO) // 0.27 : 0; const diferencia = impuesto_estimado - raw.ppm;
return { ...raw, total_ingresos, total_compras, total_deducciones, base_imponible, tasa_impuesto: TASA_IMPUESTO, impuesto_estimado, diferencia };}La heavy lifting (suma de ventas/compras/honorarios/impuestos específicos del año) vive en RentaRepository.calcularRenta. El service solo redondea y compone.
Por qué impuestos específicos como deducciones
Section titled “Por qué impuestos específicos como deducciones”impuesto_tabaco, impuesto_bebidas_*, impuesto_tabacos_elaborados son impuestos adicionales (no IVA general) que el contribuyente paga sobre productos específicos. Para renta, se tratan como deducciones porque ya fueron pagados al fisco — no pueden gravarse de nuevo a través del impuesto a la primera categoría.
El IVA general no aparece aquí porque no es deducible de renta; se neteó al consolidar ventas netas y compras netas.
Tasa 27%
Section titled “Tasa 27%”Constante de módulo TASA_IMPUESTO = 0.27 (Régimen General Art. 14A LIR). El service no resuelve régimen tributario — asume 27% para la estimación. Para empresas Pro Pyme (Art. 14D N°3) la tasa real es 25% (general) o variable. El impuesto_estimado por tanto es una aproximación de caja, no la determinación final del impuesto a la renta.
La determinación formal del impuesto vive en el módulo de renta anual (F22) que evalúa el régimen vigente, agregados, deducciones extraordinarias, créditos y registros empresariales. Esta vista es para feedback rápido en el ciclo contable.
diferencia y su signo
Section titled “diferencia y su signo”diferencia = impuesto_estimado - ppm| Signo | Significado |
|---|---|
> 0 | El PPM declarado durante el año no cubre el impuesto estimado. Falta pagar la diferencia en F22. |
< 0 | El PPM excede el impuesto. Devolución o crédito a favor. |
= 0 | Pago exacto. |
Cuándo usar RentaService vs BalanceService.calcular
Section titled “Cuándo usar RentaService vs BalanceService.calcular”BalanceService.calcular retorna ReporteAnual.renta que es el mismo BalanceTributario. Hay dos paths para llegar al mismo dato:
BalanceService.calcular(anio, tipo, {mes})→ cómputo completo de balance + EERR + renta. Útil cuando el caller necesita los tres.RentaService.calcularRenta(anio, mes)→ solo la renta. Útil cuando el caller solo necesita la base imponible (e.g., generar PDF de borrador F22, panel de renta).
La diferencia operativa: BalanceService.calcular hace Promise.all([calcularLineasBalance, calcularRenta]). RentaService.calcularRenta salta la primera query y solo computa la renta — más rápido cuando el balance no se necesita.