Skip to content

Commit

Permalink
Validation tests
Browse files Browse the repository at this point in the history
  • Loading branch information
turbo124 committed Oct 22, 2024
1 parent 29a372b commit 1d8b00f
Show file tree
Hide file tree
Showing 13 changed files with 488 additions and 107 deletions.
22 changes: 16 additions & 6 deletions app/Http/Controllers/EInvoicePeppolController.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace App\Http\Controllers;

use App\Http\Requests\EInvoice\Peppol\AddTaxIdentifierRequest;
use App\Http\Requests\EInvoice\Peppol\CreateRequest;
use App\Http\Requests\EInvoice\Peppol\DisconnectRequest;
use App\Services\EDocument\Gateway\Storecove\Storecove;
Expand All @@ -25,17 +26,14 @@ public function setup(CreateRequest $request, Storecove $storecove): Response
*/
$company = auth()->user()->company();

$data = [
...$request->validated(),
'country' => $request->country()->iso_3166_2,
];
$legal_entity_response = $storecove->createLegalEntity($request->validated(), $company);

$legal_entity_response = $storecove->createLegalEntity($data, $company);
$scheme = $storecove->router->resolveRouting($request->country, $company->settings->classification);

$add_identifier_response = $storecove->addIdentifier(
legal_entity_id: $legal_entity_response['id'],
identifier: $company->settings->vat_number,
scheme: $request->receiverIdentifier(),
scheme: $scheme,
);

if ($add_identifier_response) {
Expand All @@ -50,6 +48,18 @@ public function setup(CreateRequest $request, Storecove $storecove): Response
return response()->noContent(status: 422);
}

public function addAdditionalTaxIdentifier(AddTaxIdentifierRequest $request, Storecove $storecove): Response
{

$company = auth()->user()->company();

$scheme = $storecove->router->resolveRouting($request->country, $company->settings->classification);

$storecove->addAdditionalTaxIdentifier($company->legal_entity_id, $request->identifier, $scheme);

return response()->json(['message' => 'ok'], 200);
}

public function disconnect(DisconnectRequest $request, Storecove $storecove): Response
{
/**
Expand Down
54 changes: 54 additions & 0 deletions app/Http/Requests/Company/UpdateCompanyRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,36 @@ class UpdateCompanyRequest extends Request
'portal_custom_css',
'portal_custom_head'
];

private array $vat_regex_patterns = [
'DE' => '/^DE\d{9}$/',
'AT' => '/^ATU\d{8}$/',
'BE' => '/^BE0\d{9}$/',
'BG' => '/^BG\d{9,10}$/',
'CY' => '/^CY\d{8}L$/',
'HR' => '/^HR\d{11}$/',
'DK' => '/^DK\d{8}$/',
'ES' => '/^ES[A-Z0-9]\d{7}[A-Z0-9]$/',
'EE' => '/^EE\d{9}$/',
'FI' => '/^FI\d{8}$/',
'FR' => '/^FR\d{2}\d{9}$/',
'EL' => '/^EL\d{9}$/',
'HU' => '/^HU\d{8}$/',
'IE' => '/^IE\d{7}[A-Z]{1,2}$/',
'IT' => '/^IT\d{11}$/',
'LV' => '/^LV\d{11}$/',
'LT' => '/^LT(\d{9}|\d{12})$/',
'LU' => '/^LU\d{8}$/',
'MT' => '/^MT\d{8}$/',
'NL' => '/^NL\d{9}B\d{2}$/',
'PL' => '/^PL\d{10}$/',
'PT' => '/^PT\d{9}$/',
'CZ' => '/^CZ\d{8,10}$/',
'RO' => '/^RO\d{2,10}$/',
'SK' => '/^SK\d{10}$/',
'SI' => '/^SI\d{8}$/',
'SE' => '/^SE\d{12}$/',
];

/**
* Determine if the user is authorized to make this request.
Expand Down Expand Up @@ -86,6 +116,24 @@ public function rules()
$rules['inbound_mailbox_whitelist'] = ['sometimes', 'string', 'nullable', 'regex:/^[\w\-\.\+]+@([\w-]+\.)+[\w-]{2,4}(,[\w\-\.\+]+@([\w-]+\.)+[\w-]{2,4})*$/'];
$rules['inbound_mailbox_blacklist'] = ['sometimes', 'string', 'nullable', 'regex:/^[\w\-\.\+]+@([\w-]+\.)+[\w-]{2,4}(,[\w\-\.\+]+@([\w-]+\.)+[\w-]{2,4})*$/'];

$rules['settings.vat_number'] = [
'nullable',
'string',
'bail',
'sometimes',
Rule::requiredIf(function () {
return $this->input('settings.e_invoice_type') === 'PEPPOL';
}),
function ($attribute, $value, $fail) {
$country_code = $this->getCountryCode();
if ($country_code && isset($this->vat_regex_patterns[$country_code]) && $this->input('settings.e_invoice_type') === 'PEPPOL') {
if (!preg_match($this->vat_regex_patterns[$country_code], $value)) {
$fail(ctrans('texts.invalid_vat_number'));
}
}
},
];

return $rules;
}

Expand Down Expand Up @@ -139,6 +187,12 @@ public function prepareForValidation()
$this->replace($input);
}


private function getCountryCode()
{
return auth()->user()->company()->country()->iso_3166_2;
}

/**
* For the hosted platform, we restrict the feature settings.
*
Expand Down
115 changes: 115 additions & 0 deletions app/Http/Requests/EInvoice/Peppol/AddTaxIdentifierRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<?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\Http\Requests\EInvoice\Peppol;

use App\Models\Country;
use Illuminate\Validation\Rule;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Auth\Access\AuthorizationException;
use App\Rules\EInvoice\Peppol\SupportsReceiverIdentifier;
use App\Services\EDocument\Standards\Peppol\ReceiverIdentifier;

class AddTaxIdentifierRequest extends FormRequest
{
private array $vat_regex_patterns = [
'DE' => '/^DE\d{9}$/',
'AT' => '/^ATU\d{8}$/',
'BE' => '/^BE0\d{9}$/',
'BG' => '/^BG\d{9,10}$/',
'CY' => '/^CY\d{8}L$/',
'HR' => '/^HR\d{11}$/',
'DK' => '/^DK\d{8}$/',
'ES' => '/^ES[A-Z0-9]\d{7}[A-Z0-9]$/',
'EE' => '/^EE\d{9}$/',
'FI' => '/^FI\d{8}$/',
'FR' => '/^FR\d{2}\d{9}$/',
'EL' => '/^EL\d{9}$/',
'HU' => '/^HU\d{8}$/',
'IE' => '/^IE\d{7}[A-Z]{1,2}$/',
'IT' => '/^IT\d{11}$/',
'LV' => '/^LV\d{11}$/',
'LT' => '/^LT(\d{9}|\d{12})$/',
'LU' => '/^LU\d{8}$/',
'MT' => '/^MT\d{8}$/',
'NL' => '/^NL\d{9}B\d{2}$/',
'PL' => '/^PL\d{10}$/',
'PT' => '/^PT\d{9}$/',
'CZ' => '/^CZ\d{8,10}$/',
'RO' => '/^RO\d{2,10}$/',
'SK' => '/^SK\d{10}$/',
'SI' => '/^SI\d{8}$/',
'SE' => '/^SE\d{12}$/',
];

public function authorize(): bool
{
/**
* @var \App\Models\User
*/
$user = auth()->user();

if (app()->isLocal()) {
return true;
}

return $user->account->isPaid() && $user->isAdmin() && $user->company()->legal_entity_id != null;
}

/**
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'country' => ['required', 'bail', Rule::in(array_keys($this->vat_regex_patterns))],
'vat_number' => [
'required',
'string',
'bail',
function ($attribute, $value, $fail) {
if ($this->country && isset($this->vat_regex_patterns[$this->country])) {
if (!preg_match($this->vat_regex_patterns[$this->country], $value)) {
$fail(ctrans('texts.invalid_vat_number'));
}
}
},
]
];
}

public function prepareForValidation()
{
$input = $this->all();

if(isset($input['country'])) {
$country = $this->country();
$input['country'] = $country->iso_3166_2;
}

$this->replace($input);

}

public function country(): Country
{

/** @var \Illuminate\Support\Collection<\App\Models\Country> */
$countries = app('countries');

return $countries->first(function ($c){
return $this->country == $c->id;
});
}


}
60 changes: 53 additions & 7 deletions app/Http/Requests/EInvoice/Peppol/CreateRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,42 @@
use App\Services\EDocument\Standards\Peppol\ReceiverIdentifier;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;


class CreateRequest extends FormRequest
{

private array $vat_regex_patterns = [
'DE' => '/^DE\d{9}$/',
'AT' => '/^ATU\d{8}$/',
'BE' => '/^BE0\d{9}$/',
'BG' => '/^BG\d{9,10}$/',
'CY' => '/^CY\d{8}L$/',
'HR' => '/^HR\d{11}$/',
'DK' => '/^DK\d{8}$/',
'ES' => '/^ES[A-Z0-9]\d{7}[A-Z0-9]$/',
'EE' => '/^EE\d{9}$/',
'FI' => '/^FI\d{8}$/',
'FR' => '/^FR\d{2}\d{9}$/',
'EL' => '/^EL\d{9}$/',
'HU' => '/^HU\d{8}$/',
'IE' => '/^IE\d{7}[A-Z]{1,2}$/',
'IT' => '/^IT\d{11}$/',
'LV' => '/^LV\d{11}$/',
'LT' => '/^LT(\d{9}|\d{12})$/',
'LU' => '/^LU\d{8}$/',
'MT' => '/^MT\d{8}$/',
'NL' => '/^NL\d{9}B\d{2}$/',
'PL' => '/^PL\d{10}$/',
'PT' => '/^PT\d{9}$/',
'CZ' => '/^CZ\d{8,10}$/',
'RO' => '/^RO\d{2,10}$/',
'SK' => '/^SK\d{10}$/',
'SI' => '/^SI\d{8}$/',
'SE' => '/^SE\d{12}$/',
];

public function authorize(): bool
{
/**
Expand All @@ -31,7 +64,7 @@ public function authorize(): bool
return true;
}

return $user->account->isPaid() &&
return $user->account->isPaid() && $user->isAdmin() &&
$user->company()->legal_entity_id === null;
}

Expand All @@ -45,7 +78,7 @@ public function rules(): array
'line1' => ['required', 'string'],
'line2' => ['nullable', 'string'],
'city' => ['required', 'string'],
'country' => ['required', 'integer', 'exists:countries,id', new SupportsReceiverIdentifier()],
'country' => ['required', 'bail', Rule::in(array_keys($this->vat_regex_patterns))],
'zip' => ['required', 'string'],
'county' => ['required', 'string'],
];
Expand All @@ -58,15 +91,28 @@ protected function failedAuthorization(): void
);
}

public function country(): Country
public function prepareForValidation()
{
return Country::find($this->country);
$input = $this->all();

if(isset($input['country'])) {
$country = $this->country();
$input['country'] = $country->iso_3166_2;
}

$this->replace($input);

}

public function receiverIdentifier(): string
public function country(): Country
{
$identifier = new ReceiverIdentifier($this->country()->iso_3166_2);

/** @var \Illuminate\Support\Collection<\App\Models\Country> */
$countries = app('countries');

return $identifier->get();
return $countries->first(function ($c){
return $this->country == $c->id;
});
}

}
4 changes: 2 additions & 2 deletions app/Jobs/Mail/NinjaMailerJob.php
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ private function configureSmtpMailer()
$company = $this->company;

$smtp_host = $company->smtp_host ?? '';
$smtp_port = (int)$company->smtp_port;
$smtp_port = $company->smtp_port ?? 0;
$smtp_username = $company->smtp_username ?? '';
$smtp_password = $company->smtp_password ?? '';
$smtp_encryption = $company->smtp_encryption ?? 'tls';
Expand All @@ -437,7 +437,7 @@ private function configureSmtpMailer()
'mail.mailers.smtp' => [
'transport' => 'smtp',
'host' => $smtp_host,
'port' => $smtp_port,
'port' => (int)$smtp_port,
'username' => $smtp_username,
'password' => $smtp_password,
'encryption' => $smtp_encryption,
Expand Down
24 changes: 0 additions & 24 deletions app/Models/Company.php
Original file line number Diff line number Diff line change
Expand Up @@ -240,30 +240,6 @@ class Company extends BaseModel
use AppSetup;
use \Awobaz\Compoships\Compoships;

// const ENTITY_RECURRING_INVOICE = 'recurring_invoice';

// const ENTITY_CREDIT = 'credit';

// const ENTITY_QUOTE = 'quote';

// const ENTITY_TASK = 'task';

// const ENTITY_EXPENSE = 'expense';

// const ENTITY_PROJECT = 'project';

// const ENTITY_VENDOR = 'vendor';

// const ENTITY_TICKET = 'ticket';

// const ENTITY_PROPOSAL = 'proposal';

// const ENTITY_RECURRING_EXPENSE = 'recurring_expense';

// const ENTITY_RECURRING_TASK = 'task';

// const ENTITY_RECURRING_QUOTE = 'recurring_quote';

/** @var CompanyPresenter */
protected $presenter = CompanyPresenter::class;

Expand Down
Loading

0 comments on commit 1d8b00f

Please sign in to comment.