mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-11-03 23:57:33 -05:00 
			
		
		
		
	Peppol
This commit is contained in:
		
							parent
							
								
									4e8197a623
								
							
						
					
					
						commit
						aed30cb572
					
				@ -19,6 +19,7 @@ use App\Helpers\Invoice\InvoiceSum;
 | 
				
			|||||||
use InvoiceNinja\EInvoice\EInvoice;
 | 
					use InvoiceNinja\EInvoice\EInvoice;
 | 
				
			||||||
use App\Utils\Traits\NumberFormatter;
 | 
					use App\Utils\Traits\NumberFormatter;
 | 
				
			||||||
use App\Helpers\Invoice\InvoiceSumInclusive;
 | 
					use App\Helpers\Invoice\InvoiceSumInclusive;
 | 
				
			||||||
 | 
					use App\Services\EDocument\Standards\Peppol\RO;
 | 
				
			||||||
use InvoiceNinja\EInvoice\Models\Peppol\PaymentMeans;
 | 
					use InvoiceNinja\EInvoice\Models\Peppol\PaymentMeans;
 | 
				
			||||||
use InvoiceNinja\EInvoice\Models\Peppol\ItemType\Item;
 | 
					use InvoiceNinja\EInvoice\Models\Peppol\ItemType\Item;
 | 
				
			||||||
use InvoiceNinja\EInvoice\Models\Peppol\PartyType\Party;
 | 
					use InvoiceNinja\EInvoice\Models\Peppol\PartyType\Party;
 | 
				
			||||||
@ -52,6 +53,7 @@ use InvoiceNinja\EInvoice\Models\Peppol\CustomerPartyType\AccountingCustomerPart
 | 
				
			|||||||
use InvoiceNinja\EInvoice\Models\Peppol\SupplierPartyType\AccountingSupplierParty;
 | 
					use InvoiceNinja\EInvoice\Models\Peppol\SupplierPartyType\AccountingSupplierParty;
 | 
				
			||||||
use InvoiceNinja\EInvoice\Models\Peppol\FinancialAccountType\PayeeFinancialAccount;
 | 
					use InvoiceNinja\EInvoice\Models\Peppol\FinancialAccountType\PayeeFinancialAccount;
 | 
				
			||||||
use InvoiceNinja\EInvoice\Models\Peppol\IdentifierType\CustomerAssignedAccountID;
 | 
					use InvoiceNinja\EInvoice\Models\Peppol\IdentifierType\CustomerAssignedAccountID;
 | 
				
			||||||
 | 
					use InvoiceNinja\EInvoice\Models\Peppol\LocationType\PhysicalLocation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Peppol extends AbstractService
 | 
					class Peppol extends AbstractService
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -112,8 +114,8 @@ class Peppol extends AbstractService
 | 
				
			|||||||
        'HR' => 'VAT',
 | 
					        'HR' => 'VAT',
 | 
				
			||||||
        'HU' => 'VAT',
 | 
					        'HU' => 'VAT',
 | 
				
			||||||
        'IE' => 'VAT',
 | 
					        'IE' => 'VAT',
 | 
				
			||||||
        'IT' => 'IVA', //tested - Requires a Customer Party Identification (VAT number) - 'IT senders must first be provisioned in the partner system.'
 | 
					        'IT' => 'IVA', //tested - Requires a Customer Party Identification (VAT number) - 'IT senders must first be provisioned in the partner system.' Cannot test currently
 | 
				
			||||||
        'IT' => 'CF', //tested - Requires a Customer Party Identification (VAT number) - 'IT senders must first be provisioned in the partner system.'
 | 
					        'IT' => 'CF', //tested - Requires a Customer Party Identification (VAT number) - 'IT senders must first be provisioned in the partner system.' Cannot test currently
 | 
				
			||||||
        'LT' => 'VAT',
 | 
					        'LT' => 'VAT',
 | 
				
			||||||
        'LU' => 'VAT',
 | 
					        'LU' => 'VAT',
 | 
				
			||||||
        'LV' => 'VAT',
 | 
					        'LV' => 'VAT',
 | 
				
			||||||
@ -732,7 +734,9 @@ class Peppol extends AbstractService
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    private function resolveTaxScheme(): mixed
 | 
					    private function resolveTaxScheme(): mixed
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $rules = isset($this->routing_rules[$this->invoice->client->country->iso_3166_2]) ? $this->routing_rules[$this->invoice->client->country->iso_3166_2] : false;
 | 
					        $rules = isset($this->routing_rules[$this->invoice->client->country->iso_3166_2]) ? $this->routing_rules[$this->invoice->client->country->iso_3166_2] : [false, false, false, false,];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $code = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        match($this->invoice->client->classification){
 | 
					        match($this->invoice->client->classification){
 | 
				
			||||||
            "business" => $code = "B",
 | 
					            "business" => $code = "B",
 | 
				
			||||||
@ -741,18 +745,18 @@ class Peppol extends AbstractService
 | 
				
			|||||||
            default => $code = false,
 | 
					            default => $code = false,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(count($rules) > 1){
 | 
					        //single array
 | 
				
			||||||
 | 
					        if(is_array($rules) && !is_array($rules[0]))
 | 
				
			||||||
 | 
					            return $rules[2];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            foreach($rules as $rule)
 | 
					        foreach($rules as $rule)
 | 
				
			||||||
            {
 | 
					        {
 | 
				
			||||||
                if(stripos($rule[0], $code) !== false) {
 | 
					            if(stripos($rule[0], $code) !== false) {
 | 
				
			||||||
                    return $rule[2];
 | 
					                return $rule[2];
 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private function getAccountingCustomerParty(): AccountingCustomerParty
 | 
					    private function getAccountingCustomerParty(): AccountingCustomerParty
 | 
				
			||||||
@ -796,7 +800,11 @@ class Peppol extends AbstractService
 | 
				
			|||||||
        $address->Country = $country;
 | 
					        $address->Country = $country;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $party->PostalAddress = $address;
 | 
					        $party->PostalAddress = $address;
 | 
				
			||||||
        $party->PhysicalLocation = $address;
 | 
					
 | 
				
			||||||
 | 
					        $physical_location = new PhysicalLocation();
 | 
				
			||||||
 | 
					        $physical_location->Address = $address;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $party->PhysicalLocation = $physical_location;;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $contact = new Contact();
 | 
					        $contact = new Contact();
 | 
				
			||||||
        $contact->ElectronicMail = $this->invoice->client->present()->email();
 | 
					        $contact->ElectronicMail = $this->invoice->client->present()->email();
 | 
				
			||||||
@ -936,6 +944,15 @@ class Peppol extends AbstractService
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function getClientSetting(string $property_path): mixed
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return PropertyResolver::resolve($this->_client_settings, $property_path);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    private function getCompanySetting(string $property_path): mixed
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return PropertyResolver::resolve($this->_company_settings, $property_path);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * senderSpecificLevelMutators
 | 
					     * senderSpecificLevelMutators
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
@ -1105,12 +1122,20 @@ class Peppol extends AbstractService
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    private function setEmailRouting(string $email): self
 | 
					    private function setEmailRouting(string $email): self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					        nlog($email);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $meta = $this->getStorecoveMeta();
 | 
					        $meta = $this->getStorecoveMeta();
 | 
				
			||||||
        $emails = isset($meta['routing']['emails']) ? $meta['routing']['emails'] : ($meta['routing']['emails'] = []);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        array_push($emails, $email);
 | 
					        if(isset($meta['routing']['emails'])){
 | 
				
			||||||
 | 
					            $emails = $meta['routing']['emails'];
 | 
				
			||||||
 | 
					            array_push($emails, $email);
 | 
				
			||||||
 | 
					            $meta['routing']['emails'] = $emails;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            $meta['routing']['emails'] = [$email];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $this->setStorecoveMeta($emails);
 | 
					        $this->setStorecoveMeta($meta);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -1125,6 +1150,7 @@ class Peppol extends AbstractService
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    private function setStorecoveMeta(array $meta): self
 | 
					    private function setStorecoveMeta(array $meta): self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
        $this->storecove_meta = array_merge($this->storecove_meta, $meta);
 | 
					        $this->storecove_meta = array_merge($this->storecove_meta, $meta);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
@ -1324,24 +1350,26 @@ class Peppol extends AbstractService
 | 
				
			|||||||
        // IT Sender, IT Receiver, B2B/B2G
 | 
					        // IT Sender, IT Receiver, B2B/B2G
 | 
				
			||||||
        // Provide the receiver IT:VAT and the receiver IT:CUUO (codice destinatario)
 | 
					        // 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') {
 | 
					        if(in_array($this->invoice->client->classification, ['business','government']) && $this->invoice->company->country()->iso_3166_2 == 'IT') {
 | 
				
			||||||
            nlog("italian business/government receiver");
 | 
					
 | 
				
			||||||
            $this->setStorecoveMeta($this->buildRouting([
 | 
					            $this->setStorecoveMeta($this->buildRouting([
 | 
				
			||||||
                ["scheme" => 'IT:IVA', "id" => $this->invoice->client->vat_number],
 | 
					                ["scheme" => 'IT:IVA', "id" => $this->invoice->client->vat_number],
 | 
				
			||||||
                ["scheme" => 'IT:CUUO', "id" => $this->invoice->client->routing_id]
 | 
					                ["scheme" => 'IT:CUUO', "id" => $this->invoice->client->routing_id]
 | 
				
			||||||
            ]));
 | 
					            ]));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return $this;
 | 
					            return $this;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // IT Sender, IT Receiver, B2C
 | 
					        // IT Sender, IT Receiver, B2C
 | 
				
			||||||
        // Provide the receiver IT:CF and the receiver IT:CUUO (codice destinatario)
 | 
					        // 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') {
 | 
					        if($this->invoice->client->classification == 'individual' && $this->invoice->company->country()->iso_3166_2 == 'IT') {
 | 
				
			||||||
            nlog("business receiver");
 | 
					 | 
				
			||||||
           
 | 
					           
 | 
				
			||||||
            $this->setStorecoveMeta($this->buildRouting([
 | 
					            $this->setStorecoveMeta($this->buildRouting([
 | 
				
			||||||
                ["scheme" => 'IT:CF', "id" => $this->invoice->client->vat_number],
 | 
					                ["scheme" => 'IT:CF', "id" => $this->invoice->client->vat_number],
 | 
				
			||||||
                ["scheme" => 'IT:CUUO', "id" => $this->invoice->client->routing_id]
 | 
					                // ["scheme" => 'IT:CUUO', "id" => $this->invoice->client->routing_id]
 | 
				
			||||||
            ]));
 | 
					            ]));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $this->setEmailRouting($this->invoice->client->present()->email());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return $this;
 | 
					            return $this;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
@ -1429,27 +1457,34 @@ class Peppol extends AbstractService
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    private function RO(): self
 | 
					    private 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:
 | 
					        // 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
 | 
				
			||||||
 | 
					                        ],
 | 
				
			||||||
 | 
					                    ],
 | 
				
			||||||
 | 
					                ]];
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
    // "routing": {
 | 
					        $this->setStorecoveMeta($meta);
 | 
				
			||||||
    // "eIdentifiers": [
 | 
					        
 | 
				
			||||||
    //     {
 | 
					        $this->setStorecoveMeta($this->buildRouting([
 | 
				
			||||||
    //         "scheme": "RO:VAT",
 | 
					               ["scheme" => 'RO:VAT', "id" => $this->invoice->client->vat_number],
 | 
				
			||||||
    //         "id": "RO010101010"
 | 
					           ]));
 | 
				
			||||||
    //     }
 | 
					
 | 
				
			||||||
    // ],
 | 
					        $ro = new RO($this->invoice);
 | 
				
			||||||
    // "networks": [
 | 
					
 | 
				
			||||||
    //     {
 | 
					        $client_state = $this->getClientSetting('Invoice.AccountingSupplierParty.Party.PostalAddress.Address.CountrySubentity');
 | 
				
			||||||
    //     "application": "ro-anaf",
 | 
					        $client_city = $this->getClientSetting('Invoice.AccountingCustomerParty.Party.PostalAddress.Address.CityName');
 | 
				
			||||||
    //     "settings": {
 | 
					
 | 
				
			||||||
    //         "enabled": true
 | 
					        $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;        
 | 
				
			||||||
    // Note this will only work if your LegalEntity has been setup for this network.
 | 
					        $this->p_invoice->AccountingCustomerParty->Party->PhysicalLocation->Address->CountrySubentity = $resolved_state;
 | 
				
			||||||
    // The county field for a Romania address must use the ISO3166-2:RO codes, e.g. "RO-AB, RO-AR". Don’t omit the country prefix!
 | 
					        $this->p_invoice->AccountingCustomerParty->Party->PhysicalLocation->Address->CityName = $resolved_city;
 | 
				
			||||||
    // The city field for county RO-B must be SECTOR1 - SECTOR6.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										149
									
								
								app/Services/EDocument/Standards/Peppol/RO.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								app/Services/EDocument/Standards/Peppol/RO.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,149 @@
 | 
				
			|||||||
 | 
					<?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\Standards\Peppol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Models\Invoice;
 | 
				
			||||||
 | 
					use App\Services\EDocument\Standards\Peppol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RO
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public array $countrySubEntity = [
 | 
				
			||||||
 | 
					        'RO-AB' => 'Alba',
 | 
				
			||||||
 | 
					        'RO-AG' => 'Argeș',
 | 
				
			||||||
 | 
					        'RO-AR' => 'Arad',
 | 
				
			||||||
 | 
					        'RO-B' => 'Bucharest',
 | 
				
			||||||
 | 
					        'RO-BC' => 'Bacău',
 | 
				
			||||||
 | 
					        'RO-BH' => 'Bihor',
 | 
				
			||||||
 | 
					        'RO-BN' => 'Bistrița-Năsăud',
 | 
				
			||||||
 | 
					        'RO-BR' => 'Brăila',
 | 
				
			||||||
 | 
					        'RO-BT' => 'Botoșani',
 | 
				
			||||||
 | 
					        'RO-BV' => 'Brașov',
 | 
				
			||||||
 | 
					        'RO-BZ' => 'Buzău',
 | 
				
			||||||
 | 
					        'RO-CJ' => 'Cluj',
 | 
				
			||||||
 | 
					        'RO-CL' => 'Călărași',
 | 
				
			||||||
 | 
					        'RO-CS' => 'Caraș-Severin',
 | 
				
			||||||
 | 
					        'RO-CT' => 'Constanța',
 | 
				
			||||||
 | 
					        'RO-CV' => 'Covasna',
 | 
				
			||||||
 | 
					        'RO-DB' => 'Dâmbovița',
 | 
				
			||||||
 | 
					        'RO-DJ' => 'Dolj',
 | 
				
			||||||
 | 
					        'RO-GJ' => 'Gorj',
 | 
				
			||||||
 | 
					        'RO-GL' => 'Galați',
 | 
				
			||||||
 | 
					        'RO-GR' => 'Giurgiu',
 | 
				
			||||||
 | 
					        'RO-HD' => 'Hunedoara',
 | 
				
			||||||
 | 
					        'RO-HR' => 'Harghita',
 | 
				
			||||||
 | 
					        'RO-IF' => 'Ilfov',
 | 
				
			||||||
 | 
					        'RO-IL' => 'Ialomița',
 | 
				
			||||||
 | 
					        'RO-IS' => 'Iași',
 | 
				
			||||||
 | 
					        'RO-MH' => 'Mehedinți',
 | 
				
			||||||
 | 
					        'RO-MM' => 'Maramureș',
 | 
				
			||||||
 | 
					        'RO-MS' => 'Mureș',
 | 
				
			||||||
 | 
					        'RO-NT' => 'Neamț',
 | 
				
			||||||
 | 
					        'RO-OT' => 'Olt',
 | 
				
			||||||
 | 
					        'RO-PH' => 'Prahova',
 | 
				
			||||||
 | 
					        'RO-SB' => 'Sibiu',
 | 
				
			||||||
 | 
					        'RO-SJ' => 'Sălaj',
 | 
				
			||||||
 | 
					        'RO-SM' => 'Satu Mare',
 | 
				
			||||||
 | 
					        'RO-SV' => 'Suceava',
 | 
				
			||||||
 | 
					        'RO-TL' => 'Tulcea',
 | 
				
			||||||
 | 
					        'RO-TM' => 'Timiș',
 | 
				
			||||||
 | 
					        'RO-TR' => 'Teleorman',
 | 
				
			||||||
 | 
					        'RO-VL' => 'Vâlcea',
 | 
				
			||||||
 | 
					        'RO-VN' => 'Vaslui',
 | 
				
			||||||
 | 
					        'RO-VS' => 'Vrancea',
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected array $sectorList = [
 | 
				
			||||||
 | 
					        'SECTOR1' => 'Agriculture',
 | 
				
			||||||
 | 
					        'SECTOR2' => 'Manufacturing',
 | 
				
			||||||
 | 
					        'SECTOR3' => 'Tourism',
 | 
				
			||||||
 | 
					        'SECTOR4' => 'Information Technology (IT):',
 | 
				
			||||||
 | 
					        'SECTOR5' => 'Energy',
 | 
				
			||||||
 | 
					        'SECTOR6' => 'Healthcare',
 | 
				
			||||||
 | 
					        'SECTOR7' => 'Education',
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected array $sectorCodes = [
 | 
				
			||||||
 | 
					        'RO-AB'  => 'Manufacturing, Agriculture',
 | 
				
			||||||
 | 
					        'RO-AG'  => 'Manufacturing, Agriculture',
 | 
				
			||||||
 | 
					        'RO-AR'  => 'Manufacturing, Agriculture',
 | 
				
			||||||
 | 
					        'RO-B'  => 'Information Technology (IT), Education, Tourism',
 | 
				
			||||||
 | 
					        'RO-BC'  => 'Manufacturing, Agriculture',
 | 
				
			||||||
 | 
					        'RO-BH'  => 'Agriculture, Manufacturing',
 | 
				
			||||||
 | 
					        'RO-BN'  => 'Agriculture',
 | 
				
			||||||
 | 
					        'RO-BR'  => 'Agriculture',
 | 
				
			||||||
 | 
					        'RO-BT'  => 'Agriculture',
 | 
				
			||||||
 | 
					        'RO-BV'  => 'Tourism, Agriculture',
 | 
				
			||||||
 | 
					        'RO-BZ'  => 'Agriculture',
 | 
				
			||||||
 | 
					        'RO-CJ'  => 'Information Technology (IT), Education, Tourism',
 | 
				
			||||||
 | 
					        'RO-CL'  => 'Agriculture',
 | 
				
			||||||
 | 
					        'RO-CS'  => 'Manufacturing, Agriculture',
 | 
				
			||||||
 | 
					        'RO-CT'  => 'Tourism, Agriculture',
 | 
				
			||||||
 | 
					        'RO-CV'  => 'Agriculture',
 | 
				
			||||||
 | 
					        'RO-DB'  => 'Agriculture',
 | 
				
			||||||
 | 
					        'RO-DJ'  => 'Agriculture',
 | 
				
			||||||
 | 
					        'RO-GJ'  => 'Manufacturing, Agriculture',
 | 
				
			||||||
 | 
					        'RO-GL'  => 'Energy, Manufacturing',
 | 
				
			||||||
 | 
					        'RO-GR'  => 'Agriculture',
 | 
				
			||||||
 | 
					        'RO-HD'  => 'Energy, Manufacturing',
 | 
				
			||||||
 | 
					        'RO-HR'  => 'Agriculture',
 | 
				
			||||||
 | 
					        'RO-IF'  => 'Information Technology (IT), Education',
 | 
				
			||||||
 | 
					        'RO-IL'  => 'Agriculture',
 | 
				
			||||||
 | 
					        'RO-IS'  => 'Information Technology (IT), Education, Agriculture',
 | 
				
			||||||
 | 
					        'RO-MH'  => 'Manufacturing, Agriculture',
 | 
				
			||||||
 | 
					        'RO-MM'  => 'Agriculture',
 | 
				
			||||||
 | 
					        'RO-MS'  => 'Energy, Manufacturing, Agriculture',
 | 
				
			||||||
 | 
					        'RO-NT'  => 'Agriculture',
 | 
				
			||||||
 | 
					        'RO-OT'  => 'Agriculture',
 | 
				
			||||||
 | 
					        'RO-PH'  => 'Energy, Manufacturing',
 | 
				
			||||||
 | 
					        'RO-SB'  => 'Manufacturing, Agriculture',
 | 
				
			||||||
 | 
					        'RO-SJ'  => 'Agriculture',
 | 
				
			||||||
 | 
					        'RO-SM'  => 'Agriculture',
 | 
				
			||||||
 | 
					        'RO-SV'  => 'Agriculture',
 | 
				
			||||||
 | 
					        'RO-TL'  => 'Agriculture',
 | 
				
			||||||
 | 
					        'RO-TM'  => 'Agriculture, Manufacturing',
 | 
				
			||||||
 | 
					        'RO-TR'  => 'Agriculture',
 | 
				
			||||||
 | 
					        'RO-VL'  => 'Agriculture',
 | 
				
			||||||
 | 
					        'RO-VN'  => 'Agriculture',
 | 
				
			||||||
 | 
					        'RO-VS'  => 'Agriculture',
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function __construct(protected Invoice $invoice){}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getStateCode(?string $state_code): string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $state_code = strlen($state_code ?? '') > 1 ? $state_code : $this->invoice->client->state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //codes are configured by default
 | 
				
			||||||
 | 
					        if(isset($this->countrySubEntity[$state_code]))
 | 
				
			||||||
 | 
					            return $state_code;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $key = array_search($state_code, $this->countrySubEntity);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($key !== false) {
 | 
				
			||||||
 | 
					            return $key;
 | 
				
			||||||
 | 
					        } 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return 'RO-B';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getSectorCode(?string $client_city): string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $client_sector_code = $client_city ?? $this->invoice->client->city;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(in_array($this->getStateCode($this->invoice->client->state), ['BUCHAREST', 'RO-B']))
 | 
				
			||||||
 | 
					            return in_array(strtoupper($this->invoice->client->city), array_keys($this->sectorList)) ? strtoupper($this->invoice->client->city) : 'SECTOR1';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $client_sector_code;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -891,6 +891,158 @@ $x = '<?xml version="1.0" encoding="utf-8"?>
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function createROData()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      $this->routing_id =294639;
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					      $settings = CompanySettings::defaults();
 | 
				
			||||||
 | 
					      $settings->company_logo = 'https://pdf.invoicing.co/favicon-v2.png';
 | 
				
			||||||
 | 
					      $settings->website = 'www.invoiceninja.ro';
 | 
				
			||||||
 | 
					      $settings->address1 = 'Strada Exemplu, 28';
 | 
				
			||||||
 | 
					      $settings->address2 = 'Clădirea Exemplu';
 | 
				
			||||||
 | 
					      $settings->city = 'Bucharest';
 | 
				
			||||||
 | 
					      $settings->state = 'Bucharest';
 | 
				
			||||||
 | 
					      $settings->postal_code = '010101';
 | 
				
			||||||
 | 
					      $settings->phone = '021 1234567';
 | 
				
			||||||
 | 
					      $settings->email = $this->faker->unique()->safeEmail();
 | 
				
			||||||
 | 
					      $settings->country_id = '642'; // Romania's ISO country code
 | 
				
			||||||
 | 
					      $settings->vat_number = 'RO92443356490'; // Romanian VAT number format
 | 
				
			||||||
 | 
					      $settings->id_number = 'B12345678'; // Typical Romanian company registration format
 | 
				
			||||||
 | 
					      $settings->use_credits_payment = 'always';
 | 
				
			||||||
 | 
					      $settings->timezone_id = '1'; // CET (Central European Time)
 | 
				
			||||||
 | 
					      $settings->entity_send_time = 0;
 | 
				
			||||||
 | 
					      $settings->e_invoice_type = 'PEPPOL';
 | 
				
			||||||
 | 
					      $settings->currency_id = '3'; // Euro (EUR)
 | 
				
			||||||
 | 
					      $settings->classification = 'business';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      $company = Company::factory()->create([
 | 
				
			||||||
 | 
					        'account_id' => $this->account->id,
 | 
				
			||||||
 | 
					        'settings' => $settings,
 | 
				
			||||||
 | 
					      ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      $this->user->companies()->attach($company->id, [
 | 
				
			||||||
 | 
					          'account_id' => $this->account->id,
 | 
				
			||||||
 | 
					          'is_owner' => true,
 | 
				
			||||||
 | 
					          'is_admin' => 1,
 | 
				
			||||||
 | 
					          'is_locked' => 0,
 | 
				
			||||||
 | 
					          'permissions' => '',
 | 
				
			||||||
 | 
					          'notifications' => CompanySettings::notificationAdminDefaults(),
 | 
				
			||||||
 | 
					          'settings' => null,
 | 
				
			||||||
 | 
					      ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      Client::unguard();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      $c =
 | 
				
			||||||
 | 
					      Client::create([
 | 
				
			||||||
 | 
					        'company_id' => $company->id,
 | 
				
			||||||
 | 
					        'user_id' => $this->user->id,
 | 
				
			||||||
 | 
					        'name' => 'Impresa Esempio S.R.L.',
 | 
				
			||||||
 | 
					        'website' => 'https://www.impresa-esempio.ro',
 | 
				
			||||||
 | 
					        'private_notes' => 'Acestea sunt note private pentru clientul de test.',
 | 
				
			||||||
 | 
					        'balance' => 0,
 | 
				
			||||||
 | 
					        'paid_to_date' => 0,
 | 
				
			||||||
 | 
					        'vat_number' => 'RO9244336489', // Romanian VAT number with RO prefix
 | 
				
			||||||
 | 
					        'id_number' => 'J40/12345/2024', // Typical format for Romanian company registration numbers
 | 
				
			||||||
 | 
					        'custom_value1' => '2024-07-22 10:00:00',
 | 
				
			||||||
 | 
					        'custom_value2' => 'albastru', // Romanian for blue
 | 
				
			||||||
 | 
					        'custom_value3' => 'cuvantexemplu', // Romanian for sample word
 | 
				
			||||||
 | 
					        'custom_value4' => 'test@exemplu.ro',
 | 
				
			||||||
 | 
					        'address1' => 'Strada Exemplu 123',
 | 
				
			||||||
 | 
					        'address2' => 'Etaj 2, Birou 45',
 | 
				
			||||||
 | 
					        'city' => 'Bucharest',
 | 
				
			||||||
 | 
					        'state' => 'Bucharest',
 | 
				
			||||||
 | 
					        'postal_code' => '010101',
 | 
				
			||||||
 | 
					        'country_id' => '642', // Romania
 | 
				
			||||||
 | 
					        'shipping_address1' => 'Strada Exemplu 123',
 | 
				
			||||||
 | 
					        'shipping_address2' => 'Etaj 2, Birou 45',
 | 
				
			||||||
 | 
					        'shipping_city' => 'Bucharest',
 | 
				
			||||||
 | 
					        'shipping_state' => 'Bucharest',
 | 
				
			||||||
 | 
					        'shipping_postal_code' => '010101',
 | 
				
			||||||
 | 
					        'shipping_country_id' => '642', // Romania
 | 
				
			||||||
 | 
					        'settings' => ClientSettings::defaults(),
 | 
				
			||||||
 | 
					        'client_hash' => \Illuminate\Support\Str::random(32),
 | 
				
			||||||
 | 
					        'routing_id' => 'SCSCSCS',
 | 
				
			||||||
 | 
					        'classification' => 'business',
 | 
				
			||||||
 | 
					      ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ClientContact::factory()->create([
 | 
				
			||||||
 | 
					        'company_id' => $company->id,
 | 
				
			||||||
 | 
					        'user_id' => $this->user->id,
 | 
				
			||||||
 | 
					        'client_id' => $c->id,
 | 
				
			||||||
 | 
					        'first_name' => 'Contact First',
 | 
				
			||||||
 | 
					        'last_name' => 'Contact Last',
 | 
				
			||||||
 | 
					        'email' => 'david+c1@invoiceninja.com',
 | 
				
			||||||
 | 
					      ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      $item = new InvoiceItem();
 | 
				
			||||||
 | 
					      $item->product_key = "Product Key";
 | 
				
			||||||
 | 
					      $item->notes = "Product Description";
 | 
				
			||||||
 | 
					      $item->cost = 10;
 | 
				
			||||||
 | 
					      $item->quantity = 10;
 | 
				
			||||||
 | 
					      $item->tax_rate1 = 19;
 | 
				
			||||||
 | 
					      $item->tax_name1 = 'TVA';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      $invoice = Invoice::factory()->create([
 | 
				
			||||||
 | 
					          'company_id' => $company->id,
 | 
				
			||||||
 | 
					          'user_id' => $this->user->id,
 | 
				
			||||||
 | 
					          'client_id' => $c->id,
 | 
				
			||||||
 | 
					          'discount' => 0,
 | 
				
			||||||
 | 
					          'uses_inclusive_taxes' => false,
 | 
				
			||||||
 | 
					          'status_id' => 1,
 | 
				
			||||||
 | 
					          'tax_rate1' => 0,
 | 
				
			||||||
 | 
					          'tax_name1' => '',
 | 
				
			||||||
 | 
					          'tax_rate2' => 0,
 | 
				
			||||||
 | 
					          'tax_rate3' => 0,
 | 
				
			||||||
 | 
					          'tax_name2' => '',
 | 
				
			||||||
 | 
					          'tax_name3' => '',
 | 
				
			||||||
 | 
					          'line_items' => [$item],
 | 
				
			||||||
 | 
					          'number' => 'IT-'.rand(1000, 100000),
 | 
				
			||||||
 | 
					          'date' => now()->format('Y-m-d'),
 | 
				
			||||||
 | 
					          'due_date' => now()->addDays(14)->format('Y-m-d'),
 | 
				
			||||||
 | 
					      ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      $invoice = $invoice->calc()->getInvoice();
 | 
				
			||||||
 | 
					      $invoice->service()->markSent()->save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return $invoice;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function testRoRules() 
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      $invoice = $this->createROData();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      $e_invoice = new \InvoiceNinja\EInvoice\Models\Peppol\Invoice();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      $stub = json_decode('{"Invoice":{"Note":"Nooo","PaymentMeans":[{"ID":{"value":"afdasfasdfasdfas"},"PayeeFinancialAccount":{"Name":"PFA-NAME","ID":{"value":"DE89370400440532013000"},"AliasName":"PFA-Alias","AccountTypeCode":{"value":"CHECKING"},"AccountFormatCode":{"value":"IBAN"},"CurrencyCode":{"value":"EUR"},"FinancialInstitutionBranch":{"ID":{"value":"DEUTDEMMXXX"},"Name":"Deutsche Bank"}}}]}}');
 | 
				
			||||||
 | 
					      foreach($stub as $key => $value) {
 | 
				
			||||||
 | 
					          $e_invoice->{$key} = $value;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      $invoice->e_invoice = $e_invoice;
 | 
				
			||||||
 | 
					      $invoice->save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      $this->assertInstanceOf(Invoice::class, $invoice);
 | 
				
			||||||
 | 
					      $this->assertInstanceof(\InvoiceNinja\EInvoice\Models\Peppol\Invoice::class, $e_invoice);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      $p = new Peppol($invoice);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      $p->run();
 | 
				
			||||||
 | 
					      $xml  = $p->toXml();
 | 
				
			||||||
 | 
					      nlog($xml);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      $identifiers = $p->getStorecoveMeta();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      $sc = new \App\Services\EDocument\Gateway\Storecove\Storecove();
 | 
				
			||||||
 | 
					      $sc->sendDocument($xml, $this->routing_id, $identifiers);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function PestAtGovernmentRules()
 | 
					    public function PestAtGovernmentRules()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      $this->routing_id = 293801;
 | 
					      $this->routing_id = 293801;
 | 
				
			||||||
@ -923,7 +1075,7 @@ $x = '<?xml version="1.0" encoding="utf-8"?>
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function testItRules() 
 | 
					    public function PtestItRules() 
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      $invoice = $this->createITData();
 | 
					      $invoice = $this->createITData();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -956,28 +1108,28 @@ $x = '<?xml version="1.0" encoding="utf-8"?>
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      nlog("Individual");
 | 
					      nlog("Individual");
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
$invoice = $this->createITData(false);
 | 
					      $invoice = $this->createITData(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$e_invoice = new \InvoiceNinja\EInvoice\Models\Peppol\Invoice();
 | 
					      $e_invoice = new \InvoiceNinja\EInvoice\Models\Peppol\Invoice();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$stub = json_decode('{"Invoice":{"Note":"Nooo","PaymentMeans":[{"ID":{"value":"afdasfasdfasdfas"},"PayeeFinancialAccount":{"Name":"PFA-NAME","ID":{"value":"DE89370400440532013000"},"AliasName":"PFA-Alias","AccountTypeCode":{"value":"CHECKING"},"AccountFormatCode":{"value":"IBAN"},"CurrencyCode":{"value":"EUR"},"FinancialInstitutionBranch":{"ID":{"value":"DEUTDEMMXXX"},"Name":"Deutsche Bank"}}}]}}');
 | 
					      $stub = json_decode('{"Invoice":{"Note":"Nooo","PaymentMeans":[{"ID":{"value":"afdasfasdfasdfas"},"PayeeFinancialAccount":{"Name":"PFA-NAME","ID":{"value":"DE89370400440532013000"},"AliasName":"PFA-Alias","AccountTypeCode":{"value":"CHECKING"},"AccountFormatCode":{"value":"IBAN"},"CurrencyCode":{"value":"EUR"},"FinancialInstitutionBranch":{"ID":{"value":"DEUTDEMMXXX"},"Name":"Deutsche Bank"}}}]}}');
 | 
				
			||||||
foreach($stub as $key => $value) {
 | 
					      foreach($stub as $key => $value) {
 | 
				
			||||||
    $e_invoice->{$key} = $value;
 | 
					          $e_invoice->{$key} = $value;
 | 
				
			||||||
}
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$invoice->e_invoice = $e_invoice;
 | 
					      $invoice->e_invoice = $e_invoice;
 | 
				
			||||||
$invoice->save();
 | 
					      $invoice->save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$p = new Peppol($invoice);
 | 
					      $p = new Peppol($invoice);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$p->run();
 | 
					      $p->run();
 | 
				
			||||||
$xml  = $p->toXml();
 | 
					      $xml  = $p->toXml();
 | 
				
			||||||
nlog($xml);
 | 
					      nlog($xml);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$identifiers = $p->getStorecoveMeta();
 | 
					      $identifiers = $p->getStorecoveMeta();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$sc = new \App\Services\EDocument\Gateway\Storecove\Storecove();
 | 
					      $sc = new \App\Services\EDocument\Gateway\Storecove\Storecove();
 | 
				
			||||||
$sc->sendDocument($xml, $this->routing_id, $identifiers);
 | 
					      $sc->sendDocument($xml, $this->routing_id, $identifiers);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user