feat(cfdi): agrega columna y filtro no_identificacion en tabla Conceptos

- Backend (cfdi.service.ts): getConceptosList ahora soporta filtro noIdentificacion
  via cc.no_identificacion ILIKE

- Frontend API (cfdi.ts): ConceptosFilters incluye noIdentificacion; se envía
  como query param

- Frontend página (cfdi/page.tsx):
  * Nuevo estado noIdentificacion en conceptosFilters
  * Nueva columna 'No. Identificación' en header de tabla con Popover filtro
  * Celda no_identificacion renderizada en cada fila
  * Export a Excel respeta el nuevo filtro
This commit is contained in:
Horux Dev
2026-05-15 23:22:38 +00:00
parent 7b1f60cbf2
commit 552a7c7716
3 changed files with 35 additions and 2 deletions

View File

@@ -325,10 +325,11 @@ export default function CfdiPage() {
uuidLike: string;
claveProdServ: string;
descripcionConcepto: string;
noIdentificacion: string;
orderBy?: 'fecha' | 'importe';
orderDir?: 'asc' | 'desc';
}>({ uuidLike: '', claveProdServ: '', descripcionConcepto: '' });
const [conceptosOpenFilter, setConceptosOpenFilter] = useState<'uuid' | 'clave' | 'descripcion' | null>(null);
}>({ uuidLike: '', claveProdServ: '', descripcionConcepto: '', noIdentificacion: '' });
const [conceptosOpenFilter, setConceptosOpenFilter] = useState<'uuid' | 'clave' | 'descripcion' | 'noIdentificacion' | null>(null);
const conceptosQuery = useQuery({
queryKey: ['cfdi-conceptos', filters, selectedContribuyenteId, conceptosFilters],
@@ -338,6 +339,7 @@ export default function CfdiPage() {
uuidLike: conceptosFilters.uuidLike || undefined,
claveProdServ: conceptosFilters.claveProdServ || undefined,
descripcionConcepto: conceptosFilters.descripcionConcepto || undefined,
noIdentificacion: conceptosFilters.noIdentificacion || undefined,
orderBy: conceptosFilters.orderBy,
orderDir: conceptosFilters.orderDir,
}),
@@ -481,6 +483,7 @@ export default function CfdiPage() {
uuidLike: conceptosFilters.uuidLike || undefined,
claveProdServ: conceptosFilters.claveProdServ || undefined,
descripcionConcepto: conceptosFilters.descripcionConcepto || undefined,
noIdentificacion: conceptosFilters.noIdentificacion || undefined,
orderBy: conceptosFilters.orderBy,
orderDir: conceptosFilters.orderDir,
page: 1,
@@ -1647,6 +1650,28 @@ export default function CfdiPage() {
</Popover>
</div>
</th>
<th className="pb-3 font-medium">
<div className="flex items-center gap-1 justify-center">
No. Identificación
<Popover open={conceptosOpenFilter === 'noIdentificacion'} onOpenChange={(open) => setConceptosOpenFilter(open ? 'noIdentificacion' : null)}>
<PopoverTrigger asChild>
<button className={`p-1 rounded hover:bg-muted ${conceptosFilters.noIdentificacion ? 'text-primary' : ''}`}>
<Filter className="h-3.5 w-3.5" />
</button>
</PopoverTrigger>
<PopoverContent className="w-64" align="start">
<div className="space-y-3">
<h4 className="font-medium text-sm">Filtrar por No. Identificación</h4>
<Input className="h-8 text-sm font-mono" placeholder="Ej: PROD-001" value={conceptosFilters.noIdentificacion} onChange={(e) => setConceptosFilters({ ...conceptosFilters, noIdentificacion: e.target.value })} />
<div className="flex gap-2">
<Button size="sm" className="flex-1" onClick={() => { setFilters({ ...filters, page: 1 }); setConceptosOpenFilter(null); }}>Aplicar</Button>
{conceptosFilters.noIdentificacion && <Button size="sm" variant="outline" onClick={() => { setConceptosFilters({ ...conceptosFilters, noIdentificacion: '' }); setFilters({ ...filters, page: 1 }); }}>Limpiar</Button>}
</div>
</div>
</PopoverContent>
</Popover>
</div>
</th>
<th className="pb-3 font-medium">RFC Emisor</th>
<th className="pb-3 font-medium">RFC Receptor</th>
<th className="pb-3 font-medium text-right">Cantidad</th>
@@ -1676,6 +1701,7 @@ export default function CfdiPage() {
<td className="py-2 font-mono text-xs" title={row.uuid}>{row.uuid?.substring(0, 8) || '-'}</td>
<td className="py-2 font-mono text-xs">{row.clave_prod_serv || '-'}</td>
<td className="py-2 text-left max-w-[280px] truncate" title={row.descripcion}>{row.descripcion}</td>
<td className="py-2 font-mono text-xs" title={row.no_identificacion || ''}>{row.no_identificacion || '-'}</td>
<td className="py-2 font-mono text-xs">{row.rfcEmisor}</td>
<td className="py-2 font-mono text-xs">{row.rfcReceptor}</td>
<td className="py-2 text-right">{Number(row.cantidad ?? 0).toLocaleString('es-MX', { minimumFractionDigits: 2 })}</td>