Skip to content

Commit 1451370

Browse files
authored
v4 modernization: preserve API error shape and expand critical tests (#44)
1 parent 2af6b04 commit 1451370

33 files changed

+2536
-1195
lines changed

.github/workflows/ci.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
workflow_dispatch:
9+
10+
permissions:
11+
contents: read
12+
13+
jobs:
14+
tests:
15+
name: PHP ${{ matrix.php-version }}
16+
runs-on: ubuntu-latest
17+
strategy:
18+
fail-fast: false
19+
matrix:
20+
php-version: ['8.2', '8.4']
21+
22+
steps:
23+
- name: Checkout
24+
uses: actions/checkout@v4
25+
26+
- name: Setup PHP
27+
uses: shivammathur/setup-php@v2
28+
with:
29+
php-version: ${{ matrix.php-version }}
30+
coverage: none
31+
tools: composer:v2
32+
33+
- name: Install dependencies
34+
run: composer install --no-interaction --prefer-dist
35+
36+
- name: Run test suite
37+
run: ./vendor/bin/phpunit --configuration phpunit.xml

.github/workflows/deploy-on-main.yml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,15 @@ jobs:
2525
run: |
2626
set -euo pipefail
2727
28-
if [[ ! -f VERSION ]]; then
29-
echo "Missing VERSION file"
28+
if [[ ! -f VERSION.md ]]; then
29+
echo "Missing VERSION.md file"
3030
exit 1
3131
fi
3232
33-
LOCAL_VERSION="$(head -n1 VERSION | tr -d '[:space:]')"
34-
RELEASE_BODY="$(tail -n +2 VERSION || true)"
33+
LOCAL_VERSION="$(head -n1 VERSION.md | tr -d '[:space:]')"
34+
RELEASE_BODY="$(tail -n +2 VERSION.md || true)"
3535
if [[ ! "$LOCAL_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$ ]]; then
36-
echo "VERSION must be valid semver. Got: $LOCAL_VERSION"
36+
echo "VERSION.md first line must be valid semver. Got: $LOCAL_VERSION"
3737
exit 1
3838
fi
3939
@@ -61,13 +61,13 @@ jobs:
6161
6262
HIGHEST="$(printf '%s\n%s\n' "$REMOTE_MAX" "$LOCAL_VERSION" | sort -V | tail -n1)"
6363
if [[ "$HIGHEST" != "$LOCAL_VERSION" ]]; then
64-
echo "Local VERSION is not greater than remote max tag"
64+
echo "Local VERSION.md is not greater than remote max tag"
6565
echo "should_deploy=false" >> "$GITHUB_OUTPUT"
6666
exit 0
6767
fi
6868
6969
if ! printf '%s' "$RELEASE_BODY" | grep -q '[^[:space:]]'; then
70-
echo "VERSION requires release notes after the first line when publishing."
70+
echo "VERSION.md requires release notes after the first line when publishing."
7171
echo "Example:"
7272
echo " 3.6.1"
7373
echo " ## What changed"
@@ -108,4 +108,4 @@ jobs:
108108
- name: Deploy skipped
109109
if: steps.version.outputs.should_deploy != 'true'
110110
run: |
111-
echo "Skipping deploy: local VERSION is not greater than remote semver tag."
111+
echo "Skipping deploy: local VERSION.md is not greater than remote semver tag."

README.es.md

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
# Facturapi PHP SDK
2+
3+
SDK oficial de PHP para [Facturapi](https://www.facturapi.io).
4+
5+
Idioma: Español | [English](./README.md)
6+
7+
[![Última Versión](https://img.shields.io/packagist/v/facturapi/facturapi-php?style=flat-square)](https://packagist.org/packages/facturapi/facturapi-php)
8+
[![Versión de PHP](https://img.shields.io/packagist/php-v/facturapi/facturapi-php?style=flat-square)](https://packagist.org/packages/facturapi/facturapi-php)
9+
[![Descargas Totales](https://img.shields.io/packagist/dt/facturapi/facturapi-php?style=flat-square)](https://packagist.org/packages/facturapi/facturapi-php)
10+
[![Descargas Mensuales](https://img.shields.io/packagist/dm/facturapi/facturapi-php?style=flat-square)](https://packagist.org/packages/facturapi/facturapi-php)
11+
[![Licencia](https://img.shields.io/packagist/l/facturapi/facturapi-php?style=flat-square)](https://packagist.org/packages/facturapi/facturapi-php)
12+
13+
## Instalación ⚡
14+
15+
```bash
16+
composer require facturapi/facturapi-php
17+
```
18+
19+
Sin Composer (workaround soportado):
20+
21+
```php
22+
require_once __DIR__ . '/path/to/facturapi-php/src/Facturapi.php';
23+
```
24+
25+
Requisitos:
26+
- PHP `>=8.2`
27+
28+
## Inicio Rápido 🚀
29+
30+
```php
31+
<?php
32+
33+
require_once __DIR__ . '/vendor/autoload.php';
34+
35+
use Facturapi\Facturapi;
36+
37+
$apiKey = getenv('FACTURAPI_KEY') ?: 'YOUR_API_KEY';
38+
$facturapi = new Facturapi($apiKey);
39+
40+
$customer = $facturapi->Customers->create([
41+
'email' => 'walterwhite@gmail.com',
42+
'legal_name' => 'Walter White',
43+
'tax_id' => 'WIWA761018',
44+
'address' => [
45+
'zip' => '06800',
46+
'street' => 'Av. de los Rosales',
47+
'exterior' => '123',
48+
'neighborhood' => 'Tepito',
49+
],
50+
]);
51+
```
52+
53+
## Configuración del Cliente ⚙️
54+
55+
Firma del constructor:
56+
57+
```php
58+
new Facturapi(string $apiKey, ?array $config = null)
59+
```
60+
61+
Claves soportadas en `config`:
62+
- `apiVersion` (`string`, valor por defecto: `v2`)
63+
- `timeout` (`int|float`, valor por defecto: `360` segundos)
64+
- `httpClient` (`Psr\Http\Client\ClientInterface`, avanzado)
65+
66+
Ejemplo:
67+
68+
```php
69+
use Facturapi\Facturapi;
70+
71+
$facturapi = new Facturapi($apiKey, [
72+
'apiVersion' => 'v2',
73+
'timeout' => 420,
74+
]);
75+
```
76+
77+
### Cliente HTTP Personalizado (Avanzado)
78+
79+
El SDK funciona sin configuración adicional con su cliente interno basado en Guzzle.
80+
81+
Si proporcionas `httpClient`, puedes pasar cualquier cliente compatible con PSR-18 y configurar ahí mismo los timeouts:
82+
83+
```php
84+
use Facturapi\Facturapi;
85+
use GuzzleHttp\Client;
86+
87+
$httpClient = new Client([
88+
'timeout' => 420,
89+
]);
90+
91+
$facturapi = new Facturapi($apiKey, [
92+
'httpClient' => $httpClient,
93+
]);
94+
```
95+
96+
## Uso Común 🧾
97+
98+
### Crear un Producto
99+
100+
```php
101+
$product = $facturapi->Products->create([
102+
'product_key' => '4319150114',
103+
'description' => 'Apple iPhone 8',
104+
'price' => 345.60,
105+
]);
106+
```
107+
108+
### Crear una Factura
109+
110+
```php
111+
$invoice = $facturapi->Invoices->create([
112+
'customer' => 'YOUR_CUSTOMER_ID',
113+
'items' => [[
114+
'quantity' => 1,
115+
'product' => 'YOUR_PRODUCT_ID',
116+
]],
117+
'payment_form' => \Facturapi\PaymentForm::EFECTIVO,
118+
'folio_number' => '581',
119+
'series' => 'F',
120+
]);
121+
```
122+
123+
### Descargar Archivos
124+
125+
```php
126+
$zipBytes = $facturapi->Invoices->downloadZip('INVOICE_ID');
127+
$pdfBytes = $facturapi->Invoices->downloadPdf('INVOICE_ID');
128+
$xmlBytes = $facturapi->Invoices->downloadXml('INVOICE_ID');
129+
```
130+
131+
`downloadPdf()` devuelve bytes crudos de PDF (cadena binaria), no base64.
132+
133+
```php
134+
file_put_contents('invoice.pdf', $pdfBytes);
135+
```
136+
137+
### Enviar por Correo
138+
139+
```php
140+
$facturapi->Invoices->sendByEmail('INVOICE_ID');
141+
```
142+
143+
### Catálogos de Comercio Exterior
144+
145+
```php
146+
$results = $facturapi->ComercioExteriorCatalogs->searchTariffFractions([
147+
'q' => '0101',
148+
'page' => 0,
149+
'limit' => 10,
150+
]);
151+
```
152+
153+
## Manejo de Errores ⚠️
154+
155+
En respuestas no-2xx, el SDK lanza `Facturapi\Exceptions\FacturapiException`.
156+
157+
La excepción incluye:
158+
- `getMessage()`: mensaje del API cuando está disponible.
159+
- `getStatusCode()`: código HTTP.
160+
- `getErrorData()`: payload JSON decodificado del error (shape completo del API).
161+
- `getRawBody()`: cuerpo crudo de la respuesta.
162+
163+
```php
164+
use Facturapi\Exceptions\FacturapiException;
165+
166+
try {
167+
$facturapi->Invoices->create($payload);
168+
} catch (FacturapiException $e) {
169+
$status = $e->getStatusCode();
170+
$error = $e->getErrorData(); // Shape completo del error del API cuando el body es JSON válido.
171+
$firstDetail = $error['details'][0] ?? null; // p.ej. ['path' => 'items.0.quantity', 'message' => '...', 'code' => '...']
172+
}
173+
```
174+
175+
## Notas de Migración (v4) 🔄
176+
177+
- La versión mínima de PHP ahora es `>=8.2`.
178+
- Se eliminó el soporte para el argumento posicional `apiVersion` en el constructor.
179+
- Proyectos con Composer: no requieren cambios de carga; continúen usando `vendor/autoload.php`.
180+
- Proyectos sin Composer pueden seguir usando el SDK cargando `src/Facturapi.php` directamente.
181+
- Los aliases snake_case están deprecados en v4 y se eliminarán en v5.
182+
- `Facturapi\\Exceptions\\Facturapi_Exception` está deprecada en v4 y se eliminará en v5.
183+
- Usa `Facturapi\\Exceptions\\FacturapiException`.
184+
185+
## Documentación 📚
186+
187+
Documentación completa: [https://docs.facturapi.io](https://docs.facturapi.io)
188+
189+
## Soporte 💬
190+
191+
- Issues: abre un issue en GitHub
192+
- Email: `contacto@facturapi.io`

0 commit comments

Comments
 (0)