159 lines
5.2 KiB
TypeScript
159 lines
5.2 KiB
TypeScript
import { prisma } from '../config/database.js';
|
|
import type { IvaMensual, IsrMensual, ResumenIva, ResumenIsr } from '@horux/shared';
|
|
|
|
export async function getIvaMensual(schema: string, año: number): Promise<IvaMensual[]> {
|
|
const data = await prisma.$queryRawUnsafe<IvaMensual[]>(`
|
|
SELECT
|
|
id, año, mes,
|
|
iva_trasladado as "ivaTrasladado",
|
|
iva_acreditable as "ivaAcreditable",
|
|
COALESCE(iva_retenido, 0) as "ivaRetenido",
|
|
resultado, acumulado, estado,
|
|
fecha_declaracion as "fechaDeclaracion"
|
|
FROM "${schema}".iva_mensual
|
|
WHERE año = $1
|
|
ORDER BY mes
|
|
`, año);
|
|
|
|
return data.map(row => ({
|
|
...row,
|
|
ivaTrasladado: Number(row.ivaTrasladado),
|
|
ivaAcreditable: Number(row.ivaAcreditable),
|
|
ivaRetenido: Number(row.ivaRetenido),
|
|
resultado: Number(row.resultado),
|
|
acumulado: Number(row.acumulado),
|
|
}));
|
|
}
|
|
|
|
export async function getResumenIva(schema: string, año: number, mes: number): Promise<ResumenIva> {
|
|
// Get from iva_mensual if exists
|
|
const existing = await prisma.$queryRawUnsafe<any[]>(`
|
|
SELECT * FROM "${schema}".iva_mensual WHERE año = $1 AND mes = $2
|
|
`, año, mes);
|
|
|
|
if (existing && existing.length > 0) {
|
|
const record = existing[0];
|
|
const [acumuladoResult] = await prisma.$queryRawUnsafe<[{ total: number }]>(`
|
|
SELECT COALESCE(SUM(resultado), 0) as total
|
|
FROM "${schema}".iva_mensual
|
|
WHERE año = $1 AND mes <= $2
|
|
`, año, mes);
|
|
|
|
return {
|
|
trasladado: Number(record.iva_trasladado || 0),
|
|
acreditable: Number(record.iva_acreditable || 0),
|
|
retenido: Number(record.iva_retenido || 0),
|
|
resultado: Number(record.resultado || 0),
|
|
acumuladoAnual: Number(acumuladoResult?.total || 0),
|
|
};
|
|
}
|
|
|
|
// Calculate from CFDIs if no iva_mensual record
|
|
const [calcResult] = await prisma.$queryRawUnsafe<[{
|
|
trasladado: number;
|
|
acreditable: number;
|
|
retenido: number;
|
|
}]>(`
|
|
SELECT
|
|
COALESCE(SUM(CASE WHEN tipo = 'ingreso' THEN iva ELSE 0 END), 0) as trasladado,
|
|
COALESCE(SUM(CASE WHEN tipo = 'egreso' THEN iva ELSE 0 END), 0) as acreditable,
|
|
COALESCE(SUM(iva_retenido), 0) as retenido
|
|
FROM "${schema}".cfdis
|
|
WHERE estado = 'vigente'
|
|
AND EXTRACT(YEAR FROM fecha_emision) = $1
|
|
AND EXTRACT(MONTH FROM fecha_emision) = $2
|
|
`, año, mes);
|
|
|
|
const trasladado = Number(calcResult?.trasladado || 0);
|
|
const acreditable = Number(calcResult?.acreditable || 0);
|
|
const retenido = Number(calcResult?.retenido || 0);
|
|
const resultado = trasladado - acreditable - retenido;
|
|
|
|
return {
|
|
trasladado,
|
|
acreditable,
|
|
retenido,
|
|
resultado,
|
|
acumuladoAnual: resultado,
|
|
};
|
|
}
|
|
|
|
export async function getIsrMensual(schema: string, año: number): Promise<IsrMensual[]> {
|
|
// Check if isr_mensual table exists
|
|
try {
|
|
const data = await prisma.$queryRawUnsafe<IsrMensual[]>(`
|
|
SELECT
|
|
id, año, mes,
|
|
ingresos_acumulados as "ingresosAcumulados",
|
|
deducciones,
|
|
base_gravable as "baseGravable",
|
|
isr_causado as "isrCausado",
|
|
isr_retenido as "isrRetenido",
|
|
isr_a_pagar as "isrAPagar",
|
|
estado,
|
|
fecha_declaracion as "fechaDeclaracion"
|
|
FROM "${schema}".isr_mensual
|
|
WHERE año = $1
|
|
ORDER BY mes
|
|
`, año);
|
|
|
|
return data.map(row => ({
|
|
...row,
|
|
ingresosAcumulados: Number(row.ingresosAcumulados),
|
|
deducciones: Number(row.deducciones),
|
|
baseGravable: Number(row.baseGravable),
|
|
isrCausado: Number(row.isrCausado),
|
|
isrRetenido: Number(row.isrRetenido),
|
|
isrAPagar: Number(row.isrAPagar),
|
|
}));
|
|
} catch {
|
|
// Table doesn't exist, return empty array
|
|
return [];
|
|
}
|
|
}
|
|
|
|
export async function getResumenIsr(schema: string, año: number, mes: number): Promise<ResumenIsr> {
|
|
// Calculate from CFDIs
|
|
const [ingresos] = await prisma.$queryRawUnsafe<[{ total: number }]>(`
|
|
SELECT COALESCE(SUM(total), 0) as total
|
|
FROM "${schema}".cfdis
|
|
WHERE tipo = 'ingreso' AND estado = 'vigente'
|
|
AND EXTRACT(YEAR FROM fecha_emision) = $1
|
|
AND EXTRACT(MONTH FROM fecha_emision) <= $2
|
|
`, año, mes);
|
|
|
|
const [egresos] = await prisma.$queryRawUnsafe<[{ total: number }]>(`
|
|
SELECT COALESCE(SUM(total), 0) as total
|
|
FROM "${schema}".cfdis
|
|
WHERE tipo = 'egreso' AND estado = 'vigente'
|
|
AND EXTRACT(YEAR FROM fecha_emision) = $1
|
|
AND EXTRACT(MONTH FROM fecha_emision) <= $2
|
|
`, año, mes);
|
|
|
|
const [retenido] = await prisma.$queryRawUnsafe<[{ total: number }]>(`
|
|
SELECT COALESCE(SUM(isr_retenido), 0) as total
|
|
FROM "${schema}".cfdis
|
|
WHERE estado = 'vigente'
|
|
AND EXTRACT(YEAR FROM fecha_emision) = $1
|
|
AND EXTRACT(MONTH FROM fecha_emision) <= $2
|
|
`, año, mes);
|
|
|
|
const ingresosAcumulados = Number(ingresos?.total || 0);
|
|
const deducciones = Number(egresos?.total || 0);
|
|
const baseGravable = Math.max(0, ingresosAcumulados - deducciones);
|
|
|
|
// Simplified ISR calculation (actual calculation would use SAT tables)
|
|
const isrCausado = baseGravable * 0.30; // 30% simplified rate
|
|
const isrRetenido = Number(retenido?.total || 0);
|
|
const isrAPagar = Math.max(0, isrCausado - isrRetenido);
|
|
|
|
return {
|
|
ingresosAcumulados,
|
|
deducciones,
|
|
baseGravable,
|
|
isrCausado,
|
|
isrRetenido,
|
|
isrAPagar,
|
|
};
|
|
}
|