alfredomejia/cfdi-php
Composer 安装命令:
composer require alfredomejia/cfdi-php
包简介
Librería PHP escalable para manejo de CFDI con patrones de diseño modernos.
README 文档
README
📋 Descripción
CFDI PHP es una librería moderna y escalable para generar Comprobantes Fiscales Digitales por Internet (CFDI) en PHP. Implementa patrones de diseño avanzados para ser mantenible, extensible y fácil de usar.
✨ Características Principales
- ✅ CFDI 4.0: Generación de facturas electrónicas estándar
- ✅ Complemento de Pagos 2.0: Para recibos de pago y abonos
- ✅ Complemento de Carta Porte 3.1: Para transporte de mercancías
- ✅ Complemento de Nómina 1.2: Para nóminas y recursos humanos
- ✅ Validación Finkok: Integración con servicios de validación automática
- ✅ Arquitectura Moderna: Builder Pattern, Factory Pattern, Strategy Pattern
- ✅ XML Válido: Generación conforme a esquemas del SAT
- ✅ Manejo de Errores: Validaciones robustas y mensajes claros
🏗️ Arquitectura de la Librería
🔧 Patrones de Diseño Implementados
- Builder Pattern: Construcción fluida y expresiva de CFDIs
- Factory Pattern: Creación centralizada de diferentes tipos
- Strategy Pattern: Complementos pluggeables y extensibles
- Service Layer: Servicios especializados y reutilizables
- Dependency Injection: Flexibilidad y testing mejorado
📁 Estructura del Proyecto
cfdi-php/
├── src/
│ ├── CFDIFactory.php # 🎯 Punto de entrada principal
│ ├── Builders/ # 🔧 Constructores fluidos
│ │ ├── AbstractCFDIBuilder.php
│ │ ├── CFDI40Builder.php
│ │ ├── PagosBuilder.php
│ │ ├── CartaPorteBuilder.php
│ │ └── NominaBuilder.php
│ ├── Services/ # 🛠️ Servicios especializados
│ │ ├── FinkokService.php
│ │ ├── ValidationService.php
│ │ ├── XMLGeneratorService.php
│ │ └── FileService.php
│ ├── Models/ # 📋 Modelos de datos
│ │ ├── CFDIData.php
│ │ ├── Comprobante.php
│ │ ├── Emisor.php
│ │ └── Receptor.php
│ ├── Contracts/ # 📜 Interfaces
│ │ ├── CFDIBuilderInterface.php
│ │ ├── ValidationServiceInterface.php
│ │ └── ComplementStrategyInterface.php
│ ├── Strategies/ # 🔌 Complementos pluggeables
│ │ ├── Pagos/
│ │ ├── CartaPorte/
│ │ ├── Nomina/
│ │ └── ComercioExterior/
│ ├── Exceptions/ # ⚠️ Excepciones personalizadas
│ │ ├── CFDIException.php
│ │ └── ValidationException.php
│ └── Legacy/ # 🔄 Clases originales (compatibilidad)
│ ├── CFDI40.php
│ ├── CartaPorte31.php
│ ├── Nomina12.php
│ └── RecepcionPagos.php
├── examples/ # 📚 Ejemplos de uso
│ ├── ejemplo_cfdi_basico.php
│ ├── ejemplo_pagos.php
│ ├── ejemplo_cartaporte.php
│ ├── ejemplo_nomina.php
│ └── README.md
├── composer.json # 📦 Dependencias
└── README.md # 📖 Esta documentación
🚀 Instalación
Requisitos Previos
- PHP 7.4 o superior
- Composer instalado
- Extensiones PHP:
ext-soap(para comunicación con Finkok)ext-dom(para generación de XML)ext-libxml(para manipulación de XML)
Instalación
- Clonar el repositorio:
git clone https://github.com/AlfredoMejia/cfdi-php.git
cd cfdi-php
- Instalar dependencias:
composer install
- Verificar extensiones:
php -m | grep -E "(soap|dom)"
🔧 Configuración
Credenciales de Finkok
Para usar las validaciones automáticas, necesitas una cuenta en Finkok:
$finkokUser = "tu_usuario@finkok.com.mx"; $finkokPass = "tu_password";
Configuración del Entorno
// Habilitar reporte de errores error_reporting(E_ALL); ini_set('display_errors', 1); // Configurar zona horaria date_default_timezone_set('America/Mexico_City');
📖 Guía de Uso
🎯 Punto de Entrada Principal
La librería se usa a través de CFDIFactory, que es el punto de entrada principal:
<?php require_once 'vendor/autoload.php'; use AlfredoMejia\CfdiPhp\CFDIFactory; $factory = new CFDIFactory();
🧾 1. CFDI Básico 4.0
Uso Básico
$cfdi = $factory->createCFDI40Builder() ->comprobante( noCertificado: '30001000000500003416', serie: 'A', folio: '12345', fecha: '2024-01-15T10:30:00', subTotal: '1000.00', total: '1160.00', lugarExpedicion: '06500' ) ->emisor( rfc: 'XAXX010101000', nombre: 'EMPRESA DEMO SA DE CV', regimenFiscal: '601' ) ->receptor( rfc: 'XEXX010101000', nombre: 'CLIENTE DEMO SA DE CV', regimenFiscalReceptor: '601', usoCFDI: 'G01', domicilioFiscalReceptor: '06500' ) ->concepto( claveProdServ: '84111506', cantidad: '1.00', claveUnidad: 'H87', descripcion: 'Servicio de consultoría', valorUnitario: '1000.00', importe: '1000.00', objetoImp: '02' ) ->impuestosTotales() ->trasladoTotal( base: '1000.00', impuesto: '002', tipoFactor: 'Tasa', tasaOCuota: '0.160000', importe: '160.00' ) ->build();
Procesamiento Completo
$result = $factory->processCFDI( cfdiData: $cfdi, finkokUser: $finkokUser, finkokPassword: $finkokPass, filePath: './output/', fileName: 'FACTURA_001' ); if ($result->isSuccess()) { echo "✅ CFDI generado exitosamente\n"; echo "📄 Archivo: " . $result->getFilePath() . "\n"; } else { echo "❌ Error: " . implode(', ', $result->getErrors()) . "\n"; }
💰 2. Complemento de Pagos 2.0
Uso del Builder de Pagos
$cfdi = $factory->createPagos() ->comprobante( noCertificado: '30001000000500003416', serie: 'P', folio: '001', fecha: '2024-01-15T10:30:00', subTotal: '0.00', total: '0.00', lugarExpedicion: '06500', tipoDeComprobante: 'P' // Importante: P = Pago ) ->emisor( rfc: 'XAXX010101000', nombre: 'EMPRESA PAGOS SA DE CV', regimenFiscal: '601' ) ->receptor( rfc: 'XEXX010101000', nombre: 'CLIENTE PAGOS SA DE CV', regimenFiscalReceptor: '605', usoCFDI: 'CP01', domicilioFiscalReceptor: '06500' ) ->concepto( claveProdServ: '84111506', cantidad: '1.00', claveUnidad: 'E48', descripcion: 'Pago por servicios', valorUnitario: '0.00', // Puede ser 0.00 para tipo P importe: '0.00', // Puede ser 0.00 para tipo P objetoImp: '01' ) ->pago( fechaPago: '2024-01-15', formaDePagoP: '01', monto: '1000.00', monedaP: 'MXN', tipoCambioP: '1.00' ) ->doctoRelacionado( idDocumento: 'uuid-del-documento', monedaDR: 'MXN', metodoDePagoDR: 'PPD', numParcialidad: '1', impSaldoAnt: '1000.00', impPagado: '1000.00', impSaldoInsoluto: '0.00' ) ->trasladoDR( base: '1000.00', impuesto: '002', tipoFactor: 'Tasa', tasaOCuota: '0.160000', importe: '160.00' ) ->impuestosTotalesDR( totalImpuestosRetenidos: '0.00', totalImpuestosTrasladados: '160.00' ) ->build();
🚛 3. Complemento de Carta Porte 3.1
Uso del Builder de Carta Porte
$cfdi = $factory->createCartaPorte() ->comprobante( noCertificado: '30001000000500003416', serie: 'CP', folio: '001', fecha: '2024-01-15T10:30:00', subTotal: '1000.00', total: '1160.00', lugarExpedicion: '06500' ) ->emisor( rfc: 'XAXX010101000', nombre: 'EMPRESA TRANSPORTE SA DE CV', regimenFiscal: '601' ) ->receptor( rfc: 'XEXX010101000', nombre: 'CLIENTE TRANSPORTE SA DE CV', regimenFiscalReceptor: '601', usoCFDI: 'G01', domicilioFiscalReceptor: '06500' ) ->concepto( claveProdServ: '78101800', cantidad: '1.00', claveUnidad: 'H87', descripcion: 'Servicio de transporte de mercancía', valorUnitario: '1000.00', importe: '1000.00', objetoImp: '02' ) ->impuestosTotales() ->trasladoTotal( base: '1000.00', impuesto: '002', tipoFactor: 'Tasa', tasaOCuota: '0.160000', importe: '160.00' ) ->transporteInternacional('No') ->origen( idUbicacion: 'ORIGEN001', rfcRemitente: 'XAXX010101000', fechaHora: '2024-01-15T08:00:00', domicilio: [ 'estado' => 'CDMX', 'pais' => 'MEX', 'codigoPostal' => '06000', 'calle' => 'Av. Principal', 'numeroExterior' => '123', 'colonia' => 'Centro', 'municipio' => 'Cuauhtémoc' ] ) ->destino( idUbicacion: 'DESTINO001', rfcDestinatario: 'XEXX010101000', fechaHora: '2024-01-15T18:00:00', domicilio: [ 'estado' => 'CDMX', 'pais' => 'MEX', 'codigoPostal' => '07000', 'calle' => 'Calle Secundaria', 'numeroExterior' => '456', 'colonia' => 'Industrial', 'municipio' => 'Gustavo A. Madero' ] ) ->mercancia( bienesTransp: '10101501', descripcion: 'Productos manufacturados', cantidad: '1.00', claveUnidadPeso: 'KGM', pesoEnKg: '50.00' ) ->totalesMercancias( pesoBrutoTotal: '50.00', unidadPeso: 'KGM', numTotalMercancias: '1' ) ->operador('XEXX010101000', 'OPERADOR TRANSPORTE SA DE CV') ->build();
👥 4. Complemento de Nómina 1.2
Uso del Builder de Nómina
$cfdi = $factory->createNomina() ->comprobante( noCertificado: '30001000000500003416', serie: 'N', folio: '001', fecha: '2024-01-15T08:00:00', subTotal: '5000.00', total: '5000.00', lugarExpedicion: '06500' ) ->emisor( rfc: 'XAXX010101000', nombre: 'EMPRESA RECURSOS HUMANOS SA DE CV', regimenFiscal: '601' ) ->receptor( rfc: 'XEXX010101000', nombre: 'EMPLEADO EJEMPLO', regimenFiscalReceptor: '605', usoCFDI: 'CN01', domicilioFiscalReceptor: '06500' ) ->concepto( claveProdServ: '84111506', cantidad: '1.00', claveUnidad: 'E48', descripcion: 'Pago de nómina', valorUnitario: '5000.00', importe: '5000.00', objetoImp: '01' ) ->tipoNomina('O') ->fechasPago( fechaPago: '2024-01-15', fechaInicialPago: '2024-01-01', fechaFinalPago: '2024-01-15', numDiasPagados: '15' ) ->emisorNomina([ 'curp' => 'XEXX010101HDFXXXA8', 'registroPatronal' => 'O1234567890' ]) ->receptorNomina([ 'curp' => 'XEXX010101HDFXXXA8', 'numSeguridadSocial' => '12345678901', 'fechaInicioRelLaboral' => '2020-01-01', 'antiguedad' => 'P4Y', 'tipoContrato' => '01', 'sindicalizado' => 'No', 'tipoJornada' => '01', 'tipoRegimen' => '02', 'numEmpleado' => '001', 'departamento' => 'ADMINISTRATIVO', 'puesto' => 'AUXILIAR', 'riesgoPuesto' => '1', 'periodicidadPago' => '04', 'banco' => '012', 'cuentaBancaria' => '012345678901234567', 'salarioBaseCotApor' => '5000.00', 'salarioDiarioIntegrado' => '333.33' ]) ->percepciones([ 'totalSueldos' => '5000.00', 'totalSeparacionIndemnizacion' => '0.00', 'totalJubilacionPensionRetiro' => '0.00', 'totalGravado' => '5000.00', 'totalExento' => '0.00' ]) ->deducciones([ 'totalOtrasDeducciones' => '0.00', 'totalImpuestosRetenidos' => '0.00' ]) ->build();
🔍 Servicios Disponibles
1. Validación de Credenciales
$credentialsResult = $factory->validateCredentials($finkokUser, $finkokPass); if ($credentialsResult->isValid()) { echo "✅ Credenciales válidas\n"; } else { echo "❌ Credenciales inválidas: " . implode(', ', $credentialsResult->getErrors()) . "\n"; }
2. Validación de RFC
$rfcResult = $factory->validateRFC($finkokUser, $finkokPass, 'XAXX010101000'); if ($rfcResult->isValid()) { echo "✅ RFC válido y activo\n"; } else { echo "❌ RFC inválido: " . implode(', ', $rfcResult->getErrors()) . "\n"; }
3. Generación de XML Solo
$xml = $factory->generateXML($cfdiData); echo "XML generado: " . $xml;
4. Guardado de Archivo Solo
$path = $factory->saveXML($xml, './output/', 'mi_cfdi'); echo "Archivo guardado en: " . $path;
📊 Tipos de Comprobante
| Tipo | Descripción | Uso |
|---|---|---|
I |
Ingreso | Facturas de venta |
E |
Egreso | Notas de crédito |
T |
Traslado | Transporte de mercancías |
N |
Nómina | Pagos de nómina |
P |
Pago | Recibos de pago |
🔧 Configuración Avanzada
Múltiples Conceptos
$cfdi = $factory->createCFDI40Builder() ->comprobante(/* ... */) ->emisor(/* ... */) ->receptor(/* ... */) // Primer concepto ->concepto( claveProdServ: '84111506', cantidad: '2.00', claveUnidad: 'H87', descripcion: 'Consultoría Básica', valorUnitario: '500.00', importe: '1000.00', objetoImp: '02' ) ->traslado('1000.00', '002', 'Tasa', '0.160000', '160.00') // Segundo concepto ->concepto( claveProdServ: '84111507', cantidad: '1.00', claveUnidad: 'H87', descripcion: 'Consultoría Especializada', valorUnitario: '1500.00', importe: '1500.00', objetoImp: '02' ) ->traslado('1500.00', '002', 'Tasa', '0.160000', '240.00') // Impuestos totales ->impuestosTotales(null, '400.00') ->trasladoTotal('2500.00', '002', 'Tasa', '0.160000', '400.00') ->build();
Impuestos por Concepto
$cfdi = $factory->createCFDI40Builder() ->comprobante(/* ... */) ->emisor(/* ... */) ->receptor(/* ... */) ->concepto(/* ... */) ->traslado('1000.00', '002', 'Tasa', '0.160000', '160.00') // IVA ->retencion('1000.00', '001', 'Tasa', '0.100000', '100.00') // ISR ->build();
📁 Ejemplos de Uso
Ejecutar Ejemplos
# CFDI básico php examples/ejemplo_cfdi_basico.php # Complemento de Pagos php examples/ejemplo_pagos.php # Complemento de Carta Porte php examples/ejemplo_cartaporte.php # Complemento de Nómina php examples/ejemplo_nomina.php
Archivos Generados
Todos los ejemplos generan archivos XML en la carpeta examples/output/:
CFDI_BASICO.xmlCFDI_PAGOS.xmlCFDI_CARTA_PORTE.xmlCFDI_NOMINA.xml
🔍 Validaciones y Errores
Validaciones Automáticas
- Credenciales Finkok: Verificación de usuario y contraseña
- RFC Emisor: Estado activo en la cuenta
- Datos CFDI: Validación de campos requeridos
- Complementos: Validación específica por tipo
Manejo de Errores
$result = $factory->processCFDI(/* ... */); if (!$result->isSuccess()) { echo "❌ Error: " . $result->getMessage() . "\n"; if ($result->getErrors()) { echo "🔍 Errores detallados:\n"; foreach ($result->getErrors() as $error) { echo " - $error\n"; } } }
Errores Comunes
Error de Credenciales
❌ Error: Credenciales inválidas
Solución: Verificar credenciales de Finkok.
RFC Inactivo
❌ Error: El RFC emisor se encuentra inactivo en la cuenta
Solución: Activar RFC en cuenta de Finkok.
Error de Validación
❌ Error: El importe debe ser mayor a cero en el concepto 1
Solución: Para tipo de comprobante 'P' (Pago), el importe puede ser 0.00.
📞 Soporte
Recursos de Ayuda
- Email: alfredo.mejia@finkok.com
- Documentación: Este README y ejemplos en
/examples/
Recursos Externos
- SAT: www.sat.gob.mx
- Finkok: www.finkok.com
- GitHub: Repositorio del proyecto
🔄 Historial de Versiones
- v1.0.0: CFDI 4.0 básico
- v1.1.0: Recepción de Pagos
- v1.2.0: Carta Porte 3.1
- v1.3.0: Nómina 1.2
- v1.4.0: Nueva arquitectura escalable
- v2.0.0: Arquitectura moderna con patrones de diseño
📝 Notas Importantes
- Credenciales: Siempre usa credenciales válidas de Finkok
- Validación: Todas las clases incluyen validaciones automáticas
- XML: Los archivos se generan conforme a esquemas del SAT
alfredomejia/cfdi-php 适用场景与选型建议
alfredomejia/cfdi-php 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 1 次下载、GitHub Stars 达 0, 最近一次更新时间为 2025 年 08 月 01 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「xml」 「mexico」 「facturacion」 「sat」 「cfdi」 「finkok」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 alfredomejia/cfdi-php 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 alfredomejia/cfdi-php 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 alfredomejia/cfdi-php 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Load DOM document safety
Servicio Postal Mexicano (Sepomex) not official laravel library
Cliente para realizar la integración con los servicios web de LibreDTE desde PHP.
Servicio Postal Mexicano PHP Library (Unofficial)
Added a method to Laravel response for handling xml response and also converting Eloquent return to XML.
Uses reflection to map XML to PHP objects.
统计信息
- 总下载量: 1
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 30
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2025-08-01