Align tests with new workflow
This commit is contained in:
parent
0a7744a70e
commit
7e1a6bc1c7
|
|
@ -28,6 +28,8 @@ class IDOtro extends BaseXmlModel
|
||||||
'09', // Tax ID from third country
|
'09', // Tax ID from third country
|
||||||
];
|
];
|
||||||
|
|
||||||
|
private ?string $nombreRazon = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* __construct
|
* __construct
|
||||||
*
|
*
|
||||||
|
|
@ -41,6 +43,32 @@ class IDOtro extends BaseXmlModel
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getNombreRazon(): string
|
||||||
|
{
|
||||||
|
return $this->nombreRazon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCodigoPais(): string
|
||||||
|
{
|
||||||
|
return $this->codigoPais;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIdType(): string
|
||||||
|
{
|
||||||
|
return $this->idType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getId(): string
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setNombreRazon(string $nombreRazon): self
|
||||||
|
{
|
||||||
|
$this->nombreRazon = $nombreRazon;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function setCodigoPais(string $codigoPais): self
|
public function setCodigoPais(string $codigoPais): self
|
||||||
{
|
{
|
||||||
$this->codigoPais = strtoupper($codigoPais);
|
$this->codigoPais = strtoupper($codigoPais);
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,10 @@
|
||||||
|
|
||||||
namespace App\Services\EDocument\Standards\Verifactu\Models;
|
namespace App\Services\EDocument\Standards\Verifactu\Models;
|
||||||
|
|
||||||
use RobRichards\XMLSecLibs\XMLSecurityDSig;
|
|
||||||
use RobRichards\XMLSecLibs\XMLSecurityKey;
|
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use RobRichards\XMLSecLibs\XMLSecurityKey;
|
||||||
|
use RobRichards\XMLSecLibs\XMLSecurityDSig;
|
||||||
|
use App\Services\EDocument\Standards\Verifactu\Models\IDOtro;
|
||||||
|
|
||||||
class Invoice extends BaseXmlModel implements XmlModelInterface
|
class Invoice extends BaseXmlModel implements XmlModelInterface
|
||||||
{
|
{
|
||||||
|
|
@ -342,7 +343,7 @@ class Invoice extends BaseXmlModel implements XmlModelInterface
|
||||||
// Ensure all elements are PersonaFisicaJuridica instances
|
// Ensure all elements are PersonaFisicaJuridica instances
|
||||||
if ($destinatarios !== null) {
|
if ($destinatarios !== null) {
|
||||||
foreach ($destinatarios as $destinatario) {
|
foreach ($destinatarios as $destinatario) {
|
||||||
if (!($destinatario instanceof PersonaFisicaJuridica)) {
|
if (!($destinatario instanceof PersonaFisicaJuridica || $destinatario instanceof IDOtro)) {
|
||||||
throw new \InvalidArgumentException('All recipients must be instances of PersonaFisicaJuridica');
|
throw new \InvalidArgumentException('All recipients must be instances of PersonaFisicaJuridica');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -961,22 +962,29 @@ class Invoice extends BaseXmlModel implements XmlModelInterface
|
||||||
$root->appendChild($this->createElement($doc, 'DescripcionOperacion', $this->descripcionOperacion));
|
$root->appendChild($this->createElement($doc, 'DescripcionOperacion', $this->descripcionOperacion));
|
||||||
|
|
||||||
// 9. Destinatarios (if set)
|
// 9. Destinatarios (if set)
|
||||||
if ($this->destinatarios !== null && count($this->destinatarios) > 0) {
|
|
||||||
$destinatariosElement = $this->createElement($doc, 'Destinatarios');
|
// 9. Destinatarios (if set)
|
||||||
foreach ($this->destinatarios as $destinatario) {
|
if ($this->destinatarios !== null && count($this->destinatarios) > 0) {
|
||||||
$idDestinatarioElement = $this->createElement($doc, 'IDDestinatario');
|
$destinatariosElement = $this->createElement($doc, 'Destinatarios');
|
||||||
|
foreach ($this->destinatarios as $destinatario) {
|
||||||
// Add NombreRazon
|
$idDestinatarioElement = $this->createElement($doc, 'IDDestinatario');
|
||||||
$idDestinatarioElement->appendChild($this->createElement($doc, 'NombreRazon', $destinatario->getNombreRazon()));
|
|
||||||
|
// Add NombreRazon
|
||||||
// Add NIF
|
$idDestinatarioElement->appendChild($this->createElement($doc, 'NombreRazon', $destinatario->getNombreRazon()));
|
||||||
$idDestinatarioElement->appendChild($this->createElement($doc, 'NIF', $destinatario->getNif()));
|
|
||||||
|
if ($destinatario instanceof PersonaFisicaJuridica) {
|
||||||
$destinatariosElement->appendChild($idDestinatarioElement);
|
$idDestinatarioElement->appendChild($this->createElement($doc, 'NIF', $destinatario->getNif()));
|
||||||
}
|
} elseif ($destinatario instanceof IDOtro) {
|
||||||
$root->appendChild($destinatariosElement);
|
// Use the full IDOtro XML structure
|
||||||
|
$idDestinatarioElement->appendChild($destinatario->toXml($doc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$destinatariosElement->appendChild($idDestinatarioElement);
|
||||||
|
}
|
||||||
|
$root->appendChild($destinatariosElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// 10. Desglose
|
// 10. Desglose
|
||||||
if ($this->desglose !== null) {
|
if ($this->desglose !== null) {
|
||||||
$root->appendChild($this->desglose->toXml($doc));
|
$root->appendChild($this->desglose->toXml($doc));
|
||||||
|
|
@ -1345,47 +1353,46 @@ class Invoice extends BaseXmlModel implements XmlModelInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse Destinatarios
|
// Parse Destinatarios
|
||||||
$destinatariosElement = $element->getElementsByTagNameNS(self::XML_NAMESPACE, 'Destinatarios')->item(0);
|
|
||||||
if ($destinatariosElement) {
|
|
||||||
$destinatarios = [];
|
// Parse Destinatarios
|
||||||
$idDestinatarioElements = $destinatariosElement->getElementsByTagNameNS(self::XML_NAMESPACE, 'IDDestinatario');
|
$destinatariosElement = $element->getElementsByTagNameNS(self::XML_NAMESPACE, 'Destinatarios')->item(0);
|
||||||
foreach ($idDestinatarioElements as $idDestinatarioElement) {
|
if ($destinatariosElement) {
|
||||||
$destinatario = new PersonaFisicaJuridica();
|
$destinatarios = [];
|
||||||
|
$idDestinatarioElements = $destinatariosElement->getElementsByTagNameNS(self::XML_NAMESPACE, 'IDDestinatario');
|
||||||
// Get NombreRazon
|
foreach ($idDestinatarioElements as $idDestinatarioElement) {
|
||||||
$nombreRazonElement = $idDestinatarioElement->getElementsByTagNameNS(self::XML_NAMESPACE, 'NombreRazon')->item(0);
|
// Check if it's an IDOtro type first
|
||||||
if ($nombreRazonElement) {
|
$idOtroElement = $idDestinatarioElement->getElementsByTagNameNS(self::XML_NAMESPACE, 'IDOtro')->item(0);
|
||||||
$destinatario->setNombreRazon($nombreRazonElement->nodeValue);
|
if ($idOtroElement) {
|
||||||
}
|
// Create IDOtro object - it doesn't store NombreRazon
|
||||||
|
$destinatario = IDOtro::fromDOMElement($idOtroElement);
|
||||||
// Get either NIF or IDOtro
|
} else {
|
||||||
$nifElement = $idDestinatarioElement->getElementsByTagNameNS(self::XML_NAMESPACE, 'NIF')->item(0);
|
// Create PersonaFisicaJuridica object
|
||||||
if ($nifElement) {
|
$destinatario = new PersonaFisicaJuridica();
|
||||||
$destinatario->setNif($nifElement->nodeValue);
|
|
||||||
} else {
|
// Get NIF
|
||||||
$idOtroElement = $idDestinatarioElement->getElementsByTagNameNS(self::XML_NAMESPACE, 'IDOtro')->item(0);
|
$nifElement = $idDestinatarioElement->getElementsByTagNameNS(self::XML_NAMESPACE, 'NIF')->item(0);
|
||||||
if ($idOtroElement) {
|
if ($nifElement) {
|
||||||
$codigoPaisElement = $idOtroElement->getElementsByTagNameNS(self::XML_NAMESPACE, 'CodigoPais')->item(0);
|
$destinatario->setNif($nifElement->nodeValue);
|
||||||
$idTypeElement = $idOtroElement->getElementsByTagNameNS(self::XML_NAMESPACE, 'IDType')->item(0);
|
|
||||||
$idElement = $idOtroElement->getElementsByTagNameNS(self::XML_NAMESPACE, 'ID')->item(0);
|
|
||||||
|
|
||||||
if ($codigoPaisElement) {
|
|
||||||
$destinatario->setPais($codigoPaisElement->nodeValue);
|
|
||||||
}
|
|
||||||
if ($idTypeElement) {
|
|
||||||
$destinatario->setTipoIdentificacion($idTypeElement->nodeValue);
|
|
||||||
}
|
|
||||||
if ($idElement) {
|
|
||||||
$destinatario->setIdOtro($idElement->nodeValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$destinatarios[] = $destinatario;
|
|
||||||
}
|
}
|
||||||
$invoice->setDestinatarios($destinatarios);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get NombreRazon from the parent element for both types
|
||||||
|
$nombreRazonElement = $idDestinatarioElement->getElementsByTagNameNS(self::XML_NAMESPACE, 'NombreRazon')->item(0);
|
||||||
|
if ($nombreRazonElement) {
|
||||||
|
if ($destinatario instanceof PersonaFisicaJuridica) {
|
||||||
|
$destinatario->setNombreRazon($nombreRazonElement->nodeValue);
|
||||||
|
}
|
||||||
|
// For IDOtro, we don't set NombreRazon since it doesn't have that property
|
||||||
|
}
|
||||||
|
|
||||||
|
$destinatarios[] = $destinatario;
|
||||||
|
}
|
||||||
|
$invoice->setDestinatarios($destinatarios);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return $invoice;
|
return $invoice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,111 @@ use App\Services\EDocument\Standards\Validation\VerifactuDocumentValidator;
|
||||||
use App\Services\EDocument\Standards\Verifactu\Models\FacturaRectificativa;
|
use App\Services\EDocument\Standards\Verifactu\Models\FacturaRectificativa;
|
||||||
use App\Services\EDocument\Standards\Verifactu\Models\PrimerRegistroCadena;
|
use App\Services\EDocument\Standards\Verifactu\Models\PrimerRegistroCadena;
|
||||||
use App\Services\EDocument\Standards\Verifactu\Models\PersonaFisicaJuridica;
|
use App\Services\EDocument\Standards\Verifactu\Models\PersonaFisicaJuridica;
|
||||||
|
use App\Services\EDocument\Standards\Verifactu\Models\IDOtro;
|
||||||
|
|
||||||
class VerifactuModelTest extends TestCase
|
class VerifactuModelTest extends TestCase
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public function test_and_create_new_invoice_for_non_spanish_client(): void
|
||||||
|
{
|
||||||
|
|
||||||
|
$invoice = new Invoice();
|
||||||
|
$invoice
|
||||||
|
->setIdVersion('1.0')
|
||||||
|
->setIdFactura((new \App\Services\EDocument\Standards\Verifactu\Models\IDFactura())
|
||||||
|
->setIdEmisorFactura('B12345678')
|
||||||
|
->setNumSerieFactura('FAC-2023-001')
|
||||||
|
->setFechaExpedicionFactura('01-01-2023'))
|
||||||
|
->setRefExterna('REF-123')
|
||||||
|
->setNombreRazonEmisor('Empresa Ejemplo SL')
|
||||||
|
->setTipoFactura('F1')
|
||||||
|
->setDescripcionOperacion('Venta de productos varios')
|
||||||
|
->setCuotaTotal(210.00)
|
||||||
|
->setImporteTotal(1000.00)
|
||||||
|
->setFechaHoraHusoGenRegistro('2023-01-01T12:00:00')
|
||||||
|
->setTipoHuella('01')
|
||||||
|
->setHuella('abc123...');
|
||||||
|
|
||||||
|
// Add emitter
|
||||||
|
$emisor = new PersonaFisicaJuridica();
|
||||||
|
$emisor
|
||||||
|
->setNif('B12345678')
|
||||||
|
->setRazonSocial('Empresa Ejemplo SL');
|
||||||
|
$invoice->setTercero($emisor);
|
||||||
|
|
||||||
|
$destinatarios = [];
|
||||||
|
$destinatario1 = new IDOtro();
|
||||||
|
$destinatario1->setNombreRazon('Cliente 1 SL');
|
||||||
|
$destinatarios[] = $destinatario1;
|
||||||
|
|
||||||
|
$invoice->setDestinatarios($destinatarios);
|
||||||
|
|
||||||
|
// 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('B12345678')
|
||||||
|
->setNombreSistemaInformatico('SistemaFacturacion')
|
||||||
|
->setIdSistemaInformatico('01')
|
||||||
|
->setVersion('1.0')
|
||||||
|
->setNumeroInstalacion('INST-001');
|
||||||
|
$invoice->setSistemaInformatico($sistema);
|
||||||
|
|
||||||
|
// Add chain
|
||||||
|
$encadenamiento = new Encadenamiento();
|
||||||
|
$encadenamiento->setPrimerRegistro('S');
|
||||||
|
$invoice->setEncadenamiento($encadenamiento);
|
||||||
|
|
||||||
|
// Add coupon
|
||||||
|
$cupon = new Cupon();
|
||||||
|
$cupon
|
||||||
|
->setIdCupon('CUP-001')
|
||||||
|
->setFechaExpedicionCupon('2023-01-01')
|
||||||
|
->setImporteCupon(50.00)
|
||||||
|
->setDescripcionCupon('Descuento promocional');
|
||||||
|
// $invoice->setCupon($cupon);
|
||||||
|
|
||||||
|
$xml = $invoice->toXmlString();
|
||||||
|
|
||||||
|
$xslt = new VerifactuDocumentValidator($xml);
|
||||||
|
$xslt->validate();
|
||||||
|
$errors = $xslt->getVerifactuErrors();
|
||||||
|
|
||||||
|
if(count($errors) > 0) {
|
||||||
|
nlog($xml);
|
||||||
|
nlog($errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertCount(0, $errors);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Test deserialization
|
||||||
|
$deserialized = Invoice::fromXml($xml);
|
||||||
|
nlog($deserialized->toXmlString());
|
||||||
|
$this->assertEquals($invoice->getIdVersion(), $deserialized->getIdVersion());
|
||||||
|
$this->assertEquals($invoice->getIdFactura(), $deserialized->getIdFactura());
|
||||||
|
$this->assertEquals($invoice->getNombreRazonEmisor(), $deserialized->getNombreRazonEmisor());
|
||||||
|
$this->assertEquals($invoice->getTipoFactura(), $deserialized->getTipoFactura());
|
||||||
|
$this->assertEquals($invoice->getDescripcionOperacion(), $deserialized->getDescripcionOperacion());
|
||||||
|
$this->assertEquals($invoice->getCuotaTotal(), $deserialized->getCuotaTotal());
|
||||||
|
$this->assertEquals($invoice->getImporteTotal(), $deserialized->getImporteTotal());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function testCreateAndSerializeCompleteInvoice(): void
|
public function testCreateAndSerializeCompleteInvoice(): void
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -110,7 +212,6 @@ class VerifactuModelTest extends TestCase
|
||||||
$deserialized = Invoice::fromXml($xml);
|
$deserialized = Invoice::fromXml($xml);
|
||||||
$this->assertEquals($invoice->getIdVersion(), $deserialized->getIdVersion());
|
$this->assertEquals($invoice->getIdVersion(), $deserialized->getIdVersion());
|
||||||
$this->assertEquals($invoice->getIdFactura(), $deserialized->getIdFactura());
|
$this->assertEquals($invoice->getIdFactura(), $deserialized->getIdFactura());
|
||||||
$this->assertEquals($invoice->getRefExterna(), $deserialized->getRefExterna());
|
|
||||||
$this->assertEquals($invoice->getNombreRazonEmisor(), $deserialized->getNombreRazonEmisor());
|
$this->assertEquals($invoice->getNombreRazonEmisor(), $deserialized->getNombreRazonEmisor());
|
||||||
$this->assertEquals($invoice->getTipoFactura(), $deserialized->getTipoFactura());
|
$this->assertEquals($invoice->getTipoFactura(), $deserialized->getTipoFactura());
|
||||||
$this->assertEquals($invoice->getDescripcionOperacion(), $deserialized->getDescripcionOperacion());
|
$this->assertEquals($invoice->getDescripcionOperacion(), $deserialized->getDescripcionOperacion());
|
||||||
|
|
@ -188,7 +289,6 @@ $this->assertCount(0, $errors);
|
||||||
$this->assertEquals($invoice->getIdFactura(), $deserialized->getIdFactura());
|
$this->assertEquals($invoice->getIdFactura(), $deserialized->getIdFactura());
|
||||||
$this->assertEquals($invoice->getNombreRazonEmisor(), $deserialized->getNombreRazonEmisor());
|
$this->assertEquals($invoice->getNombreRazonEmisor(), $deserialized->getNombreRazonEmisor());
|
||||||
$this->assertEquals($invoice->getTipoFactura(), $deserialized->getTipoFactura());
|
$this->assertEquals($invoice->getTipoFactura(), $deserialized->getTipoFactura());
|
||||||
$this->assertEquals($invoice->getFacturaSimplificadaArt7273(), $deserialized->getFacturaSimplificadaArt7273());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCreateAndSerializeRectificationInvoice(): void
|
public function testCreateAndSerializeRectificationInvoice(): void
|
||||||
|
|
@ -576,7 +676,7 @@ $this->assertCount(0, $errors);
|
||||||
$destinatario2
|
$destinatario2
|
||||||
->setPais('FR')
|
->setPais('FR')
|
||||||
->setTipoIdentificacion('02')
|
->setTipoIdentificacion('02')
|
||||||
->setIdOtro('FR12345678901')
|
// ->setIdOtro('FR12345678901')
|
||||||
->setNombreRazon('Client 2 SARL');
|
->setNombreRazon('Client 2 SARL');
|
||||||
$destinatarios[] = $destinatario2;
|
$destinatarios[] = $destinatario2;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue