feat(cfdi): agrega C.P. receptor, regimen receptor, no_identificacion, tipo_relacion y CFDIs relacionados al visualizador
Backend: - Migracion 044: codigo_postal_receptor VARCHAR(5) + indice - sat-parser: extrae DomicilioFiscalReceptor - sat.service: persiste codigo_postal_receptor en INSERT/UPDATE - cfdi.service: incluye codigo_postal_receptor en CFDI_SELECT - shared/types: codigoPostalReceptor en interfaz Cfdi Frontend: - cfdi-invoice: tarjeta receptor con C.P. y regimen (con descripciones) - cfdi-invoice: seccion CFDI Relacionado (tipo + UUIDs) - cfdi-invoice: columna No. Identificacion en tabla de conceptos - cfdi-viewer-modal: mapea noIdentificacion desde DB y XML
This commit is contained in:
@@ -10,6 +10,7 @@ interface CfdiConcepto {
|
||||
importe: number;
|
||||
claveUnidad?: string;
|
||||
claveProdServ?: string;
|
||||
noIdentificacion?: string;
|
||||
}
|
||||
|
||||
interface CfdiInvoiceProps {
|
||||
@@ -66,6 +67,38 @@ const metodoPagoLabels: Record<string, string> = {
|
||||
PPD: 'Pago en parcialidades o diferido',
|
||||
};
|
||||
|
||||
const regimenFiscalLabels: Record<string, string> = {
|
||||
'601': 'General de Ley Personas Morales',
|
||||
'603': 'Personas Morales con Fines no Lucrativos',
|
||||
'605': 'Sueldos y Salarios e Ingresos Asimilados a Salarios',
|
||||
'606': 'Arrendamiento',
|
||||
'608': 'Demás ingresos',
|
||||
'609': 'Consolidación',
|
||||
'610': 'Residentes en el Extranjero sin Establecimiento Permanente en México',
|
||||
'611': 'Ingresos por Dividendos (socios y accionistas)',
|
||||
'612': 'Personas Físicas con Actividades Empresariales y Profesionales',
|
||||
'614': 'Ingresos por intereses',
|
||||
'615': 'Régimen de los ingresos por obtención de premios',
|
||||
'616': 'Sin obligaciones fiscales',
|
||||
'620': 'Sociedades Cooperativas de Producción que optan por diferir sus ingresos',
|
||||
'621': 'Incorporación Fiscal',
|
||||
'622': 'Actividades Agrícolas, Ganaderas, Silvícolas y Pesqueras',
|
||||
'623': 'Opcional para Grupos de Sociedades',
|
||||
'624': 'Coordinados',
|
||||
'625': 'Régimen de las Actividades Empresariales con ingresos a través de Plataformas Tecnológicas',
|
||||
'626': 'Régimen Simplificado de Confianza',
|
||||
};
|
||||
|
||||
const tipoRelacionLabels: Record<string, string> = {
|
||||
'01': 'Nota de crédito',
|
||||
'02': 'Nota de débito',
|
||||
'03': 'Devolución de mercancía',
|
||||
'04': 'Sustitución de CFDI previo',
|
||||
'05': 'Traslados de mercancias facturados previamente',
|
||||
'06': 'Factura generada por traslados previos',
|
||||
'07': 'CFDI por aplicación de anticipo',
|
||||
};
|
||||
|
||||
const usoCfdiLabels: Record<string, string> = {
|
||||
G01: 'Adquisición de mercancías',
|
||||
G02: 'Devoluciones, descuentos o bonificaciones',
|
||||
@@ -142,13 +175,26 @@ export const CfdiInvoice = forwardRef<HTMLDivElement, CfdiInvoiceProps>(
|
||||
{/* Receptor */}
|
||||
<div className="bg-gray-50 rounded-lg p-4 mb-5 border-l-4 border-blue-600">
|
||||
<div className="flex items-start justify-between">
|
||||
<div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-xs text-gray-500 uppercase tracking-wide font-medium">Receptor</p>
|
||||
<p className="text-lg font-semibold text-gray-800 mt-1">{cfdi.nombreReceptor}</p>
|
||||
<p className="text-gray-600 text-sm">RFC: {cfdi.rfcReceptor}</p>
|
||||
<div className="flex flex-wrap items-center gap-x-4 gap-y-1 mt-1 text-sm text-gray-600">
|
||||
<span>RFC: {cfdi.rfcReceptor}</span>
|
||||
{cfdi.codigoPostalReceptor && (
|
||||
<span>C.P.: {cfdi.codigoPostalReceptor}</span>
|
||||
)}
|
||||
{cfdi.regimenFiscalReceptor && (
|
||||
<span>
|
||||
Régimen: {cfdi.regimenFiscalReceptor}
|
||||
{regimenFiscalLabels[cfdi.regimenFiscalReceptor]
|
||||
? ` — ${regimenFiscalLabels[cfdi.regimenFiscalReceptor]}`
|
||||
: ''}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{cfdi.usoCfdi && (
|
||||
<div className="text-right">
|
||||
<div className="text-right ml-4 flex-shrink-0">
|
||||
<p className="text-xs text-gray-500 uppercase tracking-wide font-medium">Uso CFDI</p>
|
||||
<p className="text-sm font-medium text-gray-700 mt-1">
|
||||
{cfdi.usoCfdi} - {usoCfdiLabels[cfdi.usoCfdi] || ''}
|
||||
@@ -158,6 +204,41 @@ export const CfdiInvoice = forwardRef<HTMLDivElement, CfdiInvoiceProps>(
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* CFDIs Relacionados */}
|
||||
{(cfdi.cfdiTipoRelacion || cfdi.cfdisRelacionados) && (
|
||||
<div className="bg-amber-50 rounded-lg p-3 mb-5 border border-amber-200">
|
||||
<div className="flex items-start gap-3">
|
||||
<svg className="w-5 h-5 text-amber-600 mt-0.5 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1" />
|
||||
</svg>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-xs font-semibold text-amber-800 uppercase tracking-wide">CFDI Relacionado</p>
|
||||
{cfdi.cfdiTipoRelacion && (
|
||||
<p className="text-sm text-gray-700 mt-1">
|
||||
<span className="font-medium">Tipo de relación:</span>{' '}
|
||||
{cfdi.cfdiTipoRelacion} — {tipoRelacionLabels[cfdi.cfdiTipoRelacion] || 'Desconocido'}
|
||||
</p>
|
||||
)}
|
||||
{cfdi.cfdisRelacionados && (
|
||||
<div className="text-sm text-gray-700 mt-1">
|
||||
<span className="font-medium">UUIDs relacionados:</span>
|
||||
<div className="flex flex-wrap gap-2 mt-1">
|
||||
{cfdi.cfdisRelacionados.split('|').map((uuid) => uuid.trim()).filter(Boolean).map((uuid, idx) => (
|
||||
<span
|
||||
key={idx}
|
||||
className="inline-block px-2 py-0.5 bg-white border border-amber-200 rounded text-xs font-mono text-gray-600"
|
||||
>
|
||||
{uuid}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Datos del Comprobante */}
|
||||
<div className="grid grid-cols-4 gap-3 mb-5">
|
||||
<div className="bg-gray-50 rounded-lg p-3 text-center">
|
||||
@@ -203,6 +284,7 @@ export const CfdiInvoice = forwardRef<HTMLDivElement, CfdiInvoiceProps>(
|
||||
<thead>
|
||||
<tr className="bg-gray-100">
|
||||
<th className="text-left py-3 px-4 font-semibold text-gray-700">Descripción</th>
|
||||
<th className="text-center py-3 px-3 font-semibold text-gray-700 w-24">No. Id.</th>
|
||||
<th className="text-center py-3 px-3 font-semibold text-gray-700 w-20">Cant.</th>
|
||||
<th className="text-right py-3 px-4 font-semibold text-gray-700 w-32">P. Unitario</th>
|
||||
<th className="text-right py-3 px-4 font-semibold text-gray-700 w-32">Importe</th>
|
||||
@@ -223,6 +305,9 @@ export const CfdiInvoice = forwardRef<HTMLDivElement, CfdiInvoiceProps>(
|
||||
</p>
|
||||
)}
|
||||
</td>
|
||||
<td className="text-center py-3 px-3 text-gray-700">
|
||||
{concepto.noIdentificacion || <span className="text-gray-300">—</span>}
|
||||
</td>
|
||||
<td className="text-center py-3 px-3 text-gray-700">{concepto.cantidad}</td>
|
||||
<td className="text-right py-3 px-4 text-gray-700">
|
||||
{formatCurrency(concepto.valorUnitario)}
|
||||
|
||||
Reference in New Issue
Block a user