Skip to content

Repository files navigation

🧾 Fiscalapi XML Downloader (sat-ws-descarga-masiva)

.NET.NET.NETNugetLicense

📋 Descripción

Librería de https://fiscalapi.com para .NET, permite consultar y descargar facturas (CFDI) emitidas y recibidas a través del servicio web del SAT, incluyendo la obtención de metadata. Este servicio es parte del sistema "Consulta y recuperación de comprobantes" del SAT. Este paquete depende Fiscalapi.Credentials. Se recomienda leer su documentación antes de continuar.

🎯 Casos de Uso

  • Automatización de cadena de suministros - Descarga automática de facturas de proveedores
  • Automatización de cuentas por pagar - Gestión de facturas recibidas
  • Automatización de cuentas por cobrar - Control de facturas emitidas
  • Contabilidad electrónica - Integración con sistemas contables
  • Generación de pólizas contables - Procesamiento automático de comprobantes

📦 Instalación

# Package Manager
NuGet\Install-Package Fiscalapi.XmlDownloader
# .NET CLI
dotnet add package Fiscalapi.XmlDownloader

⬆️ Migración v5 → v6

La versión 6.0.0 introduce una API por-documento: leer un paquete ya no falla completo por un solo XML o línea de metadata ilegible, y agrega soporte para CFDI 3.3 (garantizado en descargas históricas, vigente hasta el 31-mar-2023).

#Breaking changev5v6
1GetComprobantesAsync (3 overloads)IAsyncEnumerable<Comprobante>IAsyncEnumerable<ComprobanteResult>: filtra por Succeeded; los fallidos traen RawXml, ErrorMessage y Error
2GetMetadataAsync (3 overloads)IAsyncEnumerable<MetaItem>IAsyncEnumerable<MetaItemResult>: los fallidos traen LineNumber, RawLine y ErrorMessage
3ZIP ilegible / vacío / base64 corruptoInvalidDataException / ArgumentExceptionCorruptPackageException (tipada, con PackageSize e inner exception)
4DownloadResponse.Succeededtrue con solo HTTP 200true solo con CodEstatus 5000 y<Paquete> con contenido; códigos SAT no mapeados degradan a SatStatus.Unknown sin lanzar
5CFDI 3.3fallaba la deserialización (y tumbaba el paquete)soportado: se mapea a la forma 4.0 unificada preservando Version = "3.3"; campos exclusivos 4.0 quedan con Specified = false; en traslados a nivel comprobante Base = 0 (no existe en 3.3)
6Match de complementos tipadospor prefijo XML (tfd, pago20)por namespace URI (el prefijo es decorativo); un complemento ilegible degrada a warning y conserva su crudo en Complemento.Any
7Flags nuevos ExportacionSpecified, ObjetoImpSpecified, RegimenFiscalReceptorSpecified, UsoCFDISpecifiedal deserializar 4.0 se establecen en true automáticamente; si construyes un Comprobante a mano para serializar, ponlos en true o el atributo se omite
8MetaItem.CreateFromString / Comprobante.DeserializeComplementsactivos[Obsolete]: usa TryCreateFromString / TryDeserializeComplements; el parse de metadata usa CultureInfo.InvariantCulture

Ejemplo de migración:

// v5awaitforeach(varcomprobanteinservice.GetComprobantesAsync(downloadResponse)){Save(comprobante);}// v6awaitforeach(varresultinservice.GetComprobantesAsync(downloadResponse)){if(result.Succeeded)Save(result.Comprobante!);// CFDI 3.3 o 4.0, forma unificadaelseLogFailure(result.SourceName,result.ErrorMessage,result.RawXml);}

Los complementos sin modelo tipado (nómina, carta porte, comercio exterior, INE, Pagos 1.0 de CFDI 3.3, etc.) no se pierden: viajan crudos como XmlElement en Comprobante.Complemento.Any — persístelos si los necesitas.

🔄 Flujo de Operación

