Documentation Index
Fetch the complete documentation index at: https://mintlify.com/Eseperio/verifactu-php/llms.txt
Use this file to discover all available pages before exploring further.
HashGeneratorService computes the huella (fingerprint / hash) that AEAT requires on every invoice and cancellation record submitted via VERI*FACTU. The hash chains consecutive records together, creating an immutable audit trail.
Namespace: eseperio\verifactu\services\HashGeneratorService
Under normal usage you never need to call
HashGeneratorService directly. Both VerifactuService::registerInvoice() and VerifactuService::cancelInvoice() call it automatically before serialising and signing the XML. The generated hash is written back to $record->hash before the record is submitted.Method
generate(InvoiceRecord $record): string
Generates the SHA-256 huella for the given record and returns it as an uppercase hexadecimal string.
InvoiceSubmission or an InvoiceCancellation. It automatically selects the correct field set and concatenation format for each type. Passing any other InvoiceRecord subclass throws \InvalidArgumentException.
Concatenation format
The hash is computed asstrtoupper(hash('sha256', $concatenatedString)) where $concatenatedString is built by joining key=value pairs with & separators. No trailing & is added.
InvoiceSubmission (RegistroAlta)
Fields are concatenated in this exact order:| Field key | Source property | Notes |
|---|---|---|
IDEmisorFactura | InvoiceId::$issuerNif | Trimmed. |
NumSerieFactura | InvoiceId::$seriesNumber | Trimmed. |
FechaExpedicionFactura | InvoiceId::$issueDate | Trimmed. Format: DD-MM-YYYY. |
TipoFactura | InvoiceSubmission::$invoiceType | The enum’s string value (e.g. "F1"). |
CuotaTotal | InvoiceSubmission::$taxAmount | Normalised to 2 decimal places, dot separator (e.g. "21.00"). |
ImporteTotal | InvoiceSubmission::$totalAmount | Normalised to 2 decimal places, dot separator. |
Huella | Previous record’s hash via Chaining::getPreviousInvoice()->hash | Empty string "" when firstRecord = 'S' or no chaining is set. |
FechaHoraHusoGenRegistro | InvoiceSubmission::$recordTimestamp | Trimmed. ISO 8601 with timezone offset, e.g. "2024-01-01T10:00:00+01:00". |
InvoiceCancellation (RegistroAnulacion)
Fields are concatenated in this exact order:| Field key | Source property | Notes |
|---|---|---|
IDEmisorFacturaAnulada | InvoiceId::$issuerNif | Trimmed. |
NumSerieFacturaAnulada | InvoiceId::$seriesNumber | Trimmed. |
FechaExpedicionFacturaAnulada | InvoiceId::$issueDate | Trimmed. |
Huella | Previous record’s hash via Chaining::getPreviousInvoice()->hash | Empty string "" for first record. |
FechaHoraHusoGenRegistro | InvoiceCancellation::$recordTimestamp | Trimmed. |
Decimal normalisation
All monetary amounts (taxAmount, totalAmount) are normalised before concatenation:
- Converted to
float. - Formatted with exactly 2 decimal places.
- Dot (
.) as decimal separator — no thousands separator.
When to call manually
CallHashGeneratorService::generate() directly when you need the hash before submitting — for example, to print the QR code on an invoice PDF at time of issue, or to pre-populate a database record with the hash for later chaining.
Chaining between records
TheHuella field in the concatenation string is the hash of the immediately preceding record in the submission sequence. This is what creates the tamper-evident chain.