@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
Markdown
<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
<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)