flowchart TD
START([Inicio]) --> AUTH[🔑 Autenticarse<br/>AuthService]
AUTH --> AUTH_OK{¿Éxito?}
AUTH_OK -->|No| ERROR([❌ Error])
AUTH_OK -->|Sí| QUERY[📝 Crear Solicitud<br/>QueryService]
QUERY --> QUERY_OK{¿Éxito?}
QUERY_OK -->|No| ERROR
QUERY_OK -->|Sí| VERIFY[🔍 Verificar Estado<br/>VerifyService]
VERIFY --> VERIFY_STATUS{¿Solicitud<br/>Resuelta?}
VERIFY_STATUS -->|En proceso| WAIT[⏳ Esperar]
WAIT --> VERIFY
VERIFY_STATUS -->|Error| ERROR
VERIFY_STATUS -->|Sí| DOWNLOAD[⬇️ Descargar Paquetes<br/>DownloadService]
DOWNLOAD --> DOWNLOAD_OK{¿Éxito?}
DOWNLOAD_OK -->|No| RETRY{¿Reintentar?}
RETRY -->|Sí| DOWNLOAD
RETRY -->|No| ERROR
DOWNLOAD_OK -->|Sí| SUCCESS([✅ Completado])
%% Estilos Fiscalapi
classDef service fill:#ffffff,stroke:#9c27b0,stroke-width:2px,color:#9c27b0
classDef decision fill:#f3e5f5,stroke:#9c27b0,stroke-width:2px,color:#9c27b0
classDef endpoint fill:#ffffff,stroke:#9c27b0,stroke-width:3px,color:#9c27b0
classDef error fill:#ffebee,stroke:#d32f2f,stroke-width:2px,color:#d32f2f
class AUTH,QUERY,VERIFY,DOWNLOAD,WAIT service
class AUTH_OK,QUERY_OK,VERIFY_STATUS,DOWNLOAD_OK,RETRY decision
class START,SUCCESS endpoint
class ERROR error
Loading

📊 Reglas de Negocio y Validaciones

Estados Permitidos por Tipo de Consulta

Tipo DescargaTipo ConsultaEstados Permitidos
EmitidosCFDIVigente, Cancelado, Todos
EmitidosMetadataVigente, Cancelado, Todos
RecibidosCFDISolo Vigente
RecibidosMetadataVigente, Cancelado, Todos

Validaciones Principales

  • Fechas: La fecha inicial debe ser menor a la fecha final
  • UUID: Debe tener exactamente 36 caracteres (cuando se especifica)
  • Límites de registros: Hasta 200,000 por petición (1,000,000 en metadata)
  • Tipos de consulta: Solo valores válidos definidos en SatQueryTypes
  • Estados de factura: Solo valores válidos según el tipo de descarga

🚀 Ejemplo de Uso

usingFiscalapi.XmlDownloader;usingFiscalapi.XmlDownloader.Models;internalclassProgram{privatestaticasyncTaskMain(string[]args){// Configuración de credenciales FIELvarcertBase64="certBase64...";varkeyBase64="keyBase64...";varpassword="keyPassPhrase...";varservice=newXmlDownloaderService();try{// 1. Autenticación con FIELConsole.WriteLine("Autenticando...");awaitservice.AuthenticateAsync(certBase64,keyBase64,password);// 2. Crear solicitud de descargaConsole.WriteLine("Creando solicitud...");varqueryParams=newQueryParameters{StartDate=newDateTime(2024,1,1).ToStartOfDay(),EndDate=newDateTime(2024,1,30).ToEndOfDay(),RecipientTin="RFC123456789",// RFC del receptorRequestType=QueryType.CFDI,InvoiceStatus=InvoiceStatus.Vigente};varqueryResponse=awaitservice.CreateRequestAsync(queryParams);if(!queryResponse.Succeeded){Console.WriteLine($"Error creando solicitud: {queryResponse.SatMessage}");return;}Console.WriteLine($"Solicitud creada exitosamente: {queryResponse.RequestId}");// 3. Verificar estado de la solicitudConsole.WriteLine("Verificando estado de la solicitud...");varverifyResponse=awaitservice.VerifyAsync(queryResponse.RequestId);if(!verifyResponse.Succeeded){Console.WriteLine($"Error verificando solicitud: {verifyResponse.SatMessage}");return;}Console.WriteLine($"Estado SAT: {verifyResponse.SatStatus}");Console.WriteLine($"Estado Solicitud: {verifyResponse.RequestStatus}");Console.WriteLine($"Facturas encontradas: {verifyResponse.InvoiceCount}");// 4. Descargar paquetes si están listosif(verifyResponse.IsReadyToDownload){Console.WriteLine($"Descargando {verifyResponse.PackageIds.Count} paquete(s)...");foreach(varpackageIdinverifyResponse.PackageIds){Console.WriteLine($"Descargando paquete: {packageId}");vardownloadResponse=awaitservice.DownloadAsync(packageId);if(downloadResponse.Succeeded){// Guardar paquete en discovarpackagePath=Path.Combine("C:\\FiscalAPI\\packages",$"{packageId}.zip");awaitservice.WritePackageAsync(packagePath,downloadResponse.PackageBytes);Console.WriteLine($"Paquete guardado en: {packagePath}");// Procesar comprobantes del paquete CFDIConsole.WriteLine("Procesando comprobantes...");awaitforeach(varcomprobanteinservice.GetComprobantesAsync(downloadResponse.PackageBytes)){Console.WriteLine($"CFDI procesado - Serie: {comprobante.Serie}, Folio: {comprobante.Folio}");}// Procesar items del paquete Metadata// await foreach (var item in service.GetMetadataAsync(downloadResponse.PackageBytes, CancellationToken.None))// {// Console.WriteLine($"Procesando MetaItem Uuid:{item.InvoiceUuid} Amount: {item.Amount} IsCancelled: {item.IsCancelled}");// }}else{Console.WriteLine($"Error descargando paquete {packageId}: {downloadResponse.SatMessage}");}}}else{Console.WriteLine($"La solicitud no está lista para descarga. Estado: {verifyResponse.RequestStatus}");}Console.WriteLine("Proceso completado exitosamente");}catch(Exceptionex){Console.WriteLine($"Error general: {ex.Message}");}}}

🔧 Servicios Principales

💡 La librería utiliza IXmlDownloaderService, el servicio principal que coordina y orquesta todo el flujo de descarga masiva. Actúa como el único punto de entrada para el desarrollador, centralizando y gestionando todo el proceso desde una sola interfaz.

Servicios Internos

AuthService Maneja la autenticación utilizando certificados FIEL (Firma Electrónica Avanzada) y gestión automática de tokens.

QueryService Crea solicitudes de descarga especificando parámetros como fechas, tipo de consulta, filtros y validaciones de reglas de negocio.

VerifyService Verifica el estado de las solicitudes creadas y obtiene los identificadores de paquetes disponibles para descarga.

DownloadService Descarga los paquetes ZIP que contienen los comprobantes fiscales y metadata desde los servidores del SAT.

FileStorageService Maneja el almacenamiento y lectura de paquetes descargados en el sistema de archivos local.

⚙️ Límites y Consideraciones

  • Límite de registros: Hasta 200,000 registros por petición (1,000,000 en metadata)
  • Número de solicitudes: Sin límite
  • Tiempo de respuesta: Variable, desde minutos hasta horas
  • Formato de descarga: Paquetes ZIP con archivos XML
  • Tipos soportados: CFDI emitidos, recibidos y metadata

📚 Documentación Oficial del SAT

  • Consulta el folder satdocs

🔧 Compatibilidad

  • .NET 8 / .NET 9 / .NET 10 - Frameworks soportados (multi-target)
  • Windows Forms - Aplicaciones de escritorio
  • Console Applications - Aplicaciones de línea de comandos
  • Web Applications - Aplicaciones web y APIs
  • Versionado Semántico 2.0.0 - Control de versiones

🤝 Contribuir

  1. Haz un fork del repositorio
  2. Crea una rama para tu feature: git checkout -b feature/AmazingFeature
  3. Realiza commits de tus cambios: git commit -m 'Add some AmazingFeature'
  4. Sube tu rama: git push origin feature/AmazingFeature
  5. Abre un Pull Request en GitHub

🐛 Reportar Problemas

Antes de reportar un problema:

  1. Verifica la versión: Asegúrate de usar la última versión del SDK
  2. Busca duplicados: Verifica si el problema ya fue reportado
  3. Ejemplo reproducible: Proporciona un ejemplo mínimo que reproduzca el error
  4. Logs completos: Incluye los mensajes de error completos y stack traces

🛣️ Roadmap

✅ Funcionalidades Completadas

  • Descarga de CFDI emitidos y recibidos
  • Descarga de metadata de CFDI
  • Validaciones de reglas de negocio del SAT
  • Soporte para múltiples RFC
  • Orquestador principal (IXmlDownloaderService)
  • Almacenamiento y lectura de paquetes descargados
  • Deserializado XML a objetos Comprobante CFDI.
  • Soporte para inyección de dependencias (.NET)

🚧 Próximas Funcionalidades

  • Descarga de CFDI Retenciones

🔗 Enlaces Útiles

📄 Licencia

Copyright © FISCAL API S DE R.L DE C.V.

Este proyecto está licenciado bajo la Licencia MPL (Mozilla Public License). Consulta el archivo LICENSE para más detalles.

About

Librería .NET para consumir los servicios web del SAT de Descarga Masiva XML

Resources

Stars

61 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages