UNPKG

@cfdi/xml

Version:

Generacion, sellado y timbrado de XML CFDI 4.0 para Node.js - facturacion electronica Mexico

373 lines (319 loc) 12.1 kB
<p align="center"> <a href="https://www.npmjs.com/package/@cfdi/xml"> <img src="https://raw.githubusercontent.com/MisaelMa/cards/main/packages/cfdi-xml.png" alt="@cfdi/xml" width="400" /> </a> </p> <h3 align="center">Librerias modernas para trabajar con CFDI 4.0 en Node.js</h3> <p align="center"> <a href="https://www.npmjs.com/package/@cfdi/xml"> <img src="https://img.shields.io/npm/v/@cfdi/xml?style=flat-square&color=cb3837&label=npm" alt="npm version" /> </a> <a href="https://www.npmjs.com/package/@cfdi/xml"> <img src="https://img.shields.io/npm/dm/@cfdi/xml?style=flat-square&color=cb3837&label=downloads" alt="npm downloads" /> </a> <a href="https://github.com/MisaelMa/node-cfdi/blob/main/LICENSE"> <img src="https://img.shields.io/badge/license-MIT-blue?style=flat-square" alt="license" /> </a> <img src="https://img.shields.io/badge/node-%3E%3D22-brightgreen?style=flat-square&logo=node.js&logoColor=white" alt="node" /> <img src="https://img.shields.io/badge/TypeScript-strict-3178c6?style=flat-square&logo=typescript&logoColor=white" alt="typescript" /> </p> <p align="center"> <a href="https://cfdi.recreando.dev"> <img src="https://raw.githubusercontent.com/MisaelMa/cards/main/cfdi-documentacion.png" alt="Documentacion" width="300" /> </a> </p> --- ## Ecosistema CFDI <p align="center"> <img src="https://raw.githubusercontent.com/MisaelMa/cards/main/cfdi-ecosystem.png" alt="CFDI Ecosystem" width="600" /> </p> <table> <tr> <td align="center" width="33%"> <a href="https://www.npmjs.com/package/@cfdi/complementos"> <img src="https://raw.githubusercontent.com/MisaelMa/cards/main/packages/cfdi-complementos.png" alt="@cfdi/complementos" width="100%" /> </a> </td> <td align="center" width="33%"> <a href="https://www.npmjs.com/package/@cfdi/xsd"> <img src="https://raw.githubusercontent.com/MisaelMa/cards/main/packages/cfdi-xsd.png" alt="@cfdi/xsd" width="100%" /> </a> </td> <td align="center" width="33%"> <a href="https://www.npmjs.com/package/@cfdi/csd"> <img src="https://raw.githubusercontent.com/MisaelMa/cards/main/packages/cfdi-csd.png" alt="@cfdi/csd" width="100%" /> </a> </td> </tr> <tr> <td align="center" width="33%"> <a href="https://www.npmjs.com/package/@cfdi/csf"> <img src="https://raw.githubusercontent.com/MisaelMa/cards/main/packages/cfdi-csf.png" alt="@cfdi/csf" width="100%" /> </a> </td> <td align="center" width="33%"> <a href="https://www.npmjs.com/package/@cfdi/catalogos"> <img src="https://raw.githubusercontent.com/MisaelMa/cards/main/packages/cfdi-catalogos.png" alt="@cfdi/catalogos" width="100%" /> </a> </td> <td align="center" width="33%"> <a href="https://www.npmjs.com/package/@cfdi/transform"> <img src="https://raw.githubusercontent.com/MisaelMa/cards/main/packages/cfdi-transform.png" alt="@cfdi/transform" width="100%" /> </a> </td> </tr> <tr> <td align="center" width="33%"> <a href="https://www.npmjs.com/package/@cfdi/elements"> <img src="https://raw.githubusercontent.com/MisaelMa/cards/main/packages/cfdi-elements.png" alt="@cfdi/elements" width="100%" /> </a> </td> <td align="center" width="33%"> <a href="https://www.npmjs.com/package/@cfdi/types"> <img src="https://raw.githubusercontent.com/MisaelMa/cards/main/packages/cfdi-types.png" alt="@cfdi/types" width="100%" /> </a> </td> <td align="center" width="33%"> <a href="https://www.npmjs.com/package/@cfdi/expresiones"> <img src="https://raw.githubusercontent.com/MisaelMa/cards/main/packages/cfdi-expresiones.png" alt="@cfdi/expresiones" width="100%" /> </a> </td> </tr> <tr> <td align="center" width="33%"> <a href="https://www.npmjs.com/package/@cfdi/xml2json"> <img src="https://raw.githubusercontent.com/MisaelMa/cards/main/packages/cfdi-2json.png" alt="@cfdi/xml2json" width="100%" /> </a> </td> <td align="center" width="33%"> <a href="https://www.npmjs.com/package/@cfdi/rfc"> <img src="https://raw.githubusercontent.com/MisaelMa/cards/main/packages/cfdi-rfc.png" alt="@cfdi/rfc" width="100%" /> </a> </td> <td align="center" width="33%"> <a href="https://www.npmjs.com/package/@cfdi/utils"> <img src="https://raw.githubusercontent.com/MisaelMa/cards/main/packages/cfdi-utils.png" alt="@cfdi/utils" width="100%" /> </a> </td> </tr> <tr> <td align="center" width="33%"> <a href="https://www.npmjs.com/package/@clir/openssl"> <img src="https://raw.githubusercontent.com/MisaelMa/cards/main/packages/clir-openssl.png" alt="@clir/openssl" width="100%" /> </a> </td> <td align="center" width="33%"> <a href="https://www.npmjs.com/package/@saxon-he/cli"> <img src="https://raw.githubusercontent.com/MisaelMa/cards/main/packages/saxon-he-cli.png" alt="@saxon-he/cli" width="100%" /> </a> </td> <td align="center" width="33%"> </td> </tr> </table> --- ## Por que @cfdi/xml? <table> <tr> <td width="25%" align="center"><b>Sin Java</b><br/><sub>Motor XSLT nativo en Node.js con <code>@cfdi/transform</code>. Saxon-HE disponible como alternativa.</sub></td> <td width="25%" align="center"><b>TypeScript nativo</b><br/><sub>Tipos estrictos, autocompletado y seguridad de tipos en todo el flujo de facturacion.</sub></td> <td width="25%" align="center"><b>SAT 4.0 compliant</b><br/><sub>Cumple con Anexo 20 del SAT. Genera XML valido contra esquemas XSD oficiales.</sub></td> <td width="25%" align="center"><b>Modular</b><br/><sub>Usa solo lo que necesitas. Cada paquete del ecosistema es independiente.</sub></td> </tr> </table> --- ## Quick Start ### 1. Instalar ```bash npm install @cfdi/xml ``` ### 2. Crear y firmar un CFDI ```ts import { CFDI, Emisor, Receptor, Concepto, Impuestos } from '@cfdi/xml'; const cfdi = new CFDI({ xslt: { path: './resources/4.0/cadenaoriginal.xslt' }, }); cfdi.comprobante({ Serie: 'A', Folio: '1', Fecha: '2024-01-15T10:30:00', FormaPago: '01', MetodoPago: 'PUE', TipoDeComprobante: 'I', LugarExpedicion: '64000', Moneda: 'MXN', SubTotal: '1000.00', Total: '1160.00', }); cfdi.emisor( new Emisor({ Rfc: 'AAA010101AAA', Nombre: 'Empresa SA de CV', RegimenFiscal: '601', }) ); cfdi.receptor( new Receptor({ Rfc: 'BBB020202BBB', Nombre: 'Cliente SA de CV', UsoCFDI: 'G03', DomicilioFiscalReceptor: '64000', RegimenFiscalReceptor: '601', }) ); const concepto = new Concepto({ ClaveProdServ: '01010101', Cantidad: '1', ClaveUnidad: 'E48', Descripcion: 'Servicio de consultoria', ValorUnitario: '1000.00', Importe: '1000.00', ObjetoImp: '02', }); concepto.setTraslado({ Base: '1000.00', Impuesto: '002', TipoFactor: 'Tasa', TasaOCuota: '0.160000', Importe: '160.00', }); cfdi.concepto(concepto); const impuestos = new Impuestos({ TotalImpuestosTrasladados: '160.00', }); impuestos.traslados({ Impuesto: '002', TipoFactor: 'Tasa', TasaOCuota: '0.160000', Importe: '160.00', Base: '1000.00', }); cfdi.impuesto(impuestos); ``` ### 3. Certificar y sellar ```ts cfdi.certificar('./certs/certificado.cer'); await cfdi.sellar('./certs/llave.key', '12345678a'); ``` ### 4. Obtener el XML ```ts const xml = cfdi.getXmlCdfi(); ``` --- ## Flujo de firmado ```mermaid graph LR A[XML CFDI] --> B[Cadena Original] B --> C[Sello Digital] C --> D[CFDI Firmado] B -- "@cfdi/transform (default)" --> B B -. "@saxon-he/cli (opcional)" .-> B C -- ".key + SHA-256" --> C A -- ".cer" --> D ``` --- ## Output de ejemplo ```xml <?xml version="1.0" encoding="utf-8"?> <cfdi:Comprobante xmlns:cfdi="http://www.sat.gob.mx/cfd/4" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sat.gob.mx/cfd/4 http://www.sat.gob.mx/sitio_internet/cfd/4/cfdv40.xsd" Version="4.0" Serie="A" Folio="1" Fecha="2024-01-15T10:30:00" FormaPago="01" MetodoPago="PUE" TipoDeComprobante="I" Moneda="MXN" SubTotal="1000.00" Total="1160.00" LugarExpedicion="64000" NoCertificado="20001000000300022815" Certificado="MIIFxTCCA62g..." Sello="GshKsM2IjAR0+7..."> <cfdi:Emisor Rfc="AAA010101AAA" Nombre="Empresa SA de CV" RegimenFiscal="601"/> <cfdi:Receptor Rfc="BBB020202BBB" Nombre="Cliente SA de CV" UsoCFDI="G03" DomicilioFiscalReceptor="64000" RegimenFiscalReceptor="601"/> <cfdi:Conceptos> <cfdi:Concepto ClaveProdServ="01010101" Cantidad="1" ClaveUnidad="E48" Descripcion="Servicio de consultoria" ValorUnitario="1000.00" Importe="1000.00" ObjetoImp="02"> <cfdi:Impuestos> <cfdi:Traslados> <cfdi:Traslado Base="1000.00" Impuesto="002" TipoFactor="Tasa" TasaOCuota="0.160000" Importe="160.00"/> </cfdi:Traslados> </cfdi:Impuestos> </cfdi:Concepto> </cfdi:Conceptos> </cfdi:Comprobante> ``` --- ## Motor XSLT La cadena original se genera mediante transformacion XSLT. Se soportan dos motores: | Motor | Paquete | Requiere Java | Default | | ------------------- | ----------------- | ------------- | ------- | | **@cfdi/transform** | `@cfdi/transform` | No | Si | | **Saxon-HE** | `@saxon-he/cli` | Si | No | ```ts // Default: @cfdi/transform (pure Node.js) const cfdi = new CFDI({ xslt: { path: './resources/4.0/cadenaoriginal.xslt' }, }); // Saxon-HE: requiere Java + Saxon instalado const cfdiSaxon = new CFDI({ xslt: { path: './resources/4.0/cadenaoriginal.xslt' }, saxon: { binary: 'transform' }, }); ``` --- ## API | Metodo | Descripcion | | ---------------------------- | ----------------------------------------------------- | | `comprobante(attr)` | Atributos del comprobante (Serie, Folio, Fecha, etc.) | | `emisor(emisor)` | Datos del emisor | | `receptor(receptor)` | Datos del receptor | | `concepto(concepto)` | Agrega un concepto (puede llamarse multiples veces) | | `impuesto(impuesto)` | Resumen de impuestos del documento | | `certificar(cerpath)` | Carga certificado `.cer` | | `sellar(keyfile, password)` | Genera cadena original y sello digital | | `getXmlCdfi()` | Retorna el XML firmado | | `getJsonCdfi()` | Retorna representacion JSON | | `saveFile(file, path, name)` | Guarda archivo XML | | `generarCadenaOriginal()` | Genera cadena original via XSLT | | `setDebug(debug)` | Activa/desactiva modo debug | --- ## Configuracion ```ts interface Config { debug?: boolean; compact?: boolean; xslt?: { path: string }; // Ruta al archivo XSLT (requerido para sellar) saxon?: { binary: string }; // Si se omite, usa @cfdi/transform schema?: { path: string }; } ``` --- ## Soporte <p> <a href="https://github.com/MisaelMa/node-cfdi/issues"> <img src="https://img.shields.io/badge/GitHub-Issues-181717?style=for-the-badge&logo=github" alt="issues" /> </a> <a href="https://github.com/MisaelMa/node-cfdi/discussions"> <img src="https://img.shields.io/badge/GitHub-Discussions-181717?style=for-the-badge&logo=github" alt="discussions" /> </a> <a href="https://www.npmjs.com/package/@cfdi/xml"> <img src="https://img.shields.io/badge/npm-@cfdi/xml-cb3837?style=for-the-badge&logo=npm" alt="npm" /> </a> </p> --- ## Autor <p align="center"> <a href="https://github.com/MisaelMa"> <img src="https://raw.githubusercontent.com/MisaelMa/cards/main/author.png" alt="Amir Misael Marin Coh" width="100%" /> </a> </p> ## Licencia [MIT](../../LICENSE)