fix(conciliacion): complementos de pago usan fecha_pago_p y campos faltantes en visor
- conciliacion.service.ts: filtros y ordenamiento ahora usan
COALESCE(fecha_pago_p, fecha_emision). Los CFDIs tipo P
(complementos de pago) aparecen en el periodo del pago real,
no de la emision del CFDI.
- conciliacion.service.ts: agrega fechaPagoP al SELECT y a la
interfaz ConciliacionCfdi.
- conciliacion/page.tsx: tablas y export Excel usan
fechaPagoP || fechaEmision para mostrar la fecha.
- cfdi-invoice.tsx: para tipo P con fechaPagoP, muestra
'Pago: {fecha}' en el encabezado.
- conciliacion.ts: actualiza interfaz ConciliacionCfdi con
todos los campos que ya devuelve el backend.
Refs: docs/CAMBIOS-2026-05-09.md secciones 7 y 8
This commit is contained in:
@@ -25,6 +25,7 @@ export interface ConciliacionCfdi {
|
|||||||
usoCfdi: string | null;
|
usoCfdi: string | null;
|
||||||
status: string | null;
|
status: string | null;
|
||||||
fechaCertSat: string | null;
|
fechaCertSat: string | null;
|
||||||
|
fechaPagoP: string | null;
|
||||||
ivaTraslado: number;
|
ivaTraslado: number;
|
||||||
ivaRetencion: number;
|
ivaRetencion: number;
|
||||||
isrRetencion: number;
|
isrRetencion: number;
|
||||||
@@ -66,11 +67,11 @@ export async function getCfdisConConciliacion(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (filters.fechaInicio) {
|
if (filters.fechaInicio) {
|
||||||
where += ` AND c.fecha_emision >= $${idx++}::date`;
|
where += ` AND COALESCE(c.fecha_pago_p, c.fecha_emision) >= $${idx++}::date`;
|
||||||
params.push(filters.fechaInicio);
|
params.push(filters.fechaInicio);
|
||||||
}
|
}
|
||||||
if (filters.fechaFin) {
|
if (filters.fechaFin) {
|
||||||
where += ` AND c.fecha_emision <= ($${idx++}::date + interval '1 day')`;
|
where += ` AND COALESCE(c.fecha_pago_p, c.fecha_emision) <= ($${idx++}::date + interval '1 day')`;
|
||||||
params.push(filters.fechaFin);
|
params.push(filters.fechaFin);
|
||||||
}
|
}
|
||||||
if (filters.regimen) {
|
if (filters.regimen) {
|
||||||
@@ -106,6 +107,7 @@ export async function getCfdisConConciliacion(
|
|||||||
c.uso_cfdi as "usoCfdi",
|
c.uso_cfdi as "usoCfdi",
|
||||||
c.status,
|
c.status,
|
||||||
c.fecha_cert_sat as "fechaCertSat",
|
c.fecha_cert_sat as "fechaCertSat",
|
||||||
|
c.fecha_pago_p as "fechaPagoP",
|
||||||
c.iva_traslado as "ivaTraslado",
|
c.iva_traslado as "ivaTraslado",
|
||||||
c.iva_retencion as "ivaRetencion",
|
c.iva_retencion as "ivaRetencion",
|
||||||
c.isr_retencion as "isrRetencion",
|
c.isr_retencion as "isrRetencion",
|
||||||
@@ -119,7 +121,7 @@ export async function getCfdisConConciliacion(
|
|||||||
LEFT JOIN conciliaciones con ON con.id_cfdi = c.id
|
LEFT JOIN conciliaciones con ON con.id_cfdi = c.id
|
||||||
LEFT JOIN bancos b ON b.id = con.id_banco
|
LEFT JOIN bancos b ON b.id = con.id_banco
|
||||||
${where}
|
${where}
|
||||||
ORDER BY c.fecha_emision DESC
|
ORDER BY COALESCE(c.fecha_pago_p, c.fecha_emision) DESC
|
||||||
`, params);
|
`, params);
|
||||||
|
|
||||||
return rows.map((r: any) => ({
|
return rows.map((r: any) => ({
|
||||||
@@ -150,6 +152,7 @@ export async function getCfdisConConciliacion(
|
|||||||
usoCfdi: r.usoCfdi,
|
usoCfdi: r.usoCfdi,
|
||||||
status: r.status,
|
status: r.status,
|
||||||
fechaCertSat: r.fechaCertSat,
|
fechaCertSat: r.fechaCertSat,
|
||||||
|
fechaPagoP: r.fechaPagoP,
|
||||||
ivaTraslado: Number(r.ivaTraslado || 0),
|
ivaTraslado: Number(r.ivaTraslado || 0),
|
||||||
ivaRetencion: Number(r.ivaRetencion || 0),
|
ivaRetencion: Number(r.ivaRetencion || 0),
|
||||||
isrRetencion: Number(r.isrRetencion || 0),
|
isrRetencion: Number(r.isrRetencion || 0),
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ export default function ConciliacionPage() {
|
|||||||
exportToExcel(
|
exportToExcel(
|
||||||
cfdis.map((c) => ({
|
cfdis.map((c) => ({
|
||||||
...c,
|
...c,
|
||||||
_fecha: new Date(c.fechaEmision).toLocaleDateString('es-MX'),
|
_fecha: new Date(c.fechaPagoP || c.fechaEmision).toLocaleDateString('es-MX'),
|
||||||
_totalMxn: getMonto(c),
|
_totalMxn: getMonto(c),
|
||||||
_estado: c.conciliado === 'true' ? 'Conciliado' : 'Pendiente',
|
_estado: c.conciliado === 'true' ? 'Conciliado' : 'Pendiente',
|
||||||
_fechaPago: c.conciliacion?.fechaDePago || '',
|
_fechaPago: c.conciliacion?.fechaDePago || '',
|
||||||
@@ -251,7 +251,7 @@ export default function ConciliacionPage() {
|
|||||||
{cfdi.uuid?.substring(0, 8)}
|
{cfdi.uuid?.substring(0, 8)}
|
||||||
</td>
|
</td>
|
||||||
<td className="py-2 text-xs">
|
<td className="py-2 text-xs">
|
||||||
{new Date(cfdi.fechaEmision).toLocaleDateString('es-MX')}
|
{new Date(cfdi.fechaPagoP || cfdi.fechaEmision).toLocaleDateString('es-MX')}
|
||||||
</td>
|
</td>
|
||||||
<td className="py-2 font-mono text-xs">{cfdi.rfcEmisor}</td>
|
<td className="py-2 font-mono text-xs">{cfdi.rfcEmisor}</td>
|
||||||
<td className="py-2 text-xs truncate max-w-[120px]">
|
<td className="py-2 text-xs truncate max-w-[120px]">
|
||||||
@@ -347,7 +347,7 @@ export default function ConciliacionPage() {
|
|||||||
{cfdi.uuid?.substring(0, 8)}
|
{cfdi.uuid?.substring(0, 8)}
|
||||||
</td>
|
</td>
|
||||||
<td className="py-2 text-xs">
|
<td className="py-2 text-xs">
|
||||||
{new Date(cfdi.fechaEmision).toLocaleDateString('es-MX')}
|
{new Date(cfdi.fechaPagoP || cfdi.fechaEmision).toLocaleDateString('es-MX')}
|
||||||
</td>
|
</td>
|
||||||
<td className="py-2 font-mono text-xs">{cfdi.rfcEmisor}</td>
|
<td className="py-2 font-mono text-xs">{cfdi.rfcEmisor}</td>
|
||||||
<td className="py-2 text-xs truncate max-w-[120px]">
|
<td className="py-2 text-xs truncate max-w-[120px]">
|
||||||
|
|||||||
@@ -129,7 +129,11 @@ export const CfdiInvoice = forwardRef<HTMLDivElement, CfdiInvoiceProps>(
|
|||||||
{cfdi.serie && <span className="text-blue-300">{cfdi.serie}-</span>}
|
{cfdi.serie && <span className="text-blue-300">{cfdi.serie}-</span>}
|
||||||
{cfdi.folio || 'S/N'}
|
{cfdi.folio || 'S/N'}
|
||||||
</div>
|
</div>
|
||||||
<p className="text-blue-200 text-sm mt-1">{formatDate(cfdi.fechaEmision)}</p>
|
<p className="text-blue-200 text-sm mt-1">
|
||||||
|
{cfdi.tipoComprobante === 'P' && cfdi.fechaPagoP
|
||||||
|
? `Pago: ${formatDate(cfdi.fechaPagoP)}`
|
||||||
|
: formatDate(cfdi.fechaEmision)}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,17 +4,31 @@ export interface ConciliacionCfdi {
|
|||||||
id: number;
|
id: number;
|
||||||
uuid: string;
|
uuid: string;
|
||||||
type: string;
|
type: string;
|
||||||
|
serie: string | null;
|
||||||
|
folio: string | null;
|
||||||
fechaEmision: string;
|
fechaEmision: string;
|
||||||
|
fechaPagoP: string | null;
|
||||||
rfcEmisor: string;
|
rfcEmisor: string;
|
||||||
nombreEmisor: string;
|
nombreEmisor: string;
|
||||||
rfcReceptor: string;
|
rfcReceptor: string;
|
||||||
nombreReceptor: string;
|
nombreReceptor: string;
|
||||||
total: number;
|
total: number;
|
||||||
totalMxn: number;
|
totalMxn: number;
|
||||||
|
subtotal: number;
|
||||||
|
descuento: number;
|
||||||
|
moneda: string;
|
||||||
|
tipoCambio: number;
|
||||||
tipoComprobante: string | null;
|
tipoComprobante: string | null;
|
||||||
montoPagoMxn: number;
|
montoPagoMxn: number;
|
||||||
montoMxn: number;
|
montoMxn: number;
|
||||||
metodoPago: string | null;
|
metodoPago: string | null;
|
||||||
|
formaPago: string | null;
|
||||||
|
usoCfdi: string | null;
|
||||||
|
status: string | null;
|
||||||
|
fechaCertSat: string | null;
|
||||||
|
ivaTraslado: number;
|
||||||
|
ivaRetencion: number;
|
||||||
|
isrRetencion: number;
|
||||||
conciliado: string | null;
|
conciliado: string | null;
|
||||||
idConciliacion: number | null;
|
idConciliacion: number | null;
|
||||||
conciliacion: {
|
conciliacion: {
|
||||||
|
|||||||
@@ -250,6 +250,39 @@ Siempre caía en el `else` mostrando CANCELADO.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 8. Fix: Complementos de pago (tipo P) en conciliación usan fecha de emisión en lugar de fecha de pago
|
||||||
|
|
||||||
|
**Problema:** Los complementos de pago emitidos por Husberto en abril no aparecían en la conciliación de "Emitidas" de abril. Estaban en mayo. Ejemplo:
|
||||||
|
- Factura PPD: 2026-04-22 a TPA210222462 por $167,140.97
|
||||||
|
- Complemento de pago: emitido 2026-05-03, pero el pago fue el **2026-04-30**
|
||||||
|
|
||||||
|
El usuario esperaba verlo en abril porque el pago ocurrió en abril, pero el sistema filtraba por `fecha_emision` (mayo).
|
||||||
|
|
||||||
|
**Causa raíz:** El servicio de conciliación filtraba y ordenaba siempre por `fecha_emision`. Para los complementos de pago (tipo P), la fecha relevante es `fecha_pago_p` (fecha del pago documentado), no la fecha de emisión del CFDI.
|
||||||
|
|
||||||
|
**Fix aplicado:**
|
||||||
|
|
||||||
|
1. **Backend (`apps/api/src/services/conciliacion.service.ts`):**
|
||||||
|
- Filtros de fecha: `c.fecha_emision` → `COALESCE(c.fecha_pago_p, c.fecha_emision)`
|
||||||
|
- ORDER BY: `c.fecha_emision DESC` → `COALESCE(c.fecha_pago_p, c.fecha_emision) DESC`
|
||||||
|
- SELECT: agregado `c.fecha_pago_p as "fechaPagoP"`
|
||||||
|
- Interfaz y mapeo: agregado `fechaPagoP`
|
||||||
|
|
||||||
|
2. **Frontend (`apps/web/app/(dashboard)/conciliacion/page.tsx`):**
|
||||||
|
- Tabla "Por conciliar": `{new Date(cfdi.fechaPagoP || cfdi.fechaEmision).toLocaleDateString('es-MX')}`
|
||||||
|
- Tabla "Conciliadas": mismo cambio
|
||||||
|
- Export Excel: mismo cambio
|
||||||
|
|
||||||
|
3. **Frontend (`apps/web/lib/api/conciliacion.ts`):**
|
||||||
|
- Interfaz `ConciliacionCfdi`: agregados todos los campos faltantes que ya existen en el backend (`serie`, `folio`, `fechaPagoP`, `subtotal`, `descuento`, `moneda`, `tipoCambio`, `formaPago`, `usoCfdi`, `status`, `fechaCertSat`, `ivaTraslado`, `ivaRetencion`, `isrRetencion`)
|
||||||
|
|
||||||
|
4. **Visor (`apps/web/components/cfdi/cfdi-invoice.tsx`):**
|
||||||
|
- Para tipo P con `fechaPagoP`, muestra "Pago: {fecha}" en lugar de la fecha de emisión
|
||||||
|
|
||||||
|
**Resultado:** Los complementos de pago ahora aparecen en el período donde ocurrió el pago real, no cuando se emitió el CFDI.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Archivos modificados (actualizado)
|
## Archivos modificados (actualizado)
|
||||||
|
|
||||||
### Backend (`apps/api/`)
|
### Backend (`apps/api/`)
|
||||||
|
|||||||
Reference in New Issue
Block a user