mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-08 20:22:42 +01:00
Working on Peppol
This commit is contained in:
parent
c44a3a971b
commit
5bd411b394
@ -262,6 +262,7 @@ class PaymentEmailEngine extends BaseEmailEngine
|
||||
$data['$client.email'] = &$data['$email'];
|
||||
|
||||
$data['$client.balance'] = ['value' => Number::formatMoney($this->client->balance, $this->client), 'label' => ctrans('texts.account_balance')];
|
||||
$data['$client.payment_balance'] = ['value' => Number::formatMoney($this->client->payment_balance, $this->client), 'label' => ctrans('texts.payment_balance_on_file')];
|
||||
$data['$outstanding'] = ['value' => Number::formatMoney($this->client->balance, $this->client), 'label' => ctrans('texts.account_balance')];
|
||||
$data['$client_balance'] = ['value' => Number::formatMoney($this->client->balance, $this->client), 'label' => ctrans('texts.account_balance')];
|
||||
$data['$paid_to_date'] = ['value' => Number::formatMoney($this->client->paid_to_date, $this->client), 'label' => ctrans('texts.paid_to_date')];
|
||||
|
@ -137,14 +137,14 @@ class Storecove {
|
||||
|
||||
}
|
||||
|
||||
public function sendDocument(string $document, int $routing_id, array $identifiers = [])
|
||||
public function sendDocument(string $document, int $routing_id, array $override_payload = [])
|
||||
{
|
||||
|
||||
$payload = [
|
||||
"legalEntityId" => $routing_id,
|
||||
"idempotencyGuid"=> \Illuminate\Support\Str::uuid(),
|
||||
"routing" => [
|
||||
"eIdentifiers" => $identifiers,
|
||||
"eIdentifiers" => [],
|
||||
"emails" => ["david@invoiceninja.com"]
|
||||
],
|
||||
"document"=> [
|
||||
@ -157,6 +157,8 @@ class Storecove {
|
||||
],
|
||||
];
|
||||
|
||||
$payload = array_merge($payload, $override_payload);
|
||||
|
||||
$uri = "document_submissions";
|
||||
|
||||
nlog($payload);
|
||||
|
@ -13,22 +13,25 @@ namespace App\Services\EDocument\Standards;
|
||||
|
||||
use App\Models\Company;
|
||||
use App\Models\Invoice;
|
||||
use App\Helpers\Invoice\Taxer;
|
||||
use App\Services\AbstractService;
|
||||
use App\Helpers\Invoice\InvoiceSum;
|
||||
use InvoiceNinja\EInvoice\EInvoice;
|
||||
use App\Utils\Traits\NumberFormatter;
|
||||
use App\Helpers\Invoice\InvoiceSumInclusive;
|
||||
use App\Helpers\Invoice\Taxer;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\PaymentMeans;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\ItemType\Item;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\PartyType\Party;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\PriceType\Price;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\IdentifierType\ID;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\AddressType\Address;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\ContactType\Contact;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\CountryType\Country;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\PartyIdentification;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\AmountType\TaxAmount;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\Party as PeppolParty;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\TaxTotalType\TaxTotal;
|
||||
use App\Services\EDocument\Standards\Settings\PropertyResolver;
|
||||
use App\Utils\Traits\NumberFormatter;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\AmountType\PriceAmount;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\PartyNameType\PartyName;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\TaxSchemeType\TaxScheme;
|
||||
@ -42,14 +45,13 @@ use InvoiceNinja\EInvoice\Models\Peppol\TaxScheme as PeppolTaxScheme;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\AmountType\TaxExclusiveAmount;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\AmountType\TaxInclusiveAmount;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\AmountType\LineExtensionAmount;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\OrderReferenceType\OrderReference;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\MonetaryTotalType\LegalMonetaryTotal;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\TaxCategoryType\ClassifiedTaxCategory;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\CustomerPartyType\AccountingCustomerParty;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\SupplierPartyType\AccountingSupplierParty;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\FinancialAccountType\PayeeFinancialAccount;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\IdentifierType\ID;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\Party as PeppolParty;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\PartyIdentification;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\IdentifierType\CustomerAssignedAccountID;
|
||||
|
||||
class Peppol extends AbstractService
|
||||
{
|
||||
@ -103,7 +105,7 @@ class Peppol extends AbstractService
|
||||
'DE' => 'VAT', //tested - requires Payment Means to be defined.
|
||||
'DK' => 'ERST',
|
||||
'EE' => 'VAT',
|
||||
'ES' => 'VAT',
|
||||
'ES' => 'VAT', //tested - B2G pending
|
||||
'FI' => 'VAT',
|
||||
'FR' => 'VAT',
|
||||
'GR' => 'VAT',
|
||||
@ -165,6 +167,8 @@ class Peppol extends AbstractService
|
||||
|
||||
private EInvoice $e;
|
||||
|
||||
private array $storecove_meta = [];
|
||||
|
||||
/**
|
||||
* @param Invoice $invoice
|
||||
*/
|
||||
@ -649,7 +653,7 @@ class Peppol extends AbstractService
|
||||
{
|
||||
|
||||
$acp = new AccountingCustomerParty();
|
||||
|
||||
|
||||
$party = new Party();
|
||||
|
||||
if(strlen($this->invoice->client->vat_number ?? '') > 1) {
|
||||
@ -740,7 +744,15 @@ class Peppol extends AbstractService
|
||||
|
||||
return $total;
|
||||
}
|
||||
|
||||
///////////////// Helper Methods /////////////////////////
|
||||
|
||||
/**
|
||||
* setInvoiceDefaults
|
||||
*
|
||||
* Stubs a default einvoice
|
||||
* @return self
|
||||
*/
|
||||
public function setInvoiceDefaults(): self
|
||||
{
|
||||
$settings = [
|
||||
@ -769,7 +781,15 @@ class Peppol extends AbstractService
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
|
||||
@ -783,8 +803,14 @@ class Peppol extends AbstractService
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
public function countryLevelMutators():self
|
||||
|
||||
/**
|
||||
* countryLevelMutators
|
||||
*
|
||||
* Runs country level specific requirements for the e-invoice
|
||||
* @return self
|
||||
*/
|
||||
private function countryLevelMutators():self
|
||||
{
|
||||
|
||||
if(method_exists($this, $this->invoice->company->country()->iso_3166_2))
|
||||
@ -792,7 +818,14 @@ class Peppol extends AbstractService
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* setPaymentMeans
|
||||
*
|
||||
* Sets the payment means - if it exists
|
||||
* @param bool $required
|
||||
* @return self
|
||||
*/
|
||||
private function setPaymentMeans(bool $required = false): self
|
||||
{
|
||||
|
||||
@ -803,12 +836,132 @@ class Peppol extends AbstractService
|
||||
return $this;
|
||||
}
|
||||
|
||||
if($required)
|
||||
throw new \Exception('e-invoice generation halted:: Payment Means required');
|
||||
return $this->checkRequired($required, "Payment Means");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* setOrderReference
|
||||
*
|
||||
* sets the order reference - if it exists (Never rely on settings for this)
|
||||
*
|
||||
* @param bool $required
|
||||
* @return self
|
||||
*/
|
||||
private function setOrderReference(bool $required = false): self
|
||||
{
|
||||
$this->p_invoice->BuyerReference = $this->invoice->po_number ?? '';
|
||||
|
||||
if(strlen($this->invoice->po_number ?? '') > 1)
|
||||
{
|
||||
$order_reference = new OrderReference();
|
||||
$id = new ID();
|
||||
$id->value = $this->invoice->po_number;
|
||||
|
||||
$order_reference->ID = $id;
|
||||
|
||||
$this->p_invoice->OrderReference = $order_reference;
|
||||
|
||||
$this->setStorecoveMeta(["document" => [
|
||||
"invoice" => [
|
||||
"references" => [
|
||||
"documentType" => "purchase_order",
|
||||
"documentId" => $this->invoice->po_number,
|
||||
],
|
||||
],
|
||||
]
|
||||
]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
return $this->checkRequired($required, 'Order Reference');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* setCustomerAssignedAccountId
|
||||
*
|
||||
* Sets the client id_number CAN rely on settings
|
||||
*
|
||||
* @param bool $required
|
||||
* @return self
|
||||
*/
|
||||
private function setCustomerAssignedAccountId(bool $required = false): self
|
||||
{
|
||||
//@phpstan-ignore-next-line
|
||||
if(isset($this->p_invoice->AccountingCustomerParty->CustomerAssignedAccountID)){
|
||||
return $this;
|
||||
}
|
||||
elseif($customer_assigned_account_id = $this->getSetting('Invoice.AccountingCustomerParty.CustomerAssignedAccountID')){
|
||||
|
||||
$this->p_invoice->AccountingCustomerParty->CustomerAssignedAccountID = $customer_assigned_account_id;
|
||||
return $this;
|
||||
}
|
||||
elseif(strlen($this->invoice->client->id_number ?? '') > 1){
|
||||
|
||||
$customer_assigned_account_id = new CustomerAssignedAccountID();
|
||||
$customer_assigned_account_id->value = $this->invoice->client->id_number;
|
||||
|
||||
$this->p_invoice->AccountingCustomerParty->CustomerAssignedAccountID = $customer_assigned_account_id;
|
||||
return $this;
|
||||
}
|
||||
|
||||
//@phpstan-ignore-next-line
|
||||
return $this->checkRequired($required, 'Client ID Number');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check Required
|
||||
*
|
||||
* Throws if a required field is missing.
|
||||
*
|
||||
* @param bool $required
|
||||
* @param string $section
|
||||
* @return self
|
||||
*/
|
||||
private function checkRequired(bool $required, string $section): self
|
||||
{
|
||||
|
||||
return $required ? throw new \Exception("e-invoice generation halted:: {$section} required") : $this;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Builds the Routing object for StoreCove
|
||||
*
|
||||
* @param string $schemeId
|
||||
* @param string $id
|
||||
* @return array
|
||||
*/
|
||||
private function buildRouting(string $schemeId, string $id): array
|
||||
{
|
||||
|
||||
return
|
||||
[
|
||||
"routing" => [
|
||||
"publicIdentifiers" => [
|
||||
[
|
||||
"scheme" => $schemeId,
|
||||
"id" => $id
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////// Country level mutators /////////////////////////////////////
|
||||
|
||||
/**
|
||||
* DE
|
||||
*
|
||||
@ -824,7 +977,21 @@ class Peppol extends AbstractService
|
||||
|
||||
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;
|
||||
}
|
||||
/**
|
||||
* CH
|
||||
*
|
||||
@ -867,10 +1034,10 @@ class Peppol extends AbstractService
|
||||
* ES
|
||||
*
|
||||
* @Pending
|
||||
* B2G configuration
|
||||
* B2G Testing
|
||||
*
|
||||
* ES:DIRE - routing identifier
|
||||
*
|
||||
* testing. //293098
|
||||
* testing. // routing identifier - 293098
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
@ -923,17 +1090,37 @@ class Peppol extends AbstractService
|
||||
|
||||
private 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('FR:SIRET', "0009:11000201100044"));
|
||||
|
||||
// The SIRET / 0009 identifier of the final recipient is to be included in the invoice.accountingCustomerParty.publicIdentifiers array.
|
||||
$this->setCustomerAssignedAccountId(true);
|
||||
|
||||
}
|
||||
|
||||
|
||||
if(strlen($this->invoice->client->id_number ?? '') == 9) {
|
||||
//SIREN
|
||||
$this->setStorecoveMeta($this->buildRouting('FR:SIREN', "0002:{$this->invoice->client->id_number}"));
|
||||
}
|
||||
else {
|
||||
//SIRET
|
||||
$this->setStorecoveMeta($this->buildRouting('FR:SIRET', "0009:{$this->invoice->client->id_number}"));
|
||||
}
|
||||
|
||||
// ??????????????????????? //@TODO
|
||||
// The service code must be sent in invoice.buyerReference (deprecated) or the invoice.references array (documentType buyer_reference)
|
||||
|
||||
// The commitment number must be sent in the invoice.orderReference (deprecated) or the invoice.references array (documentType purchase_order).
|
||||
if(strlen($this->invoice->po_number ?? '') >1) {
|
||||
$this->setOrderReference(false);
|
||||
}
|
||||
|
||||
// Invoices to companies (SIRET / 0009 or SIRENE / 0002) are routed directly to that identifier.
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,7 @@
|
||||
"asm/php-ansible": "dev-main",
|
||||
"authorizenet/authorizenet": "^2.0",
|
||||
"awobaz/compoships": "^2.1",
|
||||
"aws/aws-sdk-php": "^3.319",
|
||||
"bacon/bacon-qr-code": "^2.0",
|
||||
"beganovich/snappdf": "dev-master",
|
||||
"braintree/braintree_php": "^6.0",
|
||||
@ -201,4 +202,4 @@
|
||||
],
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true
|
||||
}
|
||||
}
|
||||
|
19
composer.lock
generated
19
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "6eda3a2962158b87dab46711e65a8438",
|
||||
"content-hash": "95e7bd229644d1d8e768ecfbc78582cd",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adrienrn/php-mimetyper",
|
||||
@ -535,16 +535,16 @@
|
||||
},
|
||||
{
|
||||
"name": "aws/aws-sdk-php",
|
||||
"version": "3.317.1",
|
||||
"version": "3.319.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/aws/aws-sdk-php.git",
|
||||
"reference": "dc1e3031c2721a25beb2e8fbb175b576e3d60ab9"
|
||||
"reference": "a5c408d4cd1945d5fc817f45e46383634b610497"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/dc1e3031c2721a25beb2e8fbb175b576e3d60ab9",
|
||||
"reference": "dc1e3031c2721a25beb2e8fbb175b576e3d60ab9",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/a5c408d4cd1945d5fc817f45e46383634b610497",
|
||||
"reference": "a5c408d4cd1945d5fc817f45e46383634b610497",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -597,7 +597,10 @@
|
||||
],
|
||||
"psr-4": {
|
||||
"Aws\\": "src/"
|
||||
}
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"src/data/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
@ -624,9 +627,9 @@
|
||||
"support": {
|
||||
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
|
||||
"issues": "https://github.com/aws/aws-sdk-php/issues",
|
||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.317.1"
|
||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.319.0"
|
||||
},
|
||||
"time": "2024-08-02T18:09:42+00:00"
|
||||
"time": "2024-08-07T18:05:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "bacon/bacon-qr-code",
|
||||
|
@ -5313,7 +5313,7 @@ $lang = array(
|
||||
'forever_free' => 'Forever Free',
|
||||
'comments_only' => 'Comments Only',
|
||||
'payment_balance_on_file' => 'Payment Balance On File',
|
||||
|
||||
'ubl_email_attachment_help' => 'For more e-invoice settings please navigate :here',
|
||||
);
|
||||
|
||||
return $lang;
|
||||
|
@ -639,10 +639,14 @@ $x = '<?xml version="1.0" encoding="utf-8"?>
|
||||
nlog($xml);
|
||||
|
||||
$identifiers = [
|
||||
[
|
||||
'scheme' => 'ES:VAT',
|
||||
'id' => 'ESB53625999'
|
||||
],
|
||||
"routing" => [
|
||||
"eIdentifiers" => [
|
||||
[
|
||||
'scheme' => 'ES:VAT',
|
||||
'id' => 'ESB53625999'
|
||||
],
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
$sc = new \App\Services\EDocument\Gateway\Storecove\Storecove();
|
||||
@ -673,9 +677,13 @@ $x = '<?xml version="1.0" encoding="utf-8"?>
|
||||
nlog($xml);
|
||||
|
||||
$identifiers = [
|
||||
[
|
||||
'scheme' => 'DE:VAT',
|
||||
'id' => 'DE010101010'
|
||||
"routing" => [
|
||||
"eIdentifiers" => [
|
||||
[
|
||||
'scheme' => 'DE:VAT',
|
||||
'id' => 'DE010101010'
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user