202 lines
5.7 KiB
PHP
202 lines
5.7 KiB
PHP
<?php
|
|
/**
|
|
* Invoice Ninja (https://invoiceninja.com).
|
|
*
|
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
|
*
|
|
* @copyright Copyright (c) 2025. Invoice Ninja LLC (https://invoiceninja.com)
|
|
*
|
|
* @license https://www.elastic.co/licensing/elastic-license
|
|
*/
|
|
|
|
namespace App\Services\EDocument\Standards;
|
|
|
|
use App\Models\Company;
|
|
use App\Models\Invoice;
|
|
use App\Models\Product;
|
|
use App\Models\VerifactuLog;
|
|
use App\Helpers\Invoice\Taxer;
|
|
use App\DataMapper\Tax\BaseRule;
|
|
use App\Services\AbstractService;
|
|
use App\Helpers\Invoice\InvoiceSum;
|
|
use App\Utils\Traits\NumberFormatter;
|
|
use App\Helpers\Invoice\InvoiceSumInclusive;
|
|
use App\Services\EDocument\Standards\Verifactu\AeatClient;
|
|
use App\Services\EDocument\Standards\Verifactu\RegistroAlta;
|
|
use App\Services\EDocument\Standards\Verifactu\Models\Desglose;
|
|
use App\Services\EDocument\Standards\Verifactu\Models\Encadenamiento;
|
|
use App\Services\EDocument\Standards\Verifactu\Models\RegistroAnterior;
|
|
use App\Services\EDocument\Standards\Verifactu\Models\SistemaInformatico;
|
|
use App\Services\EDocument\Standards\Verifactu\Models\PersonaFisicaJuridica;
|
|
use App\Services\EDocument\Standards\Verifactu\Models\Invoice as VerifactuInvoice;
|
|
|
|
class Verifactu extends AbstractService
|
|
{
|
|
|
|
private AeatClient $aeat_client;
|
|
|
|
private string $soapXml;
|
|
|
|
//store the current document state
|
|
private VerifactuInvoice $_document;
|
|
|
|
//store the current huella
|
|
private string $_huella;
|
|
|
|
private string $_previous_huella;
|
|
|
|
public function __construct(public Invoice $invoice)
|
|
{
|
|
$this->aeat_client = new AeatClient();
|
|
}
|
|
|
|
/**
|
|
* Entry point for building document
|
|
*
|
|
* @return self
|
|
*/
|
|
public function run(): self
|
|
{
|
|
|
|
$v_logs = $this->invoice->company->verifactu_logs;
|
|
|
|
$i_logs = $this->invoice->verifactu_logs;
|
|
|
|
$document = (new RegistroAlta($this->invoice))->run();
|
|
|
|
if($this->invoice->amount < 0) {
|
|
$document = $document->setRectification();
|
|
}
|
|
|
|
$document = $document->getInvoice();
|
|
|
|
//keep this state for logging later on successful send
|
|
$this->_document = $document;
|
|
|
|
$this->_previous_huella = '';
|
|
|
|
if($v_logs->count() >= 1){
|
|
$v_log = $v_logs->first();
|
|
$this->_previous_huella = $v_log->hash;
|
|
}
|
|
|
|
$this->_huella = $this->calculateHash($document, $this->_previous_huella); // careful with this! we'll need to reference this later
|
|
$document->setHuella($this->_huella);
|
|
|
|
$this->setEnvelope($document->toSoapEnvelope());
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
/**
|
|
* setHuella
|
|
* We need this for cancellation documents.
|
|
*
|
|
* @param string $huella
|
|
* @return self
|
|
*/
|
|
public function setHuella(string $huella): self
|
|
{
|
|
$this->_huella = $huella;
|
|
return $this;
|
|
}
|
|
|
|
public function getInvoice()
|
|
{
|
|
return $this->_document;
|
|
}
|
|
|
|
public function setInvoice(VerifactuInvoice $invoice): self
|
|
{
|
|
$this->_document = $invoice;
|
|
return $this;
|
|
}
|
|
|
|
public function getEnvelope(): string
|
|
{
|
|
return $this->soapXml;
|
|
}
|
|
|
|
public function setTestMode(): self
|
|
{
|
|
$this->aeat_client->setTestMode();
|
|
return $this;
|
|
}
|
|
/**
|
|
* setPreviousHash
|
|
*
|
|
* **only used for testing**
|
|
* @param string $previous_hash
|
|
* @return self
|
|
*/
|
|
public function setPreviousHash(string $previous_hash): self
|
|
{
|
|
$this->_previous_huella = $previous_hash;
|
|
return $this;
|
|
}
|
|
|
|
private function setEnvelope(string $soapXml): self
|
|
{
|
|
$this->soapXml = $soapXml;
|
|
return $this;
|
|
}
|
|
|
|
public function writeLog(array $response)
|
|
{
|
|
VerifactuLog::create([
|
|
'invoice_id' => $this->invoice->id,
|
|
'company_id' => $this->invoice->company_id,
|
|
'invoice_number' => $this->invoice->number,
|
|
'date' => $this->invoice->date,
|
|
'hash' => $this->_huella,
|
|
'nif' => $this->_document->getIdFactura()->getIdEmisorFactura(),
|
|
'previous_hash' => $this->_previous_huella,
|
|
'state' => $this->_document->serialize(),
|
|
'response' => $response,
|
|
'status' => $response['guid'],
|
|
]);
|
|
}
|
|
/**
|
|
* calculateHash
|
|
*
|
|
* @param mixed $document
|
|
* @param string $huella
|
|
* @return string
|
|
*/
|
|
public function calculateHash($document, string $huella): string
|
|
{
|
|
|
|
$idEmisorFactura = $document->getIdFactura()->getIdEmisorFactura();
|
|
$numSerieFactura = $document->getIdFactura()->getNumSerieFactura();
|
|
$fechaExpedicionFactura = $document->getIdFactura()->getFechaExpedicionFactura();
|
|
$tipoFactura = $document->getTipoFactura();
|
|
$cuotaTotal = $document->getCuotaTotal();
|
|
$importeTotal = $document->getImporteTotal();
|
|
$fechaHoraHusoGenRegistro = $document->getFechaHoraHusoGenRegistro();
|
|
|
|
$hashInput = "IDEmisorFactura={$idEmisorFactura}&" .
|
|
"NumSerieFactura={$numSerieFactura}&" .
|
|
"FechaExpedicionFactura={$fechaExpedicionFactura}&" .
|
|
"TipoFactura={$tipoFactura}&" .
|
|
"CuotaTotal={$cuotaTotal}&" .
|
|
"ImporteTotal={$importeTotal}&" .
|
|
"Huella={$huella}&" .
|
|
"FechaHoraHusoGenRegistro={$fechaHoraHusoGenRegistro}";
|
|
|
|
return strtoupper(hash('sha256', $hashInput));
|
|
}
|
|
|
|
public function send(string $soapXml): array
|
|
{
|
|
nlog(["sending", $soapXml]);
|
|
|
|
$response = $this->aeat_client->send($soapXml);
|
|
|
|
if($response['success'] || $response['status'] == 'ParcialmenteCorrecto'){
|
|
$this->writeLog($response);
|
|
}
|
|
|
|
return $response;
|
|
}
|
|
} |