Skip to content

FEAT: v5.0.0 modernization - PHP 8.2+, strictly typed DTOs, enums & AI-ready DX - #60

Draft
macarthuror wants to merge 46 commits into
FacturAPI:mainfrom
Increde:main
Draft

macarthuror wants to merge 46 commits into
FacturAPI:mainfrom
Increde:main

Conversation

@macarthuror

Copy link
Copy Markdown

Propuesta para Facturapi PHP SDK v5.0.0:


Modernización Integral, Tipado Estricto y Experiencia de Desarrollo Lista para IA

Hola equipo de Facturapi,

Primero que nada, muchas gracias por su trabajo con Facturapi y su SDK oficial de PHP.

Desde la publicación de las versiones 4.x del SDK de Facturapi, el ecosistema de PHP ha dado un salto cualitativo gigantesco (adopción masiva de PHP 8.2+, Enums nativos, tipos de retorno estrictos, estándares PSR-18 y análisis estático riguroso).
Al mismo tiempo, el flujo de trabajo moderno de desarrollo ha cambiado radicalmente: hoy en día, una gran parte de los desarrolladores construyen integraciones asistidos por Inteligencia Artificial y Coding Agents (Cursor, GitHub Copilot, Claude Code, Antigravity, etc.).

Con esto en mente, hemos preparado esta propuesta integral para evolucionar el SDK a la versión 5.0.0, rediseñando su arquitectura para que sea:

  1. Robusta y fuertemente tipada (contratos explícitos, autocompletado en IDEs y cero incertidumbre de datos).
  2. Optimizada para el desarrollo con IA (contratos deterministas que evitan alucinaciones de parámetros y atributos del SAT).
  3. Agnóstica y moderna (desacoplada de Guzzle mediante PSR-18, compatible con servidores como FrankenPHP y Laravel Octane).
  4. Segura y mantenible a largo plazo (PHPStan Nivel 9 con 0 errores y suite moderna en Pest v3 con 139 tests).
  5. Amigable con código existente (implementación estratégica de \ArrayAccess en DTOs comunes).

🤝 Propuesta de Colaboración y Siguientes Pasos

Somos conscientes de que este es un Pull Request de gran escala (+22,000 líneas entre nuevos DTOs, Enums y tests). La intención es sumar al proyecto y brindar a los desarrolladores de PHP la mejor experiencia posible al facturar con Facturapi.

Estamos a su entera disposición para:

  • Crear una rama de release mayor (ej. v5.0 o next) para pruebas beta de la comunidad.
  • Resolver cualquier duda o ajustar detalles de estilo y nombres según la visión del equipo core.

¡Esperamos que esta propuesta sea de gran valor para Facturapi y para toda la comunidad de desarrolladores en México!

Con aprecio,
Arturo Ortega (@macarthuror) & el equipo de INCREDE (@Increde)


Principales Ventajas de la Versión 5.0

1. Diseñado para un Mundo de Desarrollo Asistido por IA

Cuando los desarrolladores o asistentes de IA interactúan con APIs complejas como CFDI 4.0 mediante arreglos asociativos sin esquema tipado, surgen problemas comunes:

En v5.0:

  • Todos los recursos cuentan con DTOs fuertemente tipados (src/Models/) generados directamente desde la especificación OpenAPI oficial de Facturapi.
  • Los catálogos clave del SAT ahora cuentan con Enums respaldados (Backed Enums) (PaymentForm, TaxType, etc.).
  • Los agentes y asistentes inteligentes ahora pueden inferir el 100% de las propiedades válidas de una factura, cliente o retención, permitiendo generar código sin errores de sintaxis ni fallos en tiempo de ejecución.

Problematica Actual

  • Alucinación de claves: Los LLMs suelen inventar nombres de llaves o confundir formatos del SAT (ej. payment_type en lugar de payment_form).
  • Falta de introspección: Las herramientas de IA y los analizadores estáticos no pueden verificar si una propiedad devuelta por la API realmente existe.

2. Experiencia de Desarrollo (DX) e IntelliSense en el IDE

Para no tener que estar consultando continuamente la documentación para saber qué campo viene en la respuesta o lidiar con errores.

// ❌ v4.x: Arreglos asociativos genéricos (Sin autocompletado, propenso a typos)
$customer = $facturapi->Customers->create([...]);
echo $customer['legal_name']; // ¿Era 'legal_name' o 'razon_social'? El IDE no lo sabe

// ✅ v5.0: DTOs fuertemente tipados con autocompletado nativo
$customer = $facturapi->customers()->create([...]);
echo $customer->legal_name; // Autocompletado inmediato en PhpStorm, VS Code y asistentes de código

3. Retrocompatibilidad Estratégica (\ArrayAccess)

Entendemos el impacto de un cambio mayor en código en producción. Por ello, hemos implementado \ArrayAccess en DTOs anidados frecuentes (como direcciones en CommonAddressProperties):

// ✅ Tu código legado que dependa de sintaxis de arreglo seguirá funcionando:
echo $customer->address['zip']; 

// ✅ O puedes usar la nueva sintaxis limpia orientada a objetos:
echo $customer->address->zip;

Además, los métodos que reciben catálogos aceptan tanto instancias de los nuevos Enums como strings crudos para no obligar a una refactorización masiva de payloads existentes:

// Ambas formas son 100% válidas en v5:
'payment_form' => \Facturapi\PaymentForm::EFECTIVO, // Recomendada (IDE & AI Friendly)
'payment_form' => '01',                             // Totalmente compatible

4. Cliente HTTP Desacoplado (Estándares PSR-18 y PSR-17)

En v4, el SDK estaba estrictamente amarrado a una versión fija de Guzzle. En v5:

  • Se implementa php-http/discovery para detectar automáticamente cualquier cliente HTTP PSR-18 disponible en el proyecto (Guzzle 7/8, Symfony HttpClient, Buzz, etc.).
  • Ya no se generan conflictos de dependencias en proyectos que utilicen versiones diferentes de Guzzle o clientes HTTP personalizados.
  • Soporte para inyección de clientes personalizados con configuración de proxies, reintentos o timeouts avanzados.

5. Arquitectura Stateless y Compatibilidad con Servidores Modernos

El SDK es 100% libre de estado compartido entre peticiones:

  • Compatible de forma nativa con FrankenPHP, Swoole, RoadRunner y Laravel Octane.
  • El cliente principal Facturapi puede registrarse de forma segura como un Singleton en contenedores de inyección de dependencias sin riesgo de fugas de memoria o fuga de datos entre inquilinos (cross-tenant bleed).

6. Jerarquía Granular de Excepciones Semánticas

Se reemplazó el lanzamiento genérico de \Exception por una jerarquía basada en FacturapiException, donde cada error HTTP o de transporte tiene su propia clase tipada:

  • ValidationException (HTTP 400 y 422 - Errores de validación de datos, formato o reglas del SAT)
  • AuthenticationException (HTTP 401 y 403 - API key faltante/inválida o permisos insuficientes)
  • NotFoundException (HTTP 404 - El recurso solicitado no existe)
  • RateLimitException (HTTP 429 - Límite de peticiones a la API excedido)
  • ServerException (HTTP 500+ - Errores internos de infraestructura de Facturapi)
  • NetworkException (Fallas de transporte y conectividad de red a nivel PSR-18)

Además, la clase base FacturapiException expone métodos de conveniencia para diagnosticar problemas rápidamente:

  • $e->getStatusCode(): Código HTTP de respuesta.
  • $e->getErrors(): Lista de errores devueltos por la API del SAT/Facturapi.
  • $e->getErrorCode(), $e->getErrorPath(), $e->getErrorLocation(): Detalles precisos del campo erróneo.
  • $e->getLogId(): Identificador único x-facturapi-log-id para rastrear peticiones con soporte técnico.
  • $e->getRawBody() y $e->getResponseHeaders(): Payload crudo y cabeceras completas recibidas.
    Esto permite a las aplicaciones capturar y reaccionar ante errores específicos de negocio con máxima precisión:
use Facturapi\Exceptions\AuthenticationException;
use Facturapi\Exceptions\NotFoundException;
use Facturapi\Exceptions\RateLimitException;
use Facturapi\Exceptions\ValidationException;

try {
    $invoice = $facturapi->invoices()->retrieve('inv_no_existe');
} catch (NotFoundException $e) {
    // Manejo específico cuando el recurso no existe (HTTP 404)
} catch (ValidationException $e) {
    // Errores de validación del SAT / Facturapi (HTTP 400 / 422)
    $errors = $e->getErrors();
    $field = $e->getErrorPath();
} catch (RateLimitException $e) {
    // Esperar y reintentar (HTTP 429)
} catch (AuthenticationException $e) {
    // Problemas con la API Key (HTTP 401 / 403)
}

7. Suite de Pruebas Moderna (Pest v3) y PHPStan Nivel 9

Para garantizar total estabilidad y confianza al migrar:

  • Pest v3: Se migró y amplió la suite de pruebas unitarias y funcionales a Pest, logrando una sintaxis declarativa y moderna.
  • 139 pruebas pasando (679 aserciones) en apenas 0.18 segundos.
  • PHPStan Nivel 9: Configurado al nivel más estricto de análisis estático con 0 errores, asegurando que cada parámetro, propiedad y valor de retorno esté completamente controlado.
  • Laravel Pint: Estándar de estilo de código PSR-12 aplicado en el 100% de los archivos.

Comparativa Rápida de Sintaxis (v4 vs v5)

Característica v4.x v5.0.0
Versión mínima de PHP PHP >= 8.2 PHP >= 8.2
Acceso a Recursos $facturapi->Invoices (Propiedad mágica) $facturapi->invoices() (Método explícito y tipado)
Respuestas de API stdClass o arreglos genéricos DTOs Tipados (Invoice, Customer, etc.)
Autocompletado en IDE / IA ❌ No disponible ✅ 100% Introspección y Autocompletado
Catálogos del SAT Strings mágicos ('01', 'I') Backed Enums (PaymentForm::EFECTIVO) o strings
Cliente HTTP Acoplado rígidamente a Guzzle PSR-18 Agnóstico (php-http/discovery)
Excepciones \Exception genérica Jerarquía especializada (BadRequestException, etc.)
Soporte Octane / FrankenPHP No garantizado (riesgo de estado) 100% Stateless y seguro como Singleton
Suite de Pruebas PHPUnit legado Pest v5 (139 tests, 679 assertions)
Análisis Estático Sin tipado estricto PHPStan Nivel 9 (0 errores)

Documentación y Recursos Adicionales Incluidos

  1. Guías Oficiales para Frameworks:

  2. Guía para Agentes de IA (AGENTS.md): Contexto y directrices de arquitectura diseñadas para que Cursor, Copilot o modelos de IA implementen Facturapi siguiendo las mejores prácticas del SDK.

  3. Distribución Standalone: Script de empaquetado para generar el archivo facturapi-php-standalone.zip con autoloader incluido para desarrolladores que no utilizan Composer.

  4. Skill para desarrollo del SDK: Se creo una skill para ayudar a mantener y desarrollar este SDK con ayuda de IA.

- Eliminado alias obsoleto Facturapi_Exception.php
- Creadas excepciones específicas (Validation, Authentication, NotFound, RateLimit, Server, Network)
- FacturapiHttpClient ahora lanza excepciones específicas según el status code y mapea ClientExceptionInterface a NetworkException
…"Corrige el método previewToInvoicePdf para usar POST en lugar de GET. Corrige manejo de nulos en Retentions::sendByEmail. Añade pruebas CRUD y de simulación de payload completo.
Añade métodos y query parameters faltantes en Customers y TaxIdValidationResult. Agrega un test exhaustivo con payload completo para Invoices.
Implementa las pruebas base de las organizaciones (creación, edición de dominios y legales) y las operaciones de Webhooks, cubriendo los requerimientos del plan.
Corrige omisiones de query parameters en los catálogos del SAT, CartaPorte, ComercioExterior y Nómina. Añade el endpoint check en Tools.
…ientas

Se completan las pruebas de todos los catálogos satelitales verificando el parseo de los parámetros en la URL.
Se añade Makefile con comandos útiles como test, test-coverage e install.
Actualiza versión de Guzzle, agrega autores en composer.json y elimina example.php.
@macarthuror

Copy link
Copy Markdown
Author

Como parte de nuestro proceso de validación, nos encontramos desplegando esta versión en nuestros entornos de Staging/QA sobre un proyecto real de producción, asegurando que cumpla con todos los controles operativos antes de su adopción definitiva.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant