Skip to content

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.

  • anio entero en [2000, 2100]ValidationError("Año inválido")
  • mes entero en [1, 12]ValidationError("Mes inválido (1-12)")
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)
}
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.

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 = impuesto_estimado - ppm
SignoSignificado
> 0El PPM declarado durante el año no cubre el impuesto estimado. Falta pagar la diferencia en F22.
< 0El PPM excede el impuesto. Devolución o crédito a favor.
= 0Pago 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.