Additional tests for verifactu
This commit is contained in:
parent
a431dd43d4
commit
b93ec6dd93
|
|
@ -786,6 +786,60 @@ class Invoice extends BaseXmlModel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function toSoapEnvelope(): string
|
||||||
|
{
|
||||||
|
// Create the SOAP document
|
||||||
|
$soapDoc = new \DOMDocument('1.0', 'UTF-8');
|
||||||
|
$soapDoc->preserveWhiteSpace = false;
|
||||||
|
$soapDoc->formatOutput = true;
|
||||||
|
|
||||||
|
// Create SOAP envelope with namespaces
|
||||||
|
$envelope = $soapDoc->createElementNS('http://schemas.xmlsoap.org/soap/envelope/', 'soapenv:Envelope');
|
||||||
|
$envelope->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:soapenv', 'http://schemas.xmlsoap.org/soap/envelope/');
|
||||||
|
$envelope->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:sum', 'https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroLR.xsd');
|
||||||
|
$envelope->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:sum1', 'https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroInformacion.xsd');
|
||||||
|
|
||||||
|
$soapDoc->appendChild($envelope);
|
||||||
|
|
||||||
|
// Create Header
|
||||||
|
$header = $soapDoc->createElementNS('http://schemas.xmlsoap.org/soap/envelope/', 'soapenv:Header');
|
||||||
|
$envelope->appendChild($header);
|
||||||
|
|
||||||
|
// Create Body
|
||||||
|
$body = $soapDoc->createElementNS('http://schemas.xmlsoap.org/soap/envelope/', 'soapenv:Body');
|
||||||
|
$envelope->appendChild($body);
|
||||||
|
|
||||||
|
// Create RegFactuSistemaFacturacion
|
||||||
|
$regFactu = $soapDoc->createElementNS('https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroLR.xsd', 'sum:RegFactuSistemaFacturacion');
|
||||||
|
$body->appendChild($regFactu);
|
||||||
|
|
||||||
|
// Create Cabecera
|
||||||
|
$cabecera = $soapDoc->createElementNS('https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroLR.xsd', 'sum:Cabecera');
|
||||||
|
$regFactu->appendChild($cabecera);
|
||||||
|
|
||||||
|
// Create ObligadoEmision
|
||||||
|
$obligadoEmision = $soapDoc->createElementNS('https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroInformacion.xsd', 'sum1:ObligadoEmision');
|
||||||
|
$cabecera->appendChild($obligadoEmision);
|
||||||
|
|
||||||
|
// Add ObligadoEmision content
|
||||||
|
$obligadoEmision->appendChild($soapDoc->createElementNS('https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroInformacion.xsd', 'sum1:NombreRazon', $this->sistemaInformatico->getNombreRazon()));
|
||||||
|
$obligadoEmision->appendChild($soapDoc->createElementNS('https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroInformacion.xsd', 'sum1:NIF', $this->sistemaInformatico->getNif()));
|
||||||
|
|
||||||
|
// Create RegistroFactura
|
||||||
|
$registroFactura = $soapDoc->createElementNS('https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroLR.xsd', 'sum:RegistroFactura');
|
||||||
|
$regFactu->appendChild($registroFactura);
|
||||||
|
|
||||||
|
// Import your existing XML into the RegistroFactura
|
||||||
|
$yourXmlDoc = new \DOMDocument();
|
||||||
|
$yourXmlDoc->loadXML($this->toXmlString());
|
||||||
|
|
||||||
|
// Import the root element from your XML
|
||||||
|
$importedNode = $soapDoc->importNode($yourXmlDoc->documentElement, true);
|
||||||
|
$registroFactura->appendChild($importedNode);
|
||||||
|
|
||||||
|
return $soapDoc->saveXML();
|
||||||
|
}
|
||||||
|
|
||||||
protected function validateXml(\DOMDocument $doc): void
|
protected function validateXml(\DOMDocument $doc): void
|
||||||
{
|
{
|
||||||
$xsdPath = $this->getXsdPath();
|
$xsdPath = $this->getXsdPath();
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -13,10 +13,11 @@ use App\Services\EDocument\Standards\Verifactu\Models\PersonaFisicaJuridica;
|
||||||
use App\Services\EDocument\Standards\Verifactu\Models\FacturaRectificativa;
|
use App\Services\EDocument\Standards\Verifactu\Models\FacturaRectificativa;
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
|
|
||||||
class InvoiceTest extends TestCase
|
class VerifactuInvoiceTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testCreateAndSerializeCompleteInvoice(): void
|
public function testCreateAndSerializeCompleteInvoice(): void
|
||||||
{
|
{
|
||||||
|
|
||||||
$invoice = new Invoice();
|
$invoice = new Invoice();
|
||||||
$invoice
|
$invoice
|
||||||
->setIdVersion('1.0')
|
->setIdVersion('1.0')
|
||||||
|
|
@ -82,6 +83,7 @@ class InvoiceTest extends TestCase
|
||||||
// echo $xml;
|
// echo $xml;
|
||||||
// echo "\n\n";
|
// echo "\n\n";
|
||||||
|
|
||||||
|
nlog($xml);
|
||||||
// Validate against XSD
|
// Validate against XSD
|
||||||
$doc = new \DOMDocument();
|
$doc = new \DOMDocument();
|
||||||
$doc->loadXML($xml);
|
$doc->loadXML($xml);
|
||||||
|
|
@ -2,13 +2,145 @@
|
||||||
|
|
||||||
namespace Tests\Feature\EInvoice\Verifactu\Models;
|
namespace Tests\Feature\EInvoice\Verifactu\Models;
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Http;
|
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use App\Services\EDocument\Standards\Verifactu\Models\Invoice;
|
||||||
|
use App\Services\EDocument\Standards\Verifactu\Models\Desglose;
|
||||||
|
use App\Services\EDocument\Standards\Verifactu\Models\Encadenamiento;
|
||||||
|
use App\Services\EDocument\Standards\Verifactu\Models\SistemaInformatico;
|
||||||
|
use App\Services\EDocument\Standards\Verifactu\Models\PersonaFisicaJuridica;
|
||||||
|
|
||||||
|
|
||||||
class WSTest extends TestCase
|
class WSTest extends TestCase
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public function test_generated_invoice_xml_can_send_to_web_service()
|
||||||
|
{
|
||||||
|
|
||||||
|
// Generate current timestamp in the correct format
|
||||||
|
$currentTimestamp = date('Y-m-d\TH:i:s');
|
||||||
|
nlog($currentTimestamp);
|
||||||
|
$invoice = new Invoice();
|
||||||
|
$invoice
|
||||||
|
->setIdVersion('1.0')
|
||||||
|
->setIdFactura('FAC-2023-001')
|
||||||
|
->setRefExterna('REF-123')
|
||||||
|
->setNombreRazonEmisor('Empresa Ejemplo SL')
|
||||||
|
->setTipoFactura('F1')
|
||||||
|
->setDescripcionOperacion('Venta de productos varios')
|
||||||
|
->setCuotaTotal(210.00)
|
||||||
|
->setImporteTotal(1000.00)
|
||||||
|
->setFechaHoraHusoGenRegistro($currentTimestamp)
|
||||||
|
->setTipoHuella('01')
|
||||||
|
->setHuella('PLACEHOLDER_HUELLA');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// <sum:Cabecera>
|
||||||
|
// <!-- ObligadoEmision: The computer system submitting on behalf of the invoice issuer -->
|
||||||
|
// <sum1:ObligadoEmision>
|
||||||
|
// <sum1:NombreRazon>CERTIFICADO FISICA PRUEBAS</sum1:NombreRazon>
|
||||||
|
// <sum1:NIF>99999910G</sum1:NIF>
|
||||||
|
// </sum1:ObligadoEmision>
|
||||||
|
// </sum:Cabecera>
|
||||||
|
|
||||||
|
|
||||||
|
// Add emitter
|
||||||
|
$emisor = new PersonaFisicaJuridica();
|
||||||
|
$emisor
|
||||||
|
->setNif('B12345678')
|
||||||
|
->setRazonSocial('Empresa Ejemplo SL');
|
||||||
|
$invoice->setTercero($emisor);
|
||||||
|
|
||||||
|
// Add breakdown
|
||||||
|
$desglose = new Desglose();
|
||||||
|
$desglose->setDesgloseFactura([
|
||||||
|
'Impuesto' => '01',
|
||||||
|
'ClaveRegimen' => '01',
|
||||||
|
'CalificacionOperacion' => 'S1',
|
||||||
|
'BaseImponibleOimporteNoSujeto' => 1000.00,
|
||||||
|
'TipoImpositivo' => 21,
|
||||||
|
'CuotaRepercutida' => 210.00
|
||||||
|
]);
|
||||||
|
$invoice->setDesglose($desglose);
|
||||||
|
|
||||||
|
// Add information system
|
||||||
|
$sistema = new SistemaInformatico();
|
||||||
|
$sistema
|
||||||
|
->setNombreRazon('Sistema de Facturación')
|
||||||
|
->setNif('99999910G')
|
||||||
|
->setNombreSistemaInformatico('SistemaFacturacion')
|
||||||
|
->setIdSistemaInformatico('01')
|
||||||
|
->setVersion('1.0')
|
||||||
|
->setNumeroInstalacion('INST-001');
|
||||||
|
$invoice->setSistemaInformatico($sistema);
|
||||||
|
|
||||||
|
// Add chain
|
||||||
|
$encadenamiento = new Encadenamiento();
|
||||||
|
$encadenamiento->setPrimerRegistro('S');
|
||||||
|
$invoice->setEncadenamiento($encadenamiento);
|
||||||
|
|
||||||
|
$soapXml = $invoice->toSoapEnvelope();
|
||||||
|
|
||||||
|
$this->assertNotNull($soapXml);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$correctHash = $this->calculateVerifactuHash(
|
||||||
|
$invoice->getTercero()->getNif(), // IDEmisorFactura
|
||||||
|
$invoice->getIdFactura(), // NumSerieFactura
|
||||||
|
$invoice->getFechaHoraHusoGenRegistro(), // FechaExpedicionFactura
|
||||||
|
$invoice->getTipoFactura(), // TipoFactura
|
||||||
|
$invoice->getCuotaTotal(), // CuotaTotal
|
||||||
|
$invoice->getImporteTotal(), // ImporteTotal
|
||||||
|
'', // Huella (empty for first calculation)
|
||||||
|
$currentTimestamp // FechaHoraHusoGenRegistro (current time)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Replace the placeholder with the correct hash
|
||||||
|
$soapXml = str_replace('PLACEHOLDER_HUELLA', $correctHash, $soapXml);
|
||||||
|
|
||||||
|
\Log::info('Calculated hash for XML: ' . $correctHash);
|
||||||
|
|
||||||
|
// Sign the XML before sending
|
||||||
|
$certPath = storage_path('aeat-cert2.pem');
|
||||||
|
$keyPath = storage_path('aeat-key2.pem');
|
||||||
|
$signingService = new \App\Services\EDocument\Standards\Verifactu\Signing\SigningService($soapXml, file_get_contents($keyPath), file_get_contents($certPath));
|
||||||
|
$soapXml = $signingService->sign();
|
||||||
|
|
||||||
|
// Try direct HTTP approach instead of SOAP client
|
||||||
|
$response = Http::withHeaders([
|
||||||
|
'Content-Type' => 'text/xml; charset=utf-8',
|
||||||
|
'SOAPAction' => '',
|
||||||
|
])
|
||||||
|
->withOptions([
|
||||||
|
'cert' => storage_path('aeat-cert2.pem'),
|
||||||
|
'ssl_key' => storage_path('aeat-key2.pem'),
|
||||||
|
'verify' => false,
|
||||||
|
'timeout' => 30,
|
||||||
|
])
|
||||||
|
->withBody($soapXml, 'text/xml')
|
||||||
|
->post('https://prewww1.aeat.es/wlpl/TIKE-CONT/ws/SistemaFacturacion/VerifactuSOAP');
|
||||||
|
|
||||||
|
\Log::info('Request with AEAT official test data:');
|
||||||
|
\Log::info($soapXml);
|
||||||
|
\Log::info('Response with AEAT official test data:');
|
||||||
|
\Log::info('Response Status: ' . $response->status());
|
||||||
|
\Log::info('Response Headers: ' . json_encode($response->headers()));
|
||||||
|
\Log::info('Response Body: ' . $response->body());
|
||||||
|
|
||||||
|
if (!$response->successful()) {
|
||||||
|
\Log::error('Request failed with status: ' . $response->status());
|
||||||
|
\Log::error('Response body: ' . $response->body());
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertTrue($response->successful());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function test_send_aeat_example_to_verifactu()
|
public function test_send_aeat_example_to_verifactu()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue