E-invoicing: Refactor calls (#113)
* Update main PEPPOL controller * Expose countries in AddTaxIdentifierRequest * setupLegalEntity method for Storecove * Add missing methods to the StorecoveProxy * Endpoint for additional legal identifiers * Update return types on getLegalEntity
This commit is contained in:
parent
76f2b975a2
commit
20e400d621
|
|
@ -11,8 +11,6 @@
|
|||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Utils\Ninja;
|
||||
use Http;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Response;
|
||||
use App\Http\Requests\EInvoice\Peppol\StoreEntityRequest;
|
||||
|
|
@ -54,65 +52,44 @@ class EInvoicePeppolController extends BaseController
|
|||
*/
|
||||
$company = auth()->user()->company();
|
||||
|
||||
$headers = [
|
||||
'Content-Type' => 'application/json',
|
||||
'Accept' => 'application/json',
|
||||
];
|
||||
$response = $storecove
|
||||
->proxy
|
||||
->setCompany($company)
|
||||
->setup($request->validated());
|
||||
|
||||
if (Ninja::isSelfHost()) {
|
||||
$headers['X-EInvoice-Token'] = $company->account->e_invoicing_token;
|
||||
if (data_get($response, 'status') === 'error') {
|
||||
return response()->json(data_get($response, 'errors', 'message'), status: $response['code']);
|
||||
}
|
||||
|
||||
if (Ninja::isHosted()) {
|
||||
$headers['X-EInvoice-Secret'] = config('ninja.hosted_einvoice_secret');
|
||||
}
|
||||
$company->legal_entity_id = $response['legal_entity_id'];
|
||||
|
||||
$response = Http::baseUrl(config('ninja.hosted_ninja_url'))
|
||||
->withHeaders($headers)
|
||||
->post('/api/einvoice/peppol/setup', data: [
|
||||
...$request->validated(),
|
||||
'classification' => $request->classification ?? $company->settings->classification,
|
||||
'vat_number' => $request->vat_number ?? $company->settings->vat_number,
|
||||
'id_number' => $request->id_number ?? $company->settings->id_number,
|
||||
]);
|
||||
$tax_data = $company->tax_data;
|
||||
|
||||
if ($response->successful()) {
|
||||
$company->legal_entity_id = $response->json('legal_entity_id');
|
||||
$tax_data->acts_as_sender = $request->acts_as_sender;
|
||||
$tax_data->acts_as_receiver = $request->acts_as_receiver;
|
||||
|
||||
$tax_data = $company->tax_data;
|
||||
$settings = $company->settings;
|
||||
|
||||
$tax_data->acts_as_sender = $request->acts_as_sender;
|
||||
$tax_data->acts_as_receiver = $request->acts_as_receiver;
|
||||
$settings->name = $request->party_name;
|
||||
$settings->country_id = (string) $request->country_id;
|
||||
$settings->address1 = $request->line1;
|
||||
$settings->address2 = $request->line2;
|
||||
$settings->city = $request->city;
|
||||
$settings->state = $request->county;
|
||||
$settings->postal_code = $request->zip;
|
||||
|
||||
$settings = $company->settings;
|
||||
$settings->e_invoice_type = 'PEPPOL';
|
||||
$settings->vat_number = $request->vat_number ?? $company->settings->vat_number;
|
||||
$settings->id_number = $request->id_number ?? $company->settings->id_number;
|
||||
$settings->classification = $request->classification ?? $company->settings->classification;
|
||||
$settings->enable_e_invoice = true;
|
||||
|
||||
$settings->name = $request->party_name;
|
||||
$settings->country_id = (string) $request->country_id;
|
||||
$settings->address1 = $request->line1;
|
||||
$settings->address2 = $request->line2;
|
||||
$settings->city = $request->city;
|
||||
$settings->state = $request->county;
|
||||
$settings->postal_code = $request->zip;
|
||||
$company->tax_data = $tax_data;
|
||||
$company->settings = $settings;
|
||||
|
||||
$settings->e_invoice_type = 'PEPPOL';
|
||||
$settings->vat_number = $request->vat_number ?? $company->settings->vat_number;
|
||||
$settings->id_number = $request->id_number ?? $company->settings->id_number;
|
||||
$settings->classification = $request->classification ?? $company->settings->classification;
|
||||
$settings->enable_e_invoice = true;
|
||||
$company->save();
|
||||
|
||||
$company->tax_data = $tax_data;
|
||||
$company->settings = $settings;
|
||||
|
||||
$company->save();
|
||||
|
||||
return response()->noContent();
|
||||
}
|
||||
|
||||
if ($response->status() === 422) {
|
||||
return response()->json($response->json(), 422);
|
||||
}
|
||||
|
||||
return response()->noContent(status: 500);
|
||||
return response()->noContent();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -121,44 +98,29 @@ class EInvoicePeppolController extends BaseController
|
|||
* @param \App\Http\Requests\EInvoice\Peppol\UpdateEntityRequest $request
|
||||
* @return JsonResponse|mixed|Response
|
||||
*/
|
||||
public function updateLegalEntity(UpdateEntityRequest $request)
|
||||
public function updateLegalEntity(UpdateEntityRequest $request, Storecove $storecove): JsonResponse
|
||||
{
|
||||
$company = auth()->user()->company();
|
||||
|
||||
$headers = [
|
||||
'Content-Type' => 'application/json',
|
||||
'Accept' => 'application/json',
|
||||
];
|
||||
$response = $storecove
|
||||
->proxy
|
||||
->setCompany($company)
|
||||
->updateLegalEntity($request->validated());
|
||||
|
||||
if (Ninja::isSelfHost()) {
|
||||
$headers['X-EInvoice-Token'] = $company->account->e_invoicing_token;
|
||||
if (data_get($response, 'status') === 'error') {
|
||||
return response()->json(data_get($response, 'errors', 'message'), status: $response['code']);
|
||||
}
|
||||
|
||||
if (Ninja::isHosted()) {
|
||||
$headers['X-EInvoice-Secret'] = config('ninja.hosted_einvoice_secret');
|
||||
}
|
||||
$tax_data = $company->tax_data;
|
||||
|
||||
$response = Http::baseUrl(config('ninja.hosted_ninja_url'))
|
||||
->withHeaders($headers)
|
||||
->put('/api/einvoice/peppol/update', data: [
|
||||
...$request->validated(),
|
||||
'legal_entity_id' => $company->legal_entity_id,
|
||||
]);
|
||||
$tax_data->acts_as_sender = $request->acts_as_sender;
|
||||
$tax_data->acts_as_receiver = $request->acts_as_receiver;
|
||||
|
||||
if ($response->successful()) {
|
||||
$tax_data = $company->tax_data;
|
||||
$company->tax_data = $tax_data;
|
||||
|
||||
$tax_data->acts_as_sender = $request->acts_as_sender;
|
||||
$tax_data->acts_as_receiver = $request->acts_as_receiver;
|
||||
$company->save();
|
||||
|
||||
$company->tax_data = $tax_data;
|
||||
|
||||
$company->save();
|
||||
|
||||
return response()->noContent();
|
||||
}
|
||||
|
||||
return response()->json(['message' => 'Error updating identifier'], 422);
|
||||
return response()->json();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -167,50 +129,33 @@ class EInvoicePeppolController extends BaseController
|
|||
* @param DisconnectRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function disconnect(DisconnectRequest $request): \Illuminate\Http\Response
|
||||
public function disconnect(DisconnectRequest $request, Storecove $storecove): JsonResponse
|
||||
{
|
||||
/**
|
||||
* @var \App\Models\Company $company
|
||||
*/
|
||||
$company = auth()->user()->company();
|
||||
|
||||
$headers = [
|
||||
'Content-Type' => 'application/json',
|
||||
'Accept' => 'application/json',
|
||||
];
|
||||
$response = $storecove
|
||||
->proxy
|
||||
->setCompany($company)
|
||||
->disconnect();
|
||||
|
||||
if (Ninja::isSelfHost()) {
|
||||
$headers['X-EInvoice-Token'] = $company->account->e_invoicing_token;
|
||||
if (data_get($response, 'status') === 'error') {
|
||||
return response()->json(data_get($response, 'errors', 'message'), status: $response['code']);
|
||||
}
|
||||
|
||||
if (Ninja::isHosted()) {
|
||||
$headers['X-EInvoice-Secret'] = config('ninja.hosted_einvoice_secret');
|
||||
}
|
||||
$company->legal_entity_id = null;
|
||||
$company->tax_data = $this->unsetVatNumbers($company->tax_data);
|
||||
|
||||
nlog($headers);
|
||||
$settings = $company->settings;
|
||||
$settings->e_invoice_type = 'EN16931';
|
||||
|
||||
$response = Http::baseUrl(config('ninja.hosted_ninja_url'))
|
||||
->withHeaders($headers)
|
||||
->post('/api/einvoice/peppol/disconnect', data: [
|
||||
'company_key' => $company->company_key,
|
||||
'legal_entity_id' => $company->legal_entity_id,
|
||||
]);
|
||||
$company->settings = $settings;
|
||||
|
||||
if ($response->successful()) {
|
||||
$company->legal_entity_id = null;
|
||||
$company->tax_data = $this->unsetVatNumbers($company->tax_data);
|
||||
$company->save();
|
||||
|
||||
$settings = $company->settings;
|
||||
$settings->e_invoice_type = 'EN16931';
|
||||
|
||||
$company->settings = $settings;
|
||||
|
||||
$company->save();
|
||||
|
||||
return response()->noContent();
|
||||
}
|
||||
|
||||
return response()->noContent(status: 500);
|
||||
return response()->json();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -223,9 +168,8 @@ class EInvoicePeppolController extends BaseController
|
|||
* @param Storecove $storecove
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function addAdditionalTaxIdentifier(AddTaxIdentifierRequest $request, Storecove $storecove): \Illuminate\Http\JsonResponse
|
||||
public function addAdditionalTaxIdentifier(AddTaxIdentifierRequest $request, Storecove $storecove): JsonResponse
|
||||
{
|
||||
|
||||
$company = auth()->user()->company();
|
||||
$tax_data = $company->tax_data;
|
||||
|
||||
|
|
@ -235,20 +179,22 @@ class EInvoicePeppolController extends BaseController
|
|||
return response()->json(['message' => 'Identifier already exists for this region.'], 400);
|
||||
}
|
||||
|
||||
$scheme = $storecove->router->resolveRouting($request->country, $company->settings->classification);
|
||||
$response = $storecove
|
||||
->proxy
|
||||
->setCompany($company)
|
||||
->addAdditionalTaxIdentifier($request->validated());
|
||||
|
||||
$storecove->addAdditionalTaxIdentifier($company->legal_entity_id, $request->vat_number, $scheme);
|
||||
if (data_get($response, 'status') === 'error') {
|
||||
return response()->json(data_get($response, 'errors', 'message'), status: $response['code']);
|
||||
}
|
||||
|
||||
$tax_data->regions->EU->subregions->{$request->country}->vat_number = $request->vat_number;
|
||||
$company->tax_data = $tax_data;
|
||||
$company->save();
|
||||
|
||||
return response()->json(['message' => 'ok'], 200);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private function unsetVatNumbers(mixed $taxData): mixed
|
||||
{
|
||||
if (isset($taxData->regions->EU->subregions)) {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use Illuminate\Foundation\Http\FormRequest;
|
|||
|
||||
class AddTaxIdentifierRequest extends FormRequest
|
||||
{
|
||||
private array $vat_regex_patterns = [
|
||||
public static array $vat_regex_patterns = [
|
||||
'DE' => '/^DE\d{9}$/',
|
||||
'AT' => '/^ATU\d{8}$/',
|
||||
'BE' => '/^BE0\d{9}$/',
|
||||
|
|
@ -66,14 +66,14 @@ class AddTaxIdentifierRequest extends FormRequest
|
|||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'country' => ['required', 'bail', Rule::in(array_keys($this->vat_regex_patterns))],
|
||||
'country' => ['required', 'bail', Rule::in(array_keys(self::$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)) {
|
||||
if ($this->country && isset(self::$vat_regex_patterns[$this->country])) {
|
||||
if (!preg_match(self::$vat_regex_patterns[$this->country], $value)) {
|
||||
$fail(ctrans('texts.invalid_vat_number'));
|
||||
}
|
||||
}
|
||||
|
|
@ -89,6 +89,7 @@ class AddTaxIdentifierRequest extends FormRequest
|
|||
if (isset($input['country'])) {
|
||||
$country = $this->country();
|
||||
$input['country'] = $country->iso_3166_2;
|
||||
$input['country_id'] = $country->id;
|
||||
}
|
||||
|
||||
$this->replace($input);
|
||||
|
|
|
|||
|
|
@ -262,6 +262,35 @@ class Storecove
|
|||
return $r;
|
||||
}
|
||||
|
||||
public function setupLegalEntity(array $data): array|\Illuminate\Http\Client\Response
|
||||
{
|
||||
$legal_entity_response = $this->createLegalEntity($data);
|
||||
|
||||
if (! is_array($legal_entity_response)) {
|
||||
return $legal_entity_response;
|
||||
}
|
||||
|
||||
$scheme = $this->router->resolveRouting($data['country'], $data['classification']);
|
||||
|
||||
$add_identifier_response = $this->addIdentifier(
|
||||
legal_entity_id: $legal_entity_response['id'],
|
||||
identifier: $data['classification'] === 'individual' ? str_replace('/','', $data['id_number']) : str_replace(" ", "", $data['vat_number']),
|
||||
scheme: $scheme,
|
||||
);
|
||||
|
||||
if (! is_array($add_identifier_response)) {
|
||||
return $add_identifier_response;
|
||||
}
|
||||
|
||||
return [
|
||||
'legal_entity_id' => $legal_entity_response['id'],
|
||||
'tax_data' => [
|
||||
'acts_as_sender' => $data['acts_as_sender'],
|
||||
'acts_as_receiver' => $data['acts_as_receiver'],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* CreateLegalEntity
|
||||
*
|
||||
|
|
@ -320,7 +349,7 @@ class Storecove
|
|||
* @param int $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function getLegalEntity($id)
|
||||
public function getLegalEntity($id): array|\Illuminate\Http\Client\Response
|
||||
{
|
||||
|
||||
$uri = "legal_entities/{$id}";
|
||||
|
|
@ -401,7 +430,7 @@ class Storecove
|
|||
* @return mixed
|
||||
*/
|
||||
|
||||
public function addAdditionalTaxIdentifier(int $legal_entity_id, string $identifier, string $scheme)
|
||||
public function addAdditionalTaxIdentifier(int $legal_entity_id, string $identifier, string $scheme): array|\Illuminate\Http\Client\Response
|
||||
{
|
||||
|
||||
$uri = "legal_entities/{$legal_entity_id}/additional_tax_identifiers";
|
||||
|
|
@ -477,13 +506,17 @@ class Storecove
|
|||
* @param int $legal_entity_id
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteIdentifier(int $legal_entity_id): bool
|
||||
public function deleteIdentifier(int $legal_entity_id): bool|\Illuminate\Http\Client\Response
|
||||
{
|
||||
$uri = "/legal_entities/{$legal_entity_id}";
|
||||
|
||||
$r = $this->httpClient($uri, (HttpVerb::DELETE)->value, []);
|
||||
|
||||
return $r->successful();
|
||||
if ($r->successful()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -22,13 +22,13 @@ class StorecoveProxy
|
|||
public function __construct(public Storecove $storecove)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public function setCompany(Company $company): self
|
||||
{
|
||||
$this->company = $company;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Example refactor.
|
||||
* getLegalEntity
|
||||
|
|
@ -38,12 +38,12 @@ class StorecoveProxy
|
|||
*/
|
||||
public function getLegalEntity(int $legal_entity_id): array
|
||||
{
|
||||
if(Ninja::isHosted()){
|
||||
if (Ninja::isHosted()) {
|
||||
$response = $this->storecove->getLegalEntity($legal_entity_id);
|
||||
|
||||
if(is_array($response)) //successful response is the array
|
||||
if (is_array($response)) //successful response is the array
|
||||
return $response;
|
||||
|
||||
|
||||
return $this->handleResponseError($response); //otherwise need to handle the http response returned
|
||||
}
|
||||
|
||||
|
|
@ -52,7 +52,93 @@ class StorecoveProxy
|
|||
|
||||
return $this->remoteRequest($uri, $payload); //abstract the http calls
|
||||
}
|
||||
|
||||
|
||||
public function setup(array $data): array
|
||||
{
|
||||
$data = [
|
||||
...$data,
|
||||
'classification' => $data['classification'] ?? $this->company->settings->classification,
|
||||
'vat_number' => $data['vat_number'] ?? $this->company->settings->vat_number,
|
||||
'id_number' => $data['id_number'] ?? $this->company->settings->id_number,
|
||||
];
|
||||
|
||||
if (Ninja::isHosted()) {
|
||||
$response = $this->storecove->setupLegalEntity($data);
|
||||
|
||||
if (is_array($response)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
return $this->handleResponseError($response);
|
||||
}
|
||||
|
||||
return $this->remoteRequest('/api/einvoice/peppol/setup', $data);
|
||||
}
|
||||
|
||||
public function disconnect(): bool|array
|
||||
{
|
||||
$data = [
|
||||
'company_key' => $this->company->company_key,
|
||||
'legal_entity_id' => $this->company->legal_entity_id,
|
||||
];
|
||||
|
||||
if (Ninja::isHosted()) {
|
||||
$response = $this->storecove->deleteIdentifier(
|
||||
legal_entity_id: $data['legal_entity_id'],
|
||||
);
|
||||
|
||||
if (is_bool($response)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
return $this->handleResponseError($response);
|
||||
}
|
||||
|
||||
return $this->remoteRequest('/api/einvoice/peppol/disconnect', $data);
|
||||
}
|
||||
|
||||
public function updateLegalEntity(array $data): array
|
||||
{
|
||||
$data = [
|
||||
...$data,
|
||||
'legal_entity_id' => $this->company->legal_entity_id,
|
||||
];
|
||||
|
||||
if (Ninja::isHosted()) {
|
||||
$response = $this->storecove->updateLegalEntity($data['legal_entity_id'], $data);
|
||||
|
||||
if (is_array($response)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
return $this->handleResponseError($response);
|
||||
}
|
||||
|
||||
return $this->remoteRequest('/api/einvoice/peppol/update', $data);
|
||||
}
|
||||
|
||||
public function addAdditionalTaxIdentifier(array $data): array
|
||||
{
|
||||
$data = [
|
||||
...$data,
|
||||
'classification' => $this->company->settings->classification,
|
||||
'legal_entity_id' => $this->company->legal_entity_id,
|
||||
];
|
||||
|
||||
if (Ninja::isHosted()) {
|
||||
$scheme = $this->storecove->router->resolveRouting($data['country'], $data['classification']);
|
||||
$response = $this->storecove->addAdditionalTaxIdentifier($data['legal_entity_id'], $data['vat_number'], $scheme);
|
||||
|
||||
if (is_array($response)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
return $this->handleResponseError($response);
|
||||
}
|
||||
|
||||
return $this->remoteRequest('/api/einvoice/peppol/add_additional_legal_identifier', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* handleResponseError
|
||||
*
|
||||
|
|
@ -63,7 +149,6 @@ class StorecoveProxy
|
|||
*/
|
||||
private function handleResponseError($response): array
|
||||
{
|
||||
|
||||
$error = [
|
||||
'status' => 'error',
|
||||
'message' => 'Unknown error occurred',
|
||||
|
|
@ -92,24 +177,25 @@ class StorecoveProxy
|
|||
$error['message'] = 'Resource not found';
|
||||
}
|
||||
|
||||
nlog(['Storecove API Error' => [
|
||||
'status' => $response->status(),
|
||||
'body' => $response->body(),
|
||||
'error' => $error
|
||||
]]);
|
||||
nlog([
|
||||
'Storecove API Error' => [
|
||||
'status' => $response->status(),
|
||||
'body' => $response->body(),
|
||||
'error' => $error,
|
||||
],
|
||||
]);
|
||||
|
||||
return $error;
|
||||
|
||||
}
|
||||
|
||||
private function remoteRequest(string $uri, array $payload =[]): array
|
||||
private function remoteRequest(string $uri, array $payload = []): array
|
||||
{
|
||||
|
||||
$response = Http::baseUrl(config('ninja.hosted_ninja_url'))
|
||||
->withHeaders($this->getHeaders())
|
||||
->post($uri, $payload);
|
||||
|
||||
if($response->successful())
|
||||
if ($response->successful())
|
||||
return $response->json();
|
||||
|
||||
return $this->handleResponseError($response);
|
||||
|
|
@ -117,7 +203,7 @@ class StorecoveProxy
|
|||
|
||||
private function getHeaders(): array
|
||||
{
|
||||
|
||||
|
||||
return [
|
||||
'Content-Type' => 'application/json',
|
||||
'Accept' => 'application/json',
|
||||
|
|
@ -126,4 +212,4 @@ class StorecoveProxy
|
|||
];
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -239,6 +239,7 @@ Route::group(['middleware' => ['throttle:api', 'api_db', 'token_auth', 'locale']
|
|||
Route::post('einvoice/peppol/setup', [EInvoicePeppolController::class, 'setup'])->name('einvoice.peppol.setup');
|
||||
Route::post('einvoice/peppol/disconnect', [EInvoicePeppolController::class, 'disconnect'])->name('einvoice.peppol.disconnect');
|
||||
Route::put('einvoice/peppol/update', [EInvoicePeppolController::class, 'updateLegalEntity'])->name('einvoice.peppol.update_legal_entity');
|
||||
Route::post('einvoice/peppol/add_additional_legal_identifier', [EInvoicePeppolController::class, 'addAdditionalTaxIdentifier'])->name('einvoice.peppol.add_additional_legal_identifier');
|
||||
|
||||
Route::post('einvoice/token/update', EInvoiceTokenController::class)->name('einvoice.token.update');
|
||||
Route::get('einvoice/quota', [EInvoiceController::class, 'quota'])->name('einvoice.quota');
|
||||
|
|
|
|||
Loading…
Reference in New Issue