Skip to content

Conversation

@orbilai-dgenova
Copy link

🐛 Critical Bug Fix: AEAT Hash Compliance

This PR fixes a critical bug where the hash input string was using snake_case field names instead of the official AEAT XML field names, causing non-compliance with the official AEAT specification.

📖 Reference

Document: "Detalle de las especificaciones técnicas para generación de la huella o hash de los registros de facturación"

  • Version: 0.1.2
  • Date: 27/08/2024
  • Official Source: AEAT (Agencia Estatal de Administración Tributaria)

❌ Problem (Before)

// WRONG: Using snake_case field names
$inputString = self::field('issuer_tax_id', $data['issuer_tax_id']);
$inputString .= self::field('invoice_number', $data['invoice_number']);
$inputString .= self::field('issue_date', $data['issue_date']);
$inputString .= self::field('invoice_type', $data['invoice_type']);
$inputString .= self::field('total_tax', $data['total_tax']);
$inputString .= self::field('total_amount', $data['total_amount']);
$inputString .= self::field('previous_hash', $data['previous_hash']);
$inputString .= self::field('generated_at', $data['generated_at'], false);

Generates: issuer_tax_id=89890001K&invoice_number=12345678/G33&issue_date=01-01-2024&...

✅ Solution (After)

// CORRECT: Using official AEAT XML field names (spec page 6)
$inputString = self::field('IDEmisorFactura', $data['issuer_tax_id']);
$inputString .= self::field('NumSerieFactura', $data['invoice_number']);
$inputString .= self::field('FechaExpedicionFactura', $data['issue_date']);
$inputString .= self::field('TipoFactura', $data['invoice_type']);
$inputString .= self::field('CuotaTotal', $data['total_tax']);
$inputString .= self::field('ImporteTotal', $data['total_amount']);
$inputString .= self::field('Huella', $data['previous_hash']);
$inputString .= self::field('FechaHoraHusoGenRegistro', $data['generated_at'], false);

Generates: IDEmisorFactura=89890001K&NumSerieFactura=12345678/G33&FechaExpedicionFactura=01-01-2024&...

🧪 Testing

Added comprehensive tests using official AEAT examples (spec pages 10-11):

  • ✅ Test Case 1: First invoice (hash: 3C464DAF61ACB827C65FDA19F352A4E3BDC2C640E9E9FC4CC058073F38F12F60)
  • ✅ Test Case 2: Second invoice with chain (hash: F7B94CFD8924EDFF273501B01EE5153E4CE8F259766F88CF6ACB8935802A2B97)
  • ✅ Uppercase output validation (spec page 9)
  • ✅ Whitespace trimming (spec page 6)

All tests pass: 4 tests, 7 assertions ✅

⚠️ Breaking Change

Hashes generated with the previous version are not valid according to AEAT specifications. Systems already in production will need to regenerate hashes for all invoices.

📦 Changes

  • src/Helpers/HashHelper.php: Updated field names to match official AEAT XML specification
  • tests/Unit/HashHelperAeatComplianceTest.php: New compliance tests with official examples

🔗 Related

  • AEAT Official Specification v0.1.2 (27/08/2024)
  • Page 6: Field names definition
  • Page 9: Hash format (uppercase hexadecimal)
  • Pages 10-11: Official test cases

…ficación AEAT

BREAKING CHANGE: Los nombres de campos en la cadena de hash ahora usan
los nombres oficiales del XML de AEAT en lugar de snake_case:
- issuer_tax_id -> IDEmisorFactura
- invoice_number -> NumSerieFactura
- issue_date -> FechaExpedicionFactura
- invoice_type -> TipoFactura
- total_tax -> CuotaTotal
- total_amount -> ImporteTotal
- previous_hash -> Huella
- generated_at -> FechaHoraHusoGenRegistro

Esta corrección es CRÍTICA para cumplir con la normativa oficial AEAT
según documento 'Detalle de las especificaciones técnicas para generación
de la huella o hash de los registros de facturación' v0.1.2 (27/08/2024).

Referencias:
- Página 6: Nombres de campos obligatorios
- Página 9: Hash en mayúsculas (ya implementado correctamente)
- Página 10-11: Ejemplos oficiales (validados en tests)

Tests añadidos:
- test_first_invoice_hash_matches_aeat_specification()
- test_second_invoice_hash_matches_aeat_specification()
- test_hash_output_is_uppercase()
- test_whitespace_trimming()

Todos los tests pasan correctamente (4 tests, 7 assertions).
@sonarqubecloud
Copy link

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