fix: facturapi onboarding, CSF scraper, SAT sync initial, doc notifications

- Auto-update fiscal data on org creation via updateOrgLegalOnCreate
- Add Carta Manifiesto embedded iframe in CSD config page
- Fix CSF scraper: 60s timeout + manual RFC fallback when SAT doesn't auto-populate
- Fix contribuyenteId propagation in constancia frontend hooks/API
- Fix needsInitialSync to check per-contribuyente, not just per-tenant
- Fix documento notifications for global_admin using viewingTenantId
- Extract CSF manually for Carlos Husberto Torres Romero
- Trigger initial SAT sync for Carlos Husberto Torres Romero
- Update org legal data in Facturapi for Carlos Husberto (tax_system 612 + address)

Files changed:
- apps/api/src/controllers/documentos.controller.ts
- apps/api/src/jobs/sat-sync.job.ts
- apps/api/src/services/constancia.service.ts
- apps/api/src/services/contribuyente-facturapi.service.ts
- apps/api/src/services/sat/sat-csf-login.ts
- apps/web/app/(dashboard)/configuracion/csd/page.tsx
- apps/web/lib/api/constancias.ts
- apps/web/lib/hooks/use-constancias.ts
- docs/sessions/2026-05-17-facturapi-csf-sync-notifications.md
This commit is contained in:
Horux Dev
2026-05-17 04:28:32 +00:00
parent 1c92b8eaf1
commit 44d7c796c9
9 changed files with 292 additions and 84 deletions

View File

@@ -7,7 +7,7 @@ import { useTimbres } from '@/lib/hooks/use-facturacion';
import { apiClient } from '@/lib/api/client';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { useContribuyenteStore } from '@/stores/contribuyente-store';
import { Shield, Upload, Check, AlertCircle, Receipt, Palette, Image, Building2 } from 'lucide-react';
import { Shield, Upload, Check, AlertCircle, Receipt, Palette, Image, Building2, FileText } from 'lucide-react';
function CustomizationSection() {
const queryClient = useQueryClient();
@@ -333,6 +333,29 @@ export default function CsdConfigPage() {
</Card>
)}
{/* Carta Manifiesto */}
{selectedContribuyenteId && orgStatus?.configured && (
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2 text-base">
<FileText className="h-4 w-4" />
Carta Manifiesto
</CardTitle>
<CardDescription>
Firma requerida por el SAT/RMF para emitir CFDI. Usa tu e.firma (FIEL).
</CardDescription>
</CardHeader>
<CardContent>
<iframe
src={`https://www.facturapi.io/embedded/manifiesto?organization=${orgStatus.orgId}`}
className="w-full rounded-lg border"
style={{ height: '640px' }}
title="Firma de Carta Manifiesto"
/>
</CardContent>
</Card>
)}
{/* Personalización de factura */}
{selectedContribuyenteId && orgStatus?.configured && <CustomizationSection />}

View File

@@ -71,8 +71,10 @@ export const listConstancias = (contribuyenteId?: string) => {
return apiClient.get<Constancia[]>(`/documentos/constancias${params}`).then(r => r.data);
};
export const consultarConstancia = () =>
apiClient.post<Constancia>('/documentos/constancias/consultar').then(r => r.data);
export const consultarConstancia = (contribuyenteId?: string) => {
const params = contribuyenteId ? `?contribuyenteId=${encodeURIComponent(contribuyenteId)}` : '';
return apiClient.post<Constancia>(`/documentos/constancias/consultar${params}`).then(r => r.data);
};
export const descargarConstanciaPdf = (id: number) =>
apiClient.get(`/documentos/constancias/${id}/pdf`, { responseType: 'blob' }).then(r => r.data as Blob);

View File

@@ -15,10 +15,11 @@ export function useConstancias() {
export function useConsultarConstancia() {
const qc = useQueryClient();
const viewingTenantId = useTenantViewStore((s) => s.viewingTenantId);
const { selectedContribuyenteId } = useContribuyenteStore();
return useMutation({
mutationFn: consultarConstancia,
mutationFn: () => consultarConstancia(selectedContribuyenteId || undefined),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['constancias', viewingTenantId] });
qc.invalidateQueries({ queryKey: ['constancias', viewingTenantId, selectedContribuyenteId] });
qc.invalidateQueries({ queryKey: ['tenant-info'] });
qc.invalidateQueries({ queryKey: ['regimenes-activos'] });
},