invoiceninja/app/Services/EDocument/Standards/Verifactu/Models/InvoiceModification.php

221 lines
9.7 KiB
PHP

<?php
namespace App\Services\EDocument\Standards\Verifactu\Models;
/**
* InvoiceModification - Complete Invoice Modification Container
*
* This class represents the complete modification structure required for Verifactu e-invoicing
* modification operations. It contains both the cancellation record and the modification record.
*/
class InvoiceModification extends BaseXmlModel
{
protected RegistroAnulacion $registroAnulacion;
protected RegistroModificacion $registroModificacion;
protected SistemaInformatico $sistemaInformatico;
// @todo - in the UI we'll need additional logic to support these codes
private array $motivo_anulacion_codes = [
'1' => "Sustitución por otra factura", // Replacement by another invoice
'2' => "Error en facturación", // Billing error
'3' => "Anulación por devolución", // Cancellation due to return
'4' => "Anulación por insolvencia" // Cancellation due to insolvency
];
public function __construct()
{
$this->registroAnulacion = new RegistroAnulacion();
$this->registroModificacion = new RegistroModificacion();
$this->sistemaInformatico = new SistemaInformatico();
}
public function getRegistroAnulacion(): RegistroAnulacion
{
return $this->registroAnulacion;
}
public function setRegistroAnulacion(RegistroAnulacion $registroAnulacion): self
{
$this->registroAnulacion = $registroAnulacion;
return $this;
}
public function getRegistroModificacion(): RegistroModificacion
{
return $this->registroModificacion;
}
public function setRegistroModificacion(RegistroModificacion $registroModificacion): self
{
$this->registroModificacion = $registroModificacion;
return $this;
}
public function getSistemaInformatico(): SistemaInformatico
{
return $this->sistemaInformatico;
}
public function setSistemaInformatico(SistemaInformatico $sistemaInformatico): self
{
$this->sistemaInformatico = $sistemaInformatico;
return $this;
}
/**
* Create a modification from an existing invoice
*/
public static function createFromInvoice(Invoice $originalInvoice, Invoice $modifiedInvoice): self
{
$modification = new self();
// Set up cancellation record
$cancellation = new RegistroAnulacion();
$cancellation
->setIdEmisorFactura($originalInvoice->getTercero()?->getNif() ?? 'B12345678')
->setNumSerieFactura($originalInvoice->getIdFactura())
->setFechaExpedicionFactura($originalInvoice->getFechaExpedicionFactura())
->setMotivoAnulacion('1'); // Sustitución por otra factura
$modification->setRegistroAnulacion($cancellation);
// Set up modification record
$modificationRecord = new RegistroModificacion();
$modificationRecord
->setIdVersion($modifiedInvoice->getIdVersion())
->setIdFactura($modifiedInvoice->getIdFactura())
->setRefExterna($modifiedInvoice->getRefExterna())
->setNombreRazonEmisor($modifiedInvoice->getNombreRazonEmisor())
->setSubsanacion($modifiedInvoice->getSubsanacion())
->setRechazoPrevio($modifiedInvoice->getRechazoPrevio())
->setTipoFactura($modifiedInvoice->getTipoFactura())
->setTipoRectificativa($modifiedInvoice->getTipoRectificativa())
->setFacturasRectificadas($modifiedInvoice->getFacturasRectificadas())
->setFacturasSustituidas($modifiedInvoice->getFacturasSustituidas())
->setImporteRectificacion($modifiedInvoice->getImporteRectificacion())
->setFechaOperacion($modifiedInvoice->getFechaOperacion())
->setDescripcionOperacion($modifiedInvoice->getDescripcionOperacion())
->setFacturaSimplificadaArt7273($modifiedInvoice->getFacturaSimplificadaArt7273())
->setFacturaSinIdentifDestinatarioArt61d($modifiedInvoice->getFacturaSinIdentifDestinatarioArt61d())
->setMacrodato($modifiedInvoice->getMacrodato())
->setEmitidaPorTerceroODestinatario($modifiedInvoice->getEmitidaPorTerceroODestinatario())
->setTercero($modifiedInvoice->getTercero())
->setDestinatarios($modifiedInvoice->getDestinatarios())
->setCupon($modifiedInvoice->getCupon())
->setDesglose($modifiedInvoice->getDesglose())
->setCuotaTotal($modifiedInvoice->getCuotaTotal())
->setImporteTotal($modifiedInvoice->getImporteTotal())
->setEncadenamiento($modifiedInvoice->getEncadenamiento())
->setSistemaInformatico($modifiedInvoice->getSistemaInformatico())
->setFechaHoraHusoGenRegistro($modifiedInvoice->getFechaHoraHusoGenRegistro())
->setNumRegistroAcuerdoFacturacion($modifiedInvoice->getNumRegistroAcuerdoFacturacion())
->setIdAcuerdoSistemaInformatico($modifiedInvoice->getIdAcuerdoSistemaInformatico())
->setTipoHuella($modifiedInvoice->getTipoHuella())
->setHuella($modifiedInvoice->getHuella());
$modification->setRegistroModificacion($modificationRecord);
// Set up sistema informatico for the modification
$modification->setSistemaInformatico($modifiedInvoice->getSistemaInformatico());
return $modification;
}
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 ModificacionFactura
$modificacionFactura = $soapDoc->createElementNS('https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroLR.xsd', 'sum:ModificacionFactura');
$body->appendChild($modificacionFactura);
// Add RegistroAnulacion
$registroAnulacionElement = $this->registroAnulacion->toXml($soapDoc);
$importedRegistroAnulacion = $soapDoc->importNode($registroAnulacionElement, true);
$modificacionFactura->appendChild($importedRegistroAnulacion);
// Add RegistroModificacion
$registroModificacionElement = $this->registroModificacion->toXml($soapDoc);
$importedRegistroModificacion = $soapDoc->importNode($registroModificacionElement, true);
$modificacionFactura->appendChild($importedRegistroModificacion);
return $soapDoc->saveXML();
}
public function toXmlString(): string
{
$doc = new \DOMDocument('1.0', 'UTF-8');
$doc->preserveWhiteSpace = false;
$doc->formatOutput = true;
// Create ModificacionFactura root
$root = $doc->createElementNS(self::XML_NAMESPACE, self::XML_NAMESPACE_PREFIX . ':ModificacionFactura');
$doc->appendChild($root);
// Add RegistroAnulacion
$registroAnulacionElement = $this->registroAnulacion->toXml($doc);
$root->appendChild($registroAnulacionElement);
// Add RegistroModificacion
$registroModificacionElement = $this->registroModificacion->toXml($doc);
$root->appendChild($registroModificacionElement);
return $doc->saveXML();
}
public function toXml(\DOMDocument $doc): \DOMElement
{
// Create ModificacionFactura root
$root = $doc->createElementNS(self::XML_NAMESPACE, self::XML_NAMESPACE_PREFIX . ':ModificacionFactura');
// Add RegistroAnulacion
$registroAnulacionElement = $this->registroAnulacion->toXml($doc);
$root->appendChild($registroAnulacionElement);
// Add RegistroModificacion
$registroModificacionElement = $this->registroModificacion->toXml($doc);
$root->appendChild($registroModificacionElement);
return $root;
}
public static function fromDOMElement(\DOMElement $element): self
{
$modification = new self();
// Handle RegistroAnulacion
$registroAnulacionElement = $element->getElementsByTagNameNS(self::XML_NAMESPACE, 'RegistroAnulacion')->item(0);
if ($registroAnulacionElement) {
$registroAnulacion = RegistroAnulacion::fromDOMElement($registroAnulacionElement);
$modification->setRegistroAnulacion($registroAnulacion);
}
// Handle RegistroModificacion
$registroModificacionElement = $element->getElementsByTagNameNS(self::XML_NAMESPACE, 'RegistroModificacion')->item(0);
if ($registroModificacionElement) {
$registroModificacion = RegistroModificacion::fromDOMElement($registroModificacionElement);
$modification->setRegistroModificacion($registroModificacion);
}
return $modification;
}
}