mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Split einvoice gateways
This commit is contained in:
parent
50faf3261b
commit
737e18aa42
63
app/Services/EDocument/Gateway/MutatorInterface.php
Normal file
63
app/Services/EDocument/Gateway/MutatorInterface.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2024. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Services\EDocument\Gateway;
|
||||
|
||||
interface MutatorInterface
|
||||
{
|
||||
|
||||
public function receiverSpecificLevelMutators(): self;
|
||||
|
||||
public function senderSpecificLevelMutators(): self;
|
||||
|
||||
public function setInvoice($invoice): self;
|
||||
|
||||
public function setPeppol($p_invoice): self;
|
||||
|
||||
public function getPeppol(): mixed;
|
||||
|
||||
public function setClientSettings($client_settings): self;
|
||||
|
||||
public function setCompanySettings($company_settings): self;
|
||||
|
||||
// Country-specific methods
|
||||
public function DE(): self;
|
||||
|
||||
public function CH(): self;
|
||||
|
||||
public function AT(): self;
|
||||
|
||||
public function AU(): self;
|
||||
|
||||
public function ES(): self;
|
||||
|
||||
public function FI(): self;
|
||||
|
||||
public function FR(): self;
|
||||
|
||||
public function IT(): self;
|
||||
|
||||
public function client_IT(): self;
|
||||
|
||||
public function MY(): self;
|
||||
|
||||
public function NL(): self;
|
||||
|
||||
public function NZ(): self;
|
||||
|
||||
public function PL(): self;
|
||||
|
||||
public function RO(): self;
|
||||
|
||||
public function SG(): self;
|
||||
|
||||
public function SE(): self;
|
||||
}
|
135
app/Services/EDocument/Gateway/MutatorUtil.php
Normal file
135
app/Services/EDocument/Gateway/MutatorUtil.php
Normal file
@ -0,0 +1,135 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2024. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Services\EDocument\Gateway;
|
||||
|
||||
use App\Exceptions\PeppolValidationException;
|
||||
use App\Services\EDocument\Standards\Settings\PropertyResolver;
|
||||
|
||||
class MutatorUtil
|
||||
{
|
||||
|
||||
public function __construct(public MutatorInterface $mutator)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* setPaymentMeans
|
||||
*
|
||||
* Sets the payment means - if it exists
|
||||
* @param bool $required
|
||||
* @return self
|
||||
*/
|
||||
public function setPaymentMeans(bool $required = false): self
|
||||
{
|
||||
|
||||
if(isset($this->mutator->p_invoice->PaymentMeans)) {
|
||||
return $this;
|
||||
} elseif($paymentMeans = $this->getSetting('Invoice.PaymentMeans')) {
|
||||
$this->mutator->p_invoice->PaymentMeans = is_array($paymentMeans) ? $paymentMeans : [$paymentMeans];
|
||||
return $this;
|
||||
}
|
||||
|
||||
return $this->checkRequired($required, "Payment Means");
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* getClientSetting
|
||||
*
|
||||
* @param string $property_path
|
||||
* @return mixed
|
||||
*/
|
||||
public function getClientSetting(string $property_path): mixed
|
||||
{
|
||||
return PropertyResolver::resolve($this->mutator->_client_settings, $property_path);
|
||||
}
|
||||
|
||||
/**
|
||||
* getCompanySetting
|
||||
*
|
||||
* @param string $property_path
|
||||
* @return mixed
|
||||
*/
|
||||
public function getCompanySetting(string $property_path): mixed
|
||||
{
|
||||
return PropertyResolver::resolve($this->mutator->_company_settings, $property_path);
|
||||
}
|
||||
|
||||
/**
|
||||
* getSetting
|
||||
*
|
||||
* Attempts to harvest and return a preconfigured prop from company / client / invoice settings
|
||||
*
|
||||
* @param string $property_path
|
||||
* @return mixed
|
||||
*/
|
||||
public function getSetting(string $property_path): mixed
|
||||
{
|
||||
|
||||
if($prop_value = PropertyResolver::resolve($this->mutator->p_invoice, $property_path)) {
|
||||
return $prop_value;
|
||||
} elseif($prop_value = PropertyResolver::resolve($this->mutator->_client_settings, $property_path)) {
|
||||
return $prop_value;
|
||||
} elseif($prop_value = PropertyResolver::resolve($this->mutator->_company_settings, $property_path)) {
|
||||
return $prop_value;
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check Required
|
||||
*
|
||||
* Throws if a required field is missing.
|
||||
*
|
||||
* @param bool $required
|
||||
* @param string $section
|
||||
* @return self
|
||||
*/
|
||||
public function checkRequired(bool $required, string $section): self
|
||||
{
|
||||
return $required ? throw new PeppolValidationException("e-invoice generation halted:: {$section} required", $section, 400) : $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* setCustomerAssignedAccountId
|
||||
*
|
||||
* Sets the client id_number CAN rely on settings
|
||||
*
|
||||
* @param bool $required
|
||||
* @return self
|
||||
*/
|
||||
public function setCustomerAssignedAccountId(bool $required = false): self
|
||||
{
|
||||
//@phpstan-ignore-next-line
|
||||
if(isset($this->mutator->p_invoice->AccountingCustomerParty->CustomerAssignedAccountID)) {
|
||||
return $this;
|
||||
} elseif($customer_assigned_account_id = $this->getSetting('Invoice.AccountingCustomerParty.CustomerAssignedAccountID')) {
|
||||
|
||||
$this->mutator->p_invoice->AccountingCustomerParty->CustomerAssignedAccountID = $customer_assigned_account_id;
|
||||
return $this;
|
||||
} elseif(strlen($this->mutator->invoice->client->id_number ?? '') > 1) {
|
||||
|
||||
$customer_assigned_account_id = new CustomerAssignedAccountID();
|
||||
$customer_assigned_account_id->value = $this->mutator->invoice->client->id_number;
|
||||
|
||||
$this->mutator->p_invoice->AccountingCustomerParty->CustomerAssignedAccountID = $customer_assigned_account_id;
|
||||
return $this;
|
||||
}
|
||||
|
||||
//@phpstan-ignore-next-line
|
||||
return $this->checkRequired($required, 'Client ID Number');
|
||||
|
||||
}
|
||||
|
||||
}
|
163
app/Services/EDocument/Gateway/Qvalia/Mutator.php
Normal file
163
app/Services/EDocument/Gateway/Qvalia/Mutator.php
Normal file
@ -0,0 +1,163 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2024. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Services\EDocument\Gateway\Qvalia;
|
||||
|
||||
use App\Services\EDocument\Gateway\MutatorInterface;
|
||||
|
||||
class Mutator implements MutatorInterface
|
||||
{
|
||||
|
||||
private \InvoiceNinja\EInvoice\Models\Peppol\Invoice $p_invoice;
|
||||
|
||||
private ?\InvoiceNinja\EInvoice\Models\Peppol\Invoice $_client_settings;
|
||||
|
||||
private ?\InvoiceNinja\EInvoice\Models\Peppol\Invoice $_company_settings;
|
||||
|
||||
private $invoice;
|
||||
|
||||
public function __construct(public Qvalia $qvalia)
|
||||
{
|
||||
}
|
||||
|
||||
public function setInvoice($invoice): self
|
||||
{
|
||||
$this->invoice = $invoice;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setPeppol($p_invoice): self
|
||||
{
|
||||
$this->p_invoice = $p_invoice;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPeppol(): mixed
|
||||
{
|
||||
return $this->p_invoice;
|
||||
}
|
||||
|
||||
public function setClientSettings($client_settings): self
|
||||
{
|
||||
$this->_client_settings = $client_settings;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setCompanySettings($company_settings): self
|
||||
{
|
||||
$this->_company_settings = $company_settings;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* senderSpecificLevelMutators
|
||||
*
|
||||
* Runs sender level specific requirements for the e-invoice,
|
||||
*
|
||||
* ie, mutations that are required by the senders country.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function senderSpecificLevelMutators(): self
|
||||
{
|
||||
|
||||
if(method_exists($this, $this->invoice->company->country()->iso_3166_2)) {
|
||||
$this->{$this->invoice->company->country()->iso_3166_2}();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* receiverSpecificLevelMutators
|
||||
*
|
||||
* Runs receiver level specific requirements for the e-invoice
|
||||
*
|
||||
* ie mutations that are required by the receiving country
|
||||
* @return self
|
||||
*/
|
||||
public function receiverSpecificLevelMutators(): self
|
||||
{
|
||||
|
||||
if(method_exists($this, "client_{$this->invoice->company->country()->iso_3166_2}")) {
|
||||
$this->{"client_{$this->invoice->company->country()->iso_3166_2}"}();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
// Country-specific methods
|
||||
public function DE(): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
public function CH(): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
public function AT(): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
public function AU(): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
public function ES(): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
public function FI(): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
public function FR(): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
public function IT(): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
public function client_IT(): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
public function MY(): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
public function NL(): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
public function NZ(): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
public function PL(): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
public function RO(): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
public function SG(): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
public function SE(): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
@ -53,6 +53,7 @@ class Qvalia
|
||||
|
||||
public Invoice $invoice;
|
||||
|
||||
public Mutator $mutator;
|
||||
//integrationid - returned in headers
|
||||
|
||||
public function __construct()
|
||||
@ -60,6 +61,7 @@ class Qvalia
|
||||
$this->init();
|
||||
$this->partner = new Partner($this);
|
||||
$this->invoice = new Invoice($this);
|
||||
$this->mutator = new Mutator($this);
|
||||
}
|
||||
|
||||
private function init(): self
|
||||
|
622
app/Services/EDocument/Gateway/Storecove/Mutator.php
Normal file
622
app/Services/EDocument/Gateway/Storecove/Mutator.php
Normal file
@ -0,0 +1,622 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2024. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Services\EDocument\Gateway\Storecove;
|
||||
|
||||
use App\Services\EDocument\Gateway\MutatorUtil;
|
||||
use App\Services\EDocument\Standards\Peppol\RO;
|
||||
use App\Services\EDocument\Gateway\MutatorInterface;
|
||||
use App\Services\EDocument\Gateway\Storecove\StorecoveRouter;
|
||||
|
||||
class Mutator implements MutatorInterface
|
||||
{
|
||||
|
||||
public \InvoiceNinja\EInvoice\Models\Peppol\Invoice $p_invoice;
|
||||
|
||||
public ?\InvoiceNinja\EInvoice\Models\Peppol\Invoice $_client_settings;
|
||||
|
||||
public ?\InvoiceNinja\EInvoice\Models\Peppol\Invoice $_company_settings;
|
||||
|
||||
public $invoice;
|
||||
|
||||
private array $storecove_meta = [];
|
||||
|
||||
private MutatorUtil $mutator_util;
|
||||
// Constructor
|
||||
public function __construct(public Storecove $storecove)
|
||||
{
|
||||
$this->mutator_util = new MutatorUtil($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* setInvoice
|
||||
*
|
||||
* @param mixed $invoice
|
||||
* @return self
|
||||
*/
|
||||
public function setInvoice($invoice): self
|
||||
{
|
||||
$this->invoice = $invoice;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* setPeppol
|
||||
*
|
||||
* @param mixed $p_invoice
|
||||
* @return self
|
||||
*/
|
||||
public function setPeppol($p_invoice): self
|
||||
{
|
||||
$this->p_invoice = $p_invoice;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* getPeppol
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPeppol(): mixed
|
||||
{
|
||||
return $this->p_invoice;
|
||||
}
|
||||
|
||||
/**
|
||||
* setClientSettings
|
||||
*
|
||||
* @param mixed $client_settings
|
||||
* @return self
|
||||
*/
|
||||
public function setClientSettings($client_settings): self
|
||||
{
|
||||
$this->_client_settings = $client_settings;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* setCompanySettings
|
||||
*
|
||||
* @param mixed $company_settings
|
||||
* @return self
|
||||
*/
|
||||
public function setCompanySettings($company_settings): self
|
||||
{
|
||||
$this->_company_settings = $company_settings;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* senderSpecificLevelMutators
|
||||
*
|
||||
* Runs sender level specific requirements for the e-invoice,
|
||||
*
|
||||
* ie, mutations that are required by the senders country.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function senderSpecificLevelMutators(): self
|
||||
{
|
||||
|
||||
if(method_exists($this, $this->invoice->company->country()->iso_3166_2)) {
|
||||
$this->{$this->invoice->company->country()->iso_3166_2}();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* receiverSpecificLevelMutators
|
||||
*
|
||||
* Runs receiver level specific requirements for the e-invoice
|
||||
*
|
||||
* ie mutations that are required by the receiving country
|
||||
* @return self
|
||||
*/
|
||||
public function receiverSpecificLevelMutators(): self
|
||||
{
|
||||
|
||||
if(method_exists($this, "client_{$this->invoice->company->country()->iso_3166_2}")) {
|
||||
$this->{"client_{$this->invoice->company->country()->iso_3166_2}"}();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* DE
|
||||
*
|
||||
* @Completed
|
||||
* @Tested
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function DE(): self
|
||||
{
|
||||
|
||||
$this->mutator_util->setPaymentMeans(true);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* CH
|
||||
*
|
||||
* @Completed
|
||||
*
|
||||
* Completed - QR-Bill to be implemented at a later date.
|
||||
* @return self
|
||||
*/
|
||||
public function CH(): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* AT
|
||||
*
|
||||
* @Pending
|
||||
*
|
||||
* Need to ensure when sending to government entities that we route appropriately
|
||||
* Also need to ensure customerAssignedAccountIdValue is set so that the sender can be resolved.
|
||||
*
|
||||
* Need a way to define if the client is a government entity.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function AT(): self
|
||||
{
|
||||
//special fields for sending to AT:GOV
|
||||
|
||||
if($this->invoice->client->classification == 'government') {
|
||||
//routing "b" for production "test" for test environment
|
||||
$this->setStorecoveMeta($this->buildRouting(["scheme" => 'AT:GOV', "id" => 'b']));
|
||||
|
||||
//for government clients this must be set.
|
||||
$this->mutator_util->setCustomerAssignedAccountId(true);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function AU(): self
|
||||
{
|
||||
|
||||
//if payment means are included, they must be the same `type`
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* ES
|
||||
*
|
||||
* @Pending
|
||||
* B2G configuration
|
||||
* B2G Testing
|
||||
*
|
||||
* testing. // routing identifier - 293098
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function ES(): self
|
||||
{
|
||||
|
||||
if(!isset($this->invoice->due_date)) {
|
||||
$this->p_invoice->DueDate = new \DateTime($this->invoice->date);
|
||||
}
|
||||
|
||||
if($this->invoice->client->classification == 'business' && $this->invoice->company->getSetting('classification') == 'business') {
|
||||
//must have a paymentmeans as credit_transfer
|
||||
$this->mutator_util->setPaymentMeans(true);
|
||||
}
|
||||
|
||||
// For B2G, provide three ES:FACE identifiers in the routing object,
|
||||
// as well as the ES:VAT tax identifier in the accountingCustomerParty.publicIdentifiers.
|
||||
// The invoice will then be routed through the FACe network. The three required ES:FACE identifiers are as follows:
|
||||
// "routing": {
|
||||
// "eIdentifiers":[
|
||||
// {
|
||||
// "scheme": "ES:FACE",
|
||||
// "id": "L01234567",
|
||||
// "role": "ES-01-FISCAL"
|
||||
// },
|
||||
// {
|
||||
// "scheme": "ES:FACE",
|
||||
// "id": "L01234567",
|
||||
// "role": "ES-02-RECEPTOR"
|
||||
// },
|
||||
// {
|
||||
// "scheme": "ES:FACE",
|
||||
// "id": "L01234567",
|
||||
// "role": "ES-03-PAGADOR"
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* FI
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function FI(): self
|
||||
{
|
||||
|
||||
// For Finvoice, provide an FI:OPID routing identifier and an FI:OVT legal identifier.
|
||||
// An FI:VAT is recommended. In many cases (depending on the sender/receiver country and the type of service/goods)
|
||||
// an FI:VAT is required. So we recommend always including this.
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* FR
|
||||
* @Pending - clarification on codes needed
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function FR(): self
|
||||
{
|
||||
|
||||
// When sending invoices to the French government (Chorus Pro):
|
||||
// All invoices have to be routed to SIRET 0009:11000201100044. There is no test environment for sending to public entities.
|
||||
// The SIRET / 0009 identifier of the final recipient is to be included in the invoice.accountingCustomerParty.publicIdentifiers array.
|
||||
|
||||
if($this->invoice->client->classification == 'government') {
|
||||
//route to SIRET 0009:11000201100044
|
||||
$this->setStorecoveMeta($this->buildRouting([
|
||||
["scheme" => 'FR:SIRET', "id" => '11000201100044']
|
||||
|
||||
// ["scheme" => 'FR:SIRET', "id" => '0009:11000201100044']
|
||||
]));
|
||||
|
||||
// The SIRET / 0009 identifier of the final recipient is to be included in the invoice.accountingCustomerParty.publicIdentifiers array.
|
||||
$this->mutator_util->setCustomerAssignedAccountId(true);
|
||||
|
||||
}
|
||||
|
||||
if(strlen($this->invoice->client->id_number ?? '') == 9) {
|
||||
//SIREN
|
||||
$this->setStorecoveMeta($this->buildRouting([
|
||||
["scheme" => 'FR:SIRET', "id" => "{$this->invoice->client->id_number}"]
|
||||
|
||||
// ["scheme" => 'FR:SIRET', "id" => "0002:{$this->invoice->client->id_number}"]
|
||||
]));
|
||||
} else {
|
||||
//SIRET
|
||||
$this->setStorecoveMeta($this->buildRouting([
|
||||
["scheme" => 'FR:SIRET', "id" => "{$this->invoice->client->id_number}"]
|
||||
|
||||
// ["scheme" => 'FR:SIRET', "id" => "0009:{$this->invoice->client->id_number}"]
|
||||
]));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* IT
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function IT(): self
|
||||
{
|
||||
|
||||
// IT Sender, IT Receiver, B2B/B2G
|
||||
// Provide the receiver IT:VAT and the receiver IT:CUUO (codice destinatario)
|
||||
if(in_array($this->invoice->client->classification, ['business','government']) && $this->invoice->company->country()->iso_3166_2 == 'IT') {
|
||||
|
||||
$this->setStorecoveMeta($this->buildRouting([
|
||||
["scheme" => 'IT:IVA', "id" => $this->invoice->client->vat_number],
|
||||
["scheme" => 'IT:CUUO', "id" => $this->invoice->client->routing_id]
|
||||
]));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
// IT Sender, IT Receiver, B2C
|
||||
// Provide the receiver IT:CF and the receiver IT:CUUO (codice destinatario)
|
||||
if($this->invoice->client->classification == 'individual' && $this->invoice->company->country()->iso_3166_2 == 'IT') {
|
||||
|
||||
$this->setStorecoveMeta($this->buildRouting([
|
||||
["scheme" => 'IT:CF', "id" => $this->invoice->client->vat_number],
|
||||
// ["scheme" => 'IT:CUUO', "id" => $this->invoice->client->routing_id]
|
||||
]));
|
||||
|
||||
$this->setEmailRouting($this->invoice->client->present()->email());
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
// IT Sender, non-IT Receiver
|
||||
// Provide the receiver tax identifier and any routing identifier applicable to the receiving country (see Receiver Identifiers).
|
||||
if($this->invoice->client->country->iso_3166_2 != 'IT' && $this->invoice->company->country()->iso_3166_2 == 'IT') {
|
||||
|
||||
$code = $this->getClientRoutingCode();
|
||||
|
||||
nlog("foreign receiver");
|
||||
$this->setStorecoveMeta($this->buildRouting([
|
||||
["scheme" => $code, "id" => $this->invoice->client->vat_number]
|
||||
]));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* client_IT
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function client_IT(): self
|
||||
{
|
||||
|
||||
// non-IT Sender, IT Receiver, B2C
|
||||
// Provide the receiver IT:CF and an optional email. The invoice will be eReported and sent via email. Note that this cannot be a PEC email address.
|
||||
if(in_array($this->invoice->client->classification, ['individual']) && $this->invoice->company->country()->iso_3166_2 != 'IT') {
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
// non-IT Sender, IT Receiver, B2B/B2G
|
||||
// Provide the receiver IT:VAT and the receiver IT:CUUO (codice destinatario)
|
||||
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* MY
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function MY(): self
|
||||
{
|
||||
//way too much to digest here, delayed.
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* NL
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function NL(): self
|
||||
{
|
||||
|
||||
// When sending to public entities, the invoice.accountingSupplierParty.party.contact.email is mandatory.
|
||||
|
||||
// Dutch senders and receivers require a legal identifier. For companies, this is NL:KVK, for public entities this is NL:OINO.
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* NZ
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function NZ(): self
|
||||
{
|
||||
// New Zealand uses a GLN to identify businesses. In addition, when sending invoices to a New Zealand customer, make sure you include the pseudo identifier NZ:GST as their tax identifier.
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* PL
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function PL(): self
|
||||
{
|
||||
|
||||
// Because using this network is not yet mandatory, the default workflow is to not use this network. Therefore, you have to force its use, as follows:
|
||||
|
||||
// "routing": {
|
||||
// "eIdentifiers": [
|
||||
// {
|
||||
// "scheme": "PL:VAT",
|
||||
// "id": "PL0101010101"
|
||||
// }
|
||||
// ],
|
||||
// "networks": [
|
||||
// {
|
||||
// "application": "pl-ksef",
|
||||
// "settings": {
|
||||
// "enabled": true
|
||||
// }
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// Note this will only work if your LegalEntity has been setup for this network.
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* RO
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function RO(): self
|
||||
{
|
||||
// Because using this network is not yet mandatory, the default workflow is to not use this network. Therefore, you have to force its use, as follows:
|
||||
$meta = ["networks" => [
|
||||
[
|
||||
"application" => "ro-anaf",
|
||||
"settings" => [
|
||||
"enabled" => true
|
||||
],
|
||||
],
|
||||
]];
|
||||
|
||||
$this->setStorecoveMeta($meta);
|
||||
|
||||
$this->setStorecoveMeta($this->buildRouting([
|
||||
["scheme" => 'RO:VAT', "id" => $this->invoice->client->vat_number],
|
||||
]));
|
||||
|
||||
$ro = new RO($this->invoice);
|
||||
|
||||
$client_state = $this->mutator_util->getClientSetting('Invoice.AccountingSupplierParty.Party.PostalAddress.Address.CountrySubentity');
|
||||
$client_city = $this->mutator_util->getClientSetting('Invoice.AccountingCustomerParty.Party.PostalAddress.Address.CityName');
|
||||
|
||||
$resolved_state = $ro->getStateCode($client_state);
|
||||
$resolved_city = $ro->getSectorCode($client_city);
|
||||
|
||||
$this->p_invoice->AccountingCustomerParty->Party->PostalAddress->CountrySubentity = $resolved_state;
|
||||
$this->p_invoice->AccountingCustomerParty->Party->PostalAddress->CityName = $resolved_city;
|
||||
$this->p_invoice->AccountingCustomerParty->Party->PhysicalLocation->Address->CountrySubentity = $resolved_state;
|
||||
$this->p_invoice->AccountingCustomerParty->Party->PhysicalLocation->Address->CityName = $resolved_city;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* SG
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function SG(): self
|
||||
{
|
||||
//delayed - stage 2
|
||||
return $this;
|
||||
}
|
||||
|
||||
//Sweden
|
||||
public function SE(): self
|
||||
{
|
||||
// Deliver invoices to the "Svefaktura" co-operation of local Swedish service providers.
|
||||
// Routing is through the SE:ORGNR together with a network specification:
|
||||
|
||||
// "routing": {
|
||||
// "eIdentifiers": [
|
||||
// {
|
||||
// "scheme": "SE:ORGNR",
|
||||
// "id": "0012345678"
|
||||
// }
|
||||
// ],
|
||||
// "networks": [
|
||||
// {
|
||||
// "application": "svefaktura",
|
||||
// "settings": {
|
||||
// "enabled": true
|
||||
// }
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// Use of the "Svefaktura" co-operation can also be induced by specifying an operator id, as follows:
|
||||
|
||||
// "routing": {
|
||||
// "eIdentifiers": [
|
||||
// {
|
||||
// "scheme": "SE:ORGNR",
|
||||
// "id": "0012345678"
|
||||
// },
|
||||
// {
|
||||
// "scheme": "SE:OPID",
|
||||
// "id": "1234567890"
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/////////////// Storecove Helpers ///////////////
|
||||
|
||||
/**
|
||||
* getClientRoutingCode
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getClientRoutingCode(): string
|
||||
{
|
||||
return (new StorecoveRouter())->resolveRouting($this->invoice->client->country->iso_3166_2, $this->invoice->client->classification);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Builds the Routing object for StoreCove
|
||||
*
|
||||
* @param array $identifiers
|
||||
* @return array
|
||||
*/
|
||||
private function buildRouting(array $identifiers): array
|
||||
{
|
||||
return
|
||||
[
|
||||
"routing" => [
|
||||
"eIdentifiers" =>
|
||||
$identifiers,
|
||||
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* setEmailRouting
|
||||
*
|
||||
* @param string $email
|
||||
* @return self
|
||||
*/
|
||||
private function setEmailRouting(string $email): self
|
||||
{
|
||||
|
||||
$meta = $this->getStorecoveMeta();
|
||||
|
||||
if(isset($meta['routing']['emails'])) {
|
||||
$emails = $meta['routing']['emails'];
|
||||
array_push($emails, $email);
|
||||
$meta['routing']['emails'] = $emails;
|
||||
} else {
|
||||
$meta['routing']['emails'] = [$email];
|
||||
}
|
||||
|
||||
$this->setStorecoveMeta($meta);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* setStorecoveMeta
|
||||
*
|
||||
* updates the storecove payload for sending documents
|
||||
*
|
||||
* @param array $meta
|
||||
* @return self
|
||||
*/
|
||||
private function setStorecoveMeta(array $meta): self
|
||||
{
|
||||
|
||||
$this->storecove_meta = array_merge($this->storecove_meta, $meta);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* getStorecoveMeta
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getStorecoveMeta(): array
|
||||
{
|
||||
return $this->storecove_meta;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -55,9 +55,12 @@ class Storecove
|
||||
|
||||
public StorecoveRouter $router;
|
||||
|
||||
public Mutator $mutator;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->router = new StorecoveRouter();
|
||||
$this->mutator = new Mutator($this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user