PHPackages                             jiagbrody/laravel-factura-mx - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Payment Processing](/categories/payments)
4. /
5. jiagbrody/laravel-factura-mx

ActiveLibrary[Payment Processing](/categories/payments)

jiagbrody/laravel-factura-mx
============================

Librería para la facturación en México, creación de facturas y CFDI.

v2.1.0(1mo ago)21381[2 PRs](https://github.com/jiagbrody/laravel-factura-mx/pulls)MITPHPPHP ^8.2

Since Nov 30Pushed 9mo ago1 watchersCompare

[ Source](https://github.com/jiagbrody/laravel-factura-mx)[ Packagist](https://packagist.org/packages/jiagbrody/laravel-factura-mx)[ Docs](https://github.com/jiagbrody/laravel-factura-mx)[ RSS](/packages/jiagbrody-laravel-factura-mx/feed)WikiDiscussions main Synced 2w ago

READMEChangelog (3)Dependencies (30)Versions (7)Used By (0)

Laravel Factura MX — Facturación electrónica CFDI 4.0 para México
=================================================================

[](#laravel-factura-mx--facturación-electrónica-cfdi-40-para-méxico)

[![Latest Version on Packagist](https://camo.githubusercontent.com/a47345c128abce18db03347a0fcdfe1f6a91825729e0aac122dfe151b48c8076/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6a69616762726f64792f6c61726176656c2d666163747572612d6d782e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/jiagbrody/laravel-factura-mx)[![GitHub Tests Action Status](https://camo.githubusercontent.com/c610c037724210e2b749d710ce63f2a827d2226ebc3f34c74f1e837443c34951/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6a69616762726f64792f6c61726176656c2d666163747572612d6d782f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/jiagbrody/laravel-factura-mx/actions?query=workflow%3Arun-tests+branch%3Amain)[![GitHub Code Style Action Status](https://camo.githubusercontent.com/2ab0b338c04995f9f6ed1ad56911ddd32aa2ccde0adc4359e2f58fe7c947859e/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6a69616762726f64792f6c61726176656c2d666163747572612d6d782f6669782d7068702d636f64652d7374796c652d6973737565732e796d6c3f6272616e63683d6d61696e266c6162656c3d636f64652532307374796c65267374796c653d666c61742d737175617265)](https://github.com/jiagbrody/laravel-factura-mx/actions?query=workflow%3A%22Fix+PHP+code+style+issues%22+branch%3Amain)[![Total Downloads](https://camo.githubusercontent.com/0ea3c64596f13aa1b381ac3406e9f24f96a2e46443cb571a4935dece360d07fb/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6a69616762726f64792f6c61726176656c2d666163747572612d6d782e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/jiagbrody/laravel-factura-mx)

Paquete de Laravel para la facturación electrónica en México (CFDI **4.0**): construcción del comprobante, sellado con el CSD del emisor, **timbrado** ante un PAC (Finkok), cancelación, consulta de estatus ante el SAT, recuperación de XML timbrados y generación del PDF legible con el QR oficial de verificación del SAT.

La documentación está en español porque es el idioma natural de los tecnicismos del SAT (Anexo 20).

📖 **[Mapa funcional de la librería](docs/mapa-funcional.md)** — todo lo que hace y con qué método: ciclo de vida del CFDI, las 8 áreas de funcionalidad, matriz de cobertura por tipo de comprobante, excepciones y configuración.

Características
---------------

[](#características)

- Construcción fluida del CFDI 4.0 (ingreso, egreso/nota de crédito y complemento de pago) sobre [`eclipxe/cfdiutils`](https://github.com/eclipxe13/CfdiUtils).
- **Validación local** (XSD + reglas SAT) antes de enviar al PAC — los CFDI malformados no queman intentos de timbrado.
- Timbrado con Finkok resistente a sus estados no documentados: `Comprobante timbrado previamente` (307), timbrado asíncrono en cola, recuperación del resultado original vía `stamped` — todo normalizado en una sola respuesta (`getCheckProcess()`).
- Guard anti-doble-timbrado y guard de la ventana de 72 horas del SAT.
- Errores como **excepciones tipadas** (`FacturaMxException` y subclases) — seguras para colas y comandos, nunca `abort()`.
- Logs SOAP por operación en `storage/logs/cfdi_finkok_*.log` (con la contraseña del PAC redactada), también cuando la llamada falla.
- Persistencia post-timbrado opcional (estatus, UUID, XML, PDF, limpieza de borradores) o control total desde tu aplicación.
- Catálogos oficiales del SAT 4.0 servidos desde una base SQLite de solo lectura.

Requisitos
----------

[](#requisitos)

- PHP ^8.2 con `ext-soap` y `ext-intl`
- Laravel (el paquete se desarrolla con Orchestra Testbench)
- Una cuenta con el PAC ([Finkok](https://www.finkok.com)) — demo o producción
- El CSD del emisor (`.cer`, `.key` y contraseña) emitido por el SAT

Instalación
-----------

[](#instalación)

```
composer require jiagbrody/laravel-factura-mx
```

Publica el archivo de configuración:

```
php artisan vendor:publish --tag="jiagbrody-laravel-factura-mx-config"
```

Las migraciones se cargan directamente desde el paquete (no necesitas publicarlas):

```
php artisan migrate
```

> Los nombres de las tablas (prefijo `jiagbrody_lfmx_*`) son configurables en `table_names`, **solo antes de correr las migraciones**.

Configuración esencial
----------------------

[](#configuración-esencial)

```
FACTURA_MX_FINKOK_USER=tu_usuario_finkok
FACTURA_MX_FINKOK_PASSWORD=tu_password_finkok
```

ClaveQué es`pac_environment_production``false` = demo de Finkok, `true` = producción. Las URLs oficiales de ambos entornos vienen incluidas.`sat_files_path`Carpeta (NO pública) con los CSD de los emisores. Cada emisor se registra en la tabla `invoice_companies` con las rutas de su `.cer`/`.key`.`sat_local_resource_path`Copia local de los XSD/XSLT del SAT. Se descargan automáticamente la primera vez que se validan/sellan comprobantes.`sqlite-sat-catalogs`Ruta de la base SQLite con los catálogos oficiales del SAT 4.0 (régimen fiscal, usos, formas de pago, monedas…).`filesystem_disk` / `invoices_files_path`Dónde se guardan XML/PDF. Default: disco privado `local` — los CFDI contienen datos personales.`pre_validate_cfdi`Valida el CFDI localmente al construirlo (default `true`).`stamp_draft_max_age_hours`Bloquea el envío de borradores con `Fecha` más vieja que N horas (default `71`; el SAT rechaza a las 72).`persist_stamp_result`Si `true` (default), `build()` persiste todo al timbrar. Ponlo en `false` si tu app tiene su propia orquestación de persistencia.`generate_pdf_on_stamp` / `pdf_invoice_view`Generación del PDF legible y vista Blade a usar (copia la default con otro nombre para personalizarla).`pac_soap_timeout_seconds`Timeout de cada llamada SOAP al PAC (default 30).Uso
---

[](#uso)

### Crear un CFDI de ingreso (borrador sellado)

[](#crear-un-cfdi-de-ingreso-borrador-sellado)

```
use JiagBrody\LaravelFacturaMx\Facades\LaravelFacturaMx;
use JiagBrody\LaravelFacturaMx\Models\InvoiceCompany;
use JiagBrody\LaravelFacturaMx\Sat\InvoiceSatData\{ComprobanteAtributos, ReceptorAtributos, ConceptoAtributos, ImpuestoTrasladoAtributos};

$company = InvoiceCompany::find(1); // el emisor (con su CSD registrado)

$voucher = LaravelFacturaMx::create()->ingreso()->custom($company);

$atributos = new ComprobanteAtributos;   // Fecha default: ahora, en default_timezone
$atributos->setSerie('A');
$atributos->setFolio('1');
$atributos->setFormaPago('01');
$atributos->setMetodoPago('PUE');
$atributos->setMoneda('MXN');
$atributos->setTipoDeComprobante('I');
$atributos->setExportacion('01');
$atributos->setLugarExpedicion('63732');
$voucher->addAtributos($atributos);

$receptor = new ReceptorAtributos;
$receptor->setRfc('XAXX010101000');
$receptor->setNombre('PUBLICO EN GENERAL');
$voucher->addReceptor($receptor);

// ... addConceptos(), addRelacionados(), addComplementoImpuestosLocales() ...

$invoice = $voucher->build()->createNewInvoice(); // valida, sella y persiste el borrador
```

### Timbrar

[](#timbrar)

```
$response = LaravelFacturaMx::invoiceStamper($invoice)->build();

if ($response->getCheckProcess()) {
    $uuid = $response->getUuid();   // UUID fiscal
    $xml = $response->getXml();     // XML timbrado
} else {
    $motivo = $response->getIncidenciaMensaje(); // incidencia del PAC (también se guarda en invoice_incidents)
}
```

Con `persist_stamp_result = true` (default), el timbrado exitoso deja la factura vigente con su CFDI, XML, PDF y sin borradores — en la misma llamada.

### Cancelar, estatus y recuperación

[](#cancelar-estatus-y-recuperación)

```
use JiagBrody\LaravelFacturaMx\Enums\InvoiceCfdiCancelTypeEnum;

// Cancelación ante el SAT (persiste el acuse cuando procede)
$cancel = LaravelFacturaMx::invoiceCanceller($invoice)
    ->setCancelTypeEnum(InvoiceCfdiCancelTypeEnum::NEW_NOT_EXECUTED)
    ->build();

// Estatus del CFDI ante el SAT (total = string EXACTO impreso en el CFDI)
$status = LaravelFacturaMx::status()
    ->setInvoice($invoice)
    ->setReceptorRfc('XAXX010101000')
    ->setTotal('612.90')
    ->build();
// $status->estado, $status->esCancelable, $status->invoiceStatusEnum (null si el SAT no lo reconoce)

// Recuperar el XML timbrado (get_xml y, si el PAC no lo indexa, fallback vía "stamped")
$xml = LaravelFacturaMx::RecoveryCfdiXmlFile()->setInvoice($invoice)->build();
```

### Manejo de errores

[](#manejo-de-errores)

Todo fallo del paquete lanza `JiagBrody\LaravelFacturaMx\Exceptions\FacturaMxException` o una subclase:

ExcepciónCuándo`PacConnectionException`Fallo de red/SOAP con el PAC. **Reintentable** sin riesgo de duplicar timbres.`PacStampInProgressException`El PAC sigue procesando el timbrado asíncrono; reintenta en unos segundos.`PacUnexpectedResponseException`Respuesta con estructura desconocida; revisa el log SOAP.`InvoiceAlreadyStampedException`La factura ya tiene CFDI; se evitó un doble timbrado.`InvoiceNotStampedException`La operación (cancelar/estatus/recuperar) requiere una factura timbrada.`StaleCfdiDraftException`El borrador quedó fuera de la ventana de 72 h; regenera el CFDI.`CfdiPreValidationException`El CFDI no pasó la validación local (incluye la lista de errores).`InvoiceDocumentMissingException`Falta el XML de borrador (registro o archivo físico).Testing
-------

[](#testing)

```
composer test      # Pest
composer analyse   # PHPStan (larastan)
composer format    # Pint
```

Los tests que sellan un CFDI real se saltan si no encuentras el CSD de pruebas oficial del SAT (`EKU9003173C9`) en `sat_files_path` — ver `tests/Pest.php`. Los tests de contrato del PAC corren siempre: usan respuestas SOAP reales grabadas del demo de Finkok.

Checklist para producción
-------------------------

[](#checklist-para-producción)

1. `pac_environment_production => true` y credenciales productivas del PAC en `.env`.
2. CSD reales de los emisores en `sat_files_path` (carpeta fuera del acceso público).
3. `filesystem_disk` privado (los CFDI llevan datos personales).
4. Verifica en los primeros timbrados los logs `storage/logs/cfdi_finkok_*.log`.

Changelog / Contributing / Security
-----------------------------------

[](#changelog--contributing--security)

Ver [CHANGELOG](CHANGELOG.md), [CONTRIBUTING](CONTRIBUTING.md) y la [política de seguridad](../../security/policy).

Créditos y licencia
-------------------

[](#créditos-y-licencia)

- [J. Israel Alvarez G. (Brody)](https://github.com/jiagbrody)
- Construido sobre [eclipxe/cfdiutils](https://github.com/eclipxe13/CfdiUtils) y [phpcfdi/credentials](https://github.com/phpcfdi/credentials).

The MIT License (MIT). Ver [License File](LICENSE.md).

###  Health Score

42

—

FairBetter than 88% of packages

Maintenance73

Regular maintenance activity

Popularity16

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity60

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~478 days

Total

3

Last Release

35d ago

Major Versions

0.0.1 → v2.0.02026-07-14

### Community

Maintainers

![](https://www.gravatar.com/avatar/9873a4a6942651e2a3c86b6c5d1da11b65d55b56b70155e0827cffc9eb6bcff1?d=identicon)[Israel Alvarez](/maintainers/Israel%20Alvarez)

---

Top Contributors

[![jiagbrody](https://avatars.githubusercontent.com/u/6666512?v=4)](https://github.com/jiagbrody "jiagbrody (83 commits)")

---

Tags

laravelfacturacion-electronicafacturacionsatcfdimexicofacturabrodylaravel-factura-mxjiagbrodyjiag

###  Code Quality

TestsPest

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/jiagbrody-laravel-factura-mx/health.svg)

```
[![Health](https://phpackages.com/badges/jiagbrody-laravel-factura-mx/health.svg)](https://phpackages.com/packages/jiagbrody-laravel-factura-mx)
```

###  Alternatives

[rawilk/profile-filament-plugin

Profile &amp; MFA starter kit for filament.

3915.5k](/packages/rawilk-profile-filament-plugin)[linkxtr/laravel-qrcode

A clean, modern, and easy-to-use QR code generator for Laravel

3827.1k](/packages/linkxtr-laravel-qrcode)[harris21/laravel-fuse

Circuit breaker for Laravel queue jobs. Protect your workers from cascading failures.

46273.9k](/packages/harris21-laravel-fuse)[vormkracht10/laravel-mails

Laravel Mails can collect everything you might want to track about the mails that has been sent by your Laravel app.

25060.1k](/packages/vormkracht10-laravel-mails)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
