1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-08 12:12:48 +01:00

Tests for entity validation for einvoicing

This commit is contained in:
David Bomba 2024-09-03 15:36:01 +10:00
parent 26d55d112d
commit 607f2ff69c
8 changed files with 606 additions and 43 deletions

View File

@ -16,13 +16,6 @@ namespace App\DataMapper;
*/
class BaseSettings
{
// //@deprecated
// public function __construct($obj)
// {
// // foreach ($obj as $key => $value) {
// // $obj->{$key} = $value;
// // }
// }
public static function setCasts($obj, $casts)
{

View File

@ -0,0 +1,34 @@
<?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\Exceptions;
use Exception;
class PeppolValidationException extends Exception
{
protected string $field = '';
public function __construct($message, $field, $code = 0, Exception $previous = null)
{
// Store the custom data
$this->field = $field;
// Ensure that everything is assigned properly by calling the parent constructor
parent::__construct($message, $code, $previous);
}
public function getInvalidField()
{
return $this->field;
}
}

View File

@ -11,6 +11,7 @@
namespace App\Services\EDocument\Standards;
use App\Exceptions\PeppolValidationException;
use App\Models\Company;
use App\Models\Invoice;
use App\Helpers\Invoice\Taxer;
@ -1277,9 +1278,7 @@ class Peppol extends AbstractService
*/
private function checkRequired(bool $required, string $section): self
{
return $required ? throw new \Exception("e-invoice generation halted:: {$section} required", 400) : $this;
return $required ? throw new PeppolValidationException("e-invoice generation halted:: {$section} required", $section, 400) : $this;
}

View File

@ -0,0 +1,23 @@
<?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 BaseCountry
{
public function __construct(protected Invoice $invoice)
{
}
}

View File

@ -14,7 +14,7 @@ namespace App\Services\EDocument\Standards\Peppol;
use App\Models\Invoice;
use App\Services\EDocument\Standards\Peppol;
class RO
class RO extends BaseCountry
{
public array $countrySubEntity = [
'RO-AB' => 'Alba',

View File

@ -11,8 +11,15 @@
namespace App\Services\EDocument\Standards\Validation\Peppol;
use App\Exceptions\PeppolValidationException;
use App\Models\Quote;
use App\Models\Client;
use App\Models\Credit;
use App\Models\Vendor;
use App\Models\Company;
use App\Models\Invoice;
use App\Models\PurchaseOrder;
use App\Services\EDocument\Standards\Peppol;
use Illuminate\Support\Facades\App;
class EntityLevel
@ -44,32 +51,68 @@ class EntityLevel
private array $errors = [];
public function __invoke($entity): array
public function __construct()
{
}
private function init(string $locale): self
{
App::forgetInstance('translator');
$t = app('translator');
App::setLocale($entity->company->locale());
App::setLocale($locale);
$this->errors['status'] = false;
$this->errors['client'] = $entity->client ? $this->testClientState($entity) : [];
$this->errors['company'] = $this->testCompanyState($entity->company);
$this->errors['invoice'] = $entity instanceof Invoice ? $this->testInvoiceState($entity) : [];
// $this->errors['vendor']= $entity->client ? $this->testClientState($entity) : [];
return $this;
if(
count($this->errors['client']) == 0 &&
count($this->errors['company']) == 0
){
$this->errors['status'] = true;
}
}
public function checkClient(Client $client): array
{
$this->init($client->locale());
$this->errors['client'] = $this->testClientState($client);
$this->errors['passes'] = count($this->errors['client']) == 0;
return $this->errors;
}
private function testClientState($entity): array
public function checkCompany(Company $company): array
{
$this->init($company->locale());
$this->errors['company'] = $this->testCompanyState($company);
$this->errors['passes'] = count($this->errors['company']) == 0;
return $this->errors;
}
public function checkInvoice(Invoice $invoice): array
{
$this->init($invoice->client->locale());
$this->errors['invoice'] = [];
$this->testClientState($invoice->client);
$this->testCompanyState($invoice->client); // uses client level settings which is what we want
$p = new Peppol($invoice);
try{
$p->run()->toXml();
}
catch(PeppolValidationException $e) {
$this->errors['invoice'] = ['field' => $e->getInvalidField()];
};
$this->errors['status'] = count($this->errors['invoice']) == 0 && count($this->errors['client']) == 0 && count($this->errors['company']) == 0;
return $this->errors;
}
private function testClientState(Client $client): array
{
$errors = [];
@ -77,7 +120,10 @@ class EntityLevel
foreach($this->client_fields as $field)
{
if($this->validString($entity->client->{$field}))
if($this->validString($client->{$field}))
continue;
if($field == 'country_id' && $client->country_id >=1)
continue;
$errors[] = ['field' => ctrans("texts.{$field}")];
@ -93,14 +139,44 @@ class EntityLevel
}
private function testCompanyState($entity): array
private function testCompanyState(mixed $entity): array
{
$client = false;
$vendor = false;
$settings_object = false;
$company =false;
if($entity instanceof Client){
$client = $entity;
$company = $entity->company;
$settings_object = $client;
}
elseif($entity instanceof Company){
$company = $entity;
$settings_object = $company;
}
elseif($entity instanceof Vendor){
$vendor = $entity;
$company = $entity->company;
$settings_object = $company;
}
elseif($entity instanceof Invoice || $entity instanceof Credit || $entity instanceof Quote){
$client = $entity->client;
$company = $entity->company;
$settings_object = $entity->client;
}
elseif($entity instanceof PurchaseOrder){
$vendor = $entity->vendor;
$company = $entity->company;
$settings_object = $company;
}
$settings_object = $entity->client ? $entity->client : $entity->company;
$errors = [];
foreach($this->company_settings_fields as $field)
{
if($this->validString($settings_object->getSetting($field)))
continue;
@ -109,11 +185,11 @@ class EntityLevel
}
//test legal entity id present
if(!is_int($entity->company->legal_entity_id))
if(!is_int($company->legal_entity_id))
$errors[] = ['field' => "You have not registered a legal entity id as yet."];
//If not an individual, you MUST have a VAT number
if($settings_object->getSetting('classification') != 'individual' && !$this->validString($settings_object->getSetting('vat_number')))
if($company->getSetting('classification') != 'individual' && !$this->validString($company->getSetting('vat_number')))
{
$errors[] = ['field' => ctrans("texts.vat_number")];
}
@ -127,17 +203,17 @@ class EntityLevel
}
private function testInvoiceState(): array
{
$errors = [];
// private function testInvoiceState($entity): array
// {
// $errors = [];
foreach($this->invoice_fields as $field)
{
// foreach($this->invoice_fields as $field)
// {
}
// }
return $errors;
}
// return $errors;
// }
// private function testVendorState(): array
// {
@ -146,9 +222,9 @@ class EntityLevel
/************************************ helpers ************************************/
private function validString(?string $string)
private function validString(?string $string): bool
{
return iconv_strlen($string) > 1;
return iconv_strlen($string) >= 1;
}
}

View File

@ -38,5 +38,4 @@ parameters:
- '#Left side of && is always true.#'
- '#Right side of && is always true.#'
- '#is never read, only written.#'
- '#is never written#'
- '#is never written#'

View File

@ -0,0 +1,439 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace Tests\Integration\Einvoice\Storecove;
use Tests\TestCase;
use App\Models\Client;
use App\Models\Account;
use App\Models\Company;
use App\Models\Invoice;
use Tests\MockAccountData;
use App\Models\ClientContact;
use App\DataMapper\InvoiceItem;
use App\DataMapper\ClientSettings;
use App\DataMapper\CompanySettings;
use App\Services\EDocument\Standards\Peppol;
use App\Services\EDocument\Standards\Validation\Peppol\EntityLevel;
use InvoiceNinja\EInvoice\Models\Peppol\PaymentMeans;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class EInvoiceValidationTest extends TestCase
{
use MockAccountData;
use DatabaseTransactions;
private int $routing_id;
protected function setUp(): void
{
parent::setUp();
$this->makeTestData();
}
public function testInvalidCompanySettings()
{
$account = Account::factory()->create();
$company = Company::factory()->create([
'account_id' => $account->id,
]);
$account->default_company_id = $company->id;
$account->save();
$el = new EntityLevel();
$validation = $el->checkCompany($company);
$this->assertFalse($validation['passes']);
}
public function testValidBusinessCompanySettings()
{
$settings = CompanySettings::defaults();
$settings->address1 = '10 Wallaby Way';
$settings->city = 'Sydney';
$settings->state = 'NSW';
$settings->postal_code = '2113';
$settings->country_id = '1';
$settings->vat_number = 'ABN321231232';
$settings->classification = 'business';
$account = Account::factory()->create();
$company = Company::factory()->create([
'account_id' => $account->id,
'legal_entity_id' => 123231,
'settings' => $settings,
]);
$account->default_company_id = $company->id;
$account->save();
$el = new EntityLevel();
$validation = $el->checkCompany($company);
$this->assertTrue($validation['passes']);
}
public function testInValidBusinessCompanySettingsNoVat()
{
$settings = CompanySettings::defaults();
$settings->address1 = '10 Wallaby Way';
$settings->city = 'Sydney';
$settings->state = 'NSW';
$settings->postal_code = '2113';
$settings->country_id = '1';
$settings->vat_number = '';
$settings->classification = 'business';
$account = Account::factory()->create();
$company = Company::factory()->create([
'account_id' => $account->id,
'legal_entity_id' => 123231,
'settings' => $settings,
]);
$account->default_company_id = $company->id;
$account->save();
$el = new EntityLevel();
$validation = $el->checkCompany($company);
$this->assertFalse($validation['passes']);
}
public function testValidIndividualCompanySettingsNoVat()
{
$settings = CompanySettings::defaults();
$settings->address1 = '10 Wallaby Way';
$settings->city = 'Sydney';
$settings->state = 'NSW';
$settings->postal_code = '2113';
$settings->country_id = '1';
$settings->vat_number = '';
$settings->classification = 'individual';
$account = Account::factory()->create();
$company = Company::factory()->create([
'account_id' => $account->id,
'legal_entity_id' => 123231,
'settings' => $settings,
]);
$account->default_company_id = $company->id;
$account->save();
$el = new EntityLevel();
$validation = $el->checkCompany($company);
$this->assertTrue($validation['passes']);
}
public function testInValidBusinessCompanySettingsNoLegalEntity()
{
$settings = CompanySettings::defaults();
$settings->address1 = '10 Wallaby Way';
$settings->city = 'Sydney';
$settings->state = 'NSW';
$settings->postal_code = '2113';
$settings->country_id = '1';
$settings->vat_number = '';
$settings->classification = 'business';
$account = Account::factory()->create();
$company = Company::factory()->create([
'account_id' => $account->id,
'settings' => $settings,
]);
$account->default_company_id = $company->id;
$account->save();
$el = new EntityLevel();
$validation = $el->checkCompany($company);
nlog($validation);
$this->assertFalse($validation['passes']);
}
public function testInvalidClientSettings()
{
$company = Company::factory()->create([
'account_id' => $this->account->id,
]);
$client = Client::factory()->create([
'user_id' => $this->user->id,
'company_id' => $company->id,
'classification' => 'business',
'vat_number' => '',
]);
$el = new EntityLevel();
$validation = $el->checkClient($client);
$this->assertFalse($validation['passes']);
}
public function testInvalidClientSettingsNoCountry()
{
$company = Company::factory()->create([
'account_id' => $this->account->id,
]);
$client = Client::factory()->create([
'user_id' => $this->user->id,
'company_id' => $company->id,
'classification' => 'individual',
'vat_number' => '',
'country_id' => null,
]);
$el = new EntityLevel();
$validation = $el->checkClient($client);
$this->assertFalse($validation['passes']);
}
public function testInvalidClientSettingsMissingAddress()
{
$company = Company::factory()->create([
'account_id' => $this->account->id,
]);
$client = Client::factory()->create([
'user_id' => $this->user->id,
'company_id' => $company->id,
'classification' => 'individual',
'vat_number' => '',
'country_id' => null,
]);
$el = new EntityLevel();
$validation = $el->checkClient($client);
$this->assertFalse($validation['passes']);
}
public function testInvalidClientSettingsMissingAddressOnlyCountry()
{
$company = Company::factory()->create([
'account_id' => $this->account->id,
]);
$client = Client::factory()->create([
'user_id' => $this->user->id,
'company_id' => $company->id,
'classification' => 'individual',
'vat_number' => '',
'country_id' => 1,
'address1' => '',
'address2' => '',
'city' => '',
'state' => '',
'postal_code' => '',
]);
$el = new EntityLevel();
$validation = $el->checkClient($client);
$this->assertFalse($validation['passes']);
}
public function testInvalidClientSettingsMissingAddressOnlyCountryAndAddress1()
{
$company = Company::factory()->create([
'account_id' => $this->account->id,
]);
$client = Client::factory()->create([
'user_id' => $this->user->id,
'company_id' => $company->id,
'classification' => 'individual',
'vat_number' => '',
'country_id' => 1,
'address1' => '10 Wallaby Way',
'address2' => '',
'city' => '',
'state' => '',
'postal_code' => '',
]);
$el = new EntityLevel();
$validation = $el->checkClient($client);
$this->assertFalse($validation['passes']);
}
public function testInvalidClientSettingsMissingAddressOnlyCountryAndAddress1AndCity()
{
$company = Company::factory()->create([
'account_id' => $this->account->id,
]);
$client = Client::factory()->create([
'user_id' => $this->user->id,
'company_id' => $company->id,
'classification' => 'individual',
'vat_number' => '',
'country_id' => 1,
'address1' => '10 Wallaby Way',
'address2' => '',
'city' => 'Sydney',
'state' => '',
'postal_code' => '',
]);
$el = new EntityLevel();
$validation = $el->checkClient($client);
$this->assertFalse($validation['passes']);
}
public function testInvalidClientSettingsMissingAddressOnlyCountryAndAddress1AndCityAndState()
{
$company = Company::factory()->create([
'account_id' => $this->account->id,
]);
$client = Client::factory()->create([
'user_id' => $this->user->id,
'company_id' => $company->id,
'classification' => 'individual',
'vat_number' => '',
'country_id' => 1,
'address1' => '10 Wallaby Way',
'address2' => '',
'city' => 'Sydney',
'state' => 'NSW',
'postal_code' => '',
]);
$el = new EntityLevel();
$validation = $el->checkClient($client);
$this->assertFalse($validation['passes']);
}
public function testValidIndividualClient()
{
$company = Company::factory()->create([
'account_id' => $this->account->id,
]);
$client = Client::factory()->create([
'user_id' => $this->user->id,
'company_id' => $company->id,
'classification' => 'individual',
'vat_number' => '',
'country_id' => 1,
'address1' => '10 Wallaby Way',
'address2' => '',
'city' => 'Sydney',
'state' => 'NSW',
'postal_code' => '2113',
]);
$el = new EntityLevel();
$validation = $el->checkClient($client);
$this->assertTrue($validation['passes']);
}
public function testValidBusinessClient()
{
$company = Company::factory()->create([
'account_id' => $this->account->id,
]);
$client = Client::factory()->create([
'user_id' => $this->user->id,
'company_id' => $company->id,
'classification' => 'business',
'vat_number' => 'DE123456789',
'country_id' => 1,
'address1' => '10 Wallaby Way',
'address2' => '',
'city' => 'Sydney',
'state' => 'NSW',
'postal_code' => '2113',
]);
$el = new EntityLevel();
$validation = $el->checkClient($client);
$this->assertTrue($validation['passes']);
}
public function testInValidBusinessClientNoVat()
{
$company = Company::factory()->create([
'account_id' => $this->account->id,
]);
$client = Client::factory()->create([
'user_id' => $this->user->id,
'company_id' => $company->id,
'classification' => 'business',
'vat_number' => '',
'country_id' => 1,
'address1' => '10 Wallaby Way',
'address2' => '',
'city' => 'Sydney',
'state' => 'NSW',
'postal_code' => '2113',
]);
$el = new EntityLevel();
$validation = $el->checkClient($client);
$this->assertEquals(0, strlen($client->vat_number));
$this->assertFalse($validation['passes']);
}
}