Skip to content

Commit

Permalink
Merge pull request #108 from josemmo/develop
Browse files Browse the repository at this point in the history
v1.7.4
  • Loading branch information
josemmo authored Nov 19, 2022
2 parents 78de2c4 + a496651 commit 82a85dd
Show file tree
Hide file tree
Showing 24 changed files with 1,138 additions and 499 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,17 @@ $fac->sign("certificado.pfx", null, "passphrase");
$fac->export("mi-factura.xsig");
```

También permite firmar facturas que hayan sido generadas con otro programa:

```php
$signer = new FacturaeSigner();
$signer->loadPkcs12("certificado.pfx", "passphrase");

$xml = file_get_contents(__DIR__ . "/factura.xml");
$signedXml = $signer->sign($xml);
file_put_contents(__DIR__ . "/factura.xsig", $signedXml);
```

## Requisitos
- PHP 5.6 o superior
- OpenSSL (solo para firmar facturas)
Expand Down
1 change: 0 additions & 1 deletion doc/anexos/constantes.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ permalink: /anexos/constantes.html
|`Facturae::SCHEMA_3_2`|Formato de Facturae 3.2|
|`Facturae::SCHEMA_3_2_1`|Formato de Facturae 3.2.1|
|`Facturae::SCHEMA_3_2_2`|Formato de Facturae 3.2.2|
|`Facturae::SIGN_POLICY_3_1`|Formato de firma 3.1|

---

Expand Down
3 changes: 3 additions & 0 deletions doc/envio-y-recepcion/face.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ Al igual que al firmar una factura electrónica, puedes usar un solo archivo `.p
$face = new FaceClient("certificado.pfx", null, "passphrase");
```

> #### NOTA
> Para más información sobre qué otros valores pueden tomar los parámetros del constructor, consulta la documentación de [firma electrónica](../firma-electronica/).
Por defecto, `FaceClient` se comunica con el entorno de producción de FACe. Para usar el entorno de pruebas (*staging*) puedes utilizar el siguiente método:
```php
$face->setProduction(false);
Expand Down
3 changes: 3 additions & 0 deletions doc/envio-y-recepcion/faceb2b.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ Al igual que al firmar una factura electrónica, puedes usar un solo archivo `.p
$face = new Faceb2bClient("certificado.pfx", null, "passphrase");
```

> #### NOTA
> Para más información sobre qué otros valores pueden tomar los parámetros del constructor, consulta la documentación de [firma electrónica](../firma-electronica/).
Por defecto, `Faceb2bClient` se comunica con el entorno de producción de FACeB2B. Para usar el entorno de pruebas (*staging*) puedes utilizar el siguiente método:
```php
$face->setProduction(false);
Expand Down
82 changes: 82 additions & 0 deletions doc/firma-electronica/firma-avanzada.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
---
title: Firma avanzada
parent: Firma electrónica
nav_order: 2
permalink: /firma-electronica/firma-avanzada.html
---

# Firma avanzada
La librería permite firmar documentos XML de FacturaE que hayan sido generados con otros programas a través de la clase `FacturaeSigner`. Esta misma clase es usada a nivel interno para firmar las facturas creadas con Facturae-PHP.

```php
use josemmo\Facturae\Common\FacturaeSigner;
use RuntimeException;

// Creación y configuración de la instancia
$signer = new FacturaeSigner();
$signer->loadPkcs12("certificado.pfx", "passphrase");
$signer->setTimestampServer("https://www.safestamper.com/tsa", "usuario", "contraseña");

// Firma electrónica
$xml = file_get_contents(__DIR__ . "/factura.xml");
try {
$signedXml = $signer->sign($xml);
} catch (RuntimeException $e) {
// Fallo al firmar
}

// Sellado de tiempo
try {
$timestampedXml = $signer->timestamp($signedXml);
} catch (RuntimeException $e) {
// Fallo al añadir sello de tiempo
}
file_put_contents(__DIR__ . "/factura.xsig", $timestampedXml);
```

`FacturaeSigner` es capaz de firmar cualquier documento XML válido que cumpla con la especificación de FacturaE, siempre y cuando:

- El elemento raíz del documento sea `<fe:Facturae />`
- El namespace de FacturaE sea `xmlns:fe`
- El namespace de XMLDSig no aparezca (recomendable) o sea `xmlns:ds`
- El namespace de XAdES no aparezca (recomendable) o sea `xmlns:xades`

La inmensa mayoría de programas que generan documentos de FacturaE cumplen con estos requisitos.

---

## Fecha de la firma
Por defecto, al firmar una factura se utilizan la fecha y hora actuales como sello de tiempo. Si se quiere indicar otro valor, se debe utilizar el siguiente método:
```php
$signer->setSigningTime("2017-01-01T12:34:56+02:00");
```

> #### NOTA
> Cambiar manualmente la fecha de la firma puede entrar en conflicto con el sellado de tiempo.
---

## Identificadores de elementos XML
Al firmar un documento XML, durante la firma se añaden una serie de identificadores a determinados nodos en forma de atributos (por ejemplo, `<xades:SignedProperties Id="Signature1234-SignedProperties9876" />`).
Estos identificadores son necesarios para validar la firma e integridad del documento.

Por defecto, sus valores se generan de forma aleatoria en el momento de **instanciación** de la clase `FacturaeSigner`, por que lo que si se firman varias facturas con la misma instancia sus valores no cambian.
Se recomienda llamar al método `$signer->regenerateIds()` si se firman varios documentos:

```php
$firstXml = file_get_contents(__DIR__ . "/factura_1.xml");
$firstSignedXml = $signer->sign($firstXml);

$signer->regenerateIds();

$secondXml = file_get_contents(__DIR__ . "/factura_2.xml");
$secondSignedXml = $signer->sign($secondXml);
```

También es posible establecer valores deterministas a todos los IDs:

```php
$signer->signatureId = "My-Custom-SignatureId";
$signer->certificateId = "My-Custom-CertificateId";
$signedXml = $signer->sign($xml);
```
17 changes: 15 additions & 2 deletions doc/firma-electronica/firma-electronica.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,18 @@ Aunque es posible exportar las facturas sin firmarlas, es un paso obligatorio pa
Para firmar facturas se necesita un certificado electrónico (generalmente expedido por la FNMT) del que extraer su clave pública y su clave privada.

## Firmado con clave pública y privada X.509
Si se tienen las clave pública y privada en archivos independientes se debe utilizar este método con los siguientes argumentos:
Si se tiene la clave pública (un certificado) y la clave privada en archivos independientes, se debe utilizar este método con los siguientes argumentos:
```php
$fac->sign("clave_publica.pem", "clave_privada.pem", "passphrase");
```

También se pueden pasar como parámetros los bytes de ambos ficheros en vez de sus rutas, o instancias de `OpenSSLCertificate` y `OpenSSLAsymmetricKey`, respectivamente:
```php
$publicKey = openssl_x509_read("clave_publica.pem");
$encryptedPrivateKey = file_get_contents("clave_privada.pem");
$fac->sign($publicKey, $encryptedPrivateKey, "passphrase");
```

> #### NOTA
> Los siguientes comandos permiten extraer el certificado (clave pública) y la clave privada de un archivo PFX:
>
Expand All @@ -31,6 +38,12 @@ Desde la versión 1.0.5 de Facturae-PHP ya es posible cargar un banco de certifi
$fac->sign("certificado.pfx", null, "passphrase");
```
También se pueden pasar como parámetro los bytes del banco PKCS#12:
```php
$encryptedStore = file_get_contents("certificado.pfx");
$fac->sign($encryptedStore, null, "passphrase");
```

> #### NOTA
> Al utilizar un banco PKCS#12, Facturae-PHP incluirá la cadena completa de certificados en la factura al firmarla.
>
Expand All @@ -51,7 +64,7 @@ $fac->sign("certificado.pfx", null, "passphrase");
## Fecha de la firma
Por defecto, al firmar una factura se utilizan la fecha y hora actuales como sello de tiempo. Si se quiere indicar otro valor, se debe utilizar el siguiente método:
```php
$fac->setSignTime("2017-01-01T12:34:56+02:00");
$fac->setSigningTime("2017-01-01T12:34:56+02:00");
```
> #### NOTA
Expand Down
22 changes: 22 additions & 0 deletions doc/propiedades/suplidos.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
title: Suplidos
parent: Propiedades de una factura
nav_order: 8
permalink: /propiedades/suplidos.html
---

# Suplidos
La especificación de FacturaE permite añadir gastos a cuenta de terceros a una factura (suplidos).
Para ello, se debe hacer uso de la clase `ReimbursableExpense`:
```php
$fac->addReimbursableExpense(new ReimbursableExpense([
"seller" => new FacturaeParty(["taxNumber" => "00000000A"]),
"buyer" => new FacturaeParty(["taxNumber" => "12-3456789", "isEuropeanUnionResident" => false]),
"issueDate" => "2017-11-27",
"invoiceNumber" => "EX-19912",
"invoiceSeriesCode" => "156A",
"amount" => 100.00
]));
```

Todos las propiedades de un suplido son opcionales excepto el importe (`amount`).
Loading

0 comments on commit 82a85dd

Please sign in to comment.