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;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Utils\Ninja;
|
|
||||||
use Http;
|
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
use App\Http\Requests\EInvoice\Peppol\StoreEntityRequest;
|
use App\Http\Requests\EInvoice\Peppol\StoreEntityRequest;
|
||||||
|
|
@ -54,30 +52,16 @@ class EInvoicePeppolController extends BaseController
|
||||||
*/
|
*/
|
||||||
$company = auth()->user()->company();
|
$company = auth()->user()->company();
|
||||||
|
|
||||||
$headers = [
|
$response = $storecove
|
||||||
'Content-Type' => 'application/json',
|
->proxy
|
||||||
'Accept' => 'application/json',
|
->setCompany($company)
|
||||||
];
|
->setup($request->validated());
|
||||||
|
|
||||||
if (Ninja::isSelfHost()) {
|
if (data_get($response, 'status') === 'error') {
|
||||||
$headers['X-EInvoice-Token'] = $company->account->e_invoicing_token;
|
return response()->json(data_get($response, 'errors', 'message'), status: $response['code']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Ninja::isHosted()) {
|
$company->legal_entity_id = $response['legal_entity_id'];
|
||||||
$headers['X-EInvoice-Secret'] = config('ninja.hosted_einvoice_secret');
|
|
||||||
}
|
|
||||||
|
|
||||||
$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,
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($response->successful()) {
|
|
||||||
$company->legal_entity_id = $response->json('legal_entity_id');
|
|
||||||
|
|
||||||
$tax_data = $company->tax_data;
|
$tax_data = $company->tax_data;
|
||||||
|
|
||||||
|
|
@ -108,44 +92,25 @@ class EInvoicePeppolController extends BaseController
|
||||||
return response()->noContent();
|
return response()->noContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($response->status() === 422) {
|
|
||||||
return response()->json($response->json(), 422);
|
|
||||||
}
|
|
||||||
|
|
||||||
return response()->noContent(status: 500);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update legal properties such as acting as sender or receiver.
|
* Update legal properties such as acting as sender or receiver.
|
||||||
*
|
*
|
||||||
* @param \App\Http\Requests\EInvoice\Peppol\UpdateEntityRequest $request
|
* @param \App\Http\Requests\EInvoice\Peppol\UpdateEntityRequest $request
|
||||||
* @return JsonResponse|mixed|Response
|
* @return JsonResponse|mixed|Response
|
||||||
*/
|
*/
|
||||||
public function updateLegalEntity(UpdateEntityRequest $request)
|
public function updateLegalEntity(UpdateEntityRequest $request, Storecove $storecove): JsonResponse
|
||||||
{
|
{
|
||||||
$company = auth()->user()->company();
|
$company = auth()->user()->company();
|
||||||
|
|
||||||
$headers = [
|
$response = $storecove
|
||||||
'Content-Type' => 'application/json',
|
->proxy
|
||||||
'Accept' => 'application/json',
|
->setCompany($company)
|
||||||
];
|
->updateLegalEntity($request->validated());
|
||||||
|
|
||||||
if (Ninja::isSelfHost()) {
|
if (data_get($response, 'status') === 'error') {
|
||||||
$headers['X-EInvoice-Token'] = $company->account->e_invoicing_token;
|
return response()->json(data_get($response, 'errors', 'message'), status: $response['code']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Ninja::isHosted()) {
|
|
||||||
$headers['X-EInvoice-Secret'] = config('ninja.hosted_einvoice_secret');
|
|
||||||
}
|
|
||||||
|
|
||||||
$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,
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($response->successful()) {
|
|
||||||
$tax_data = $company->tax_data;
|
$tax_data = $company->tax_data;
|
||||||
|
|
||||||
$tax_data->acts_as_sender = $request->acts_as_sender;
|
$tax_data->acts_as_sender = $request->acts_as_sender;
|
||||||
|
|
@ -155,10 +120,7 @@ class EInvoicePeppolController extends BaseController
|
||||||
|
|
||||||
$company->save();
|
$company->save();
|
||||||
|
|
||||||
return response()->noContent();
|
return response()->json();
|
||||||
}
|
|
||||||
|
|
||||||
return response()->json(['message' => 'Error updating identifier'], 422);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -167,36 +129,22 @@ class EInvoicePeppolController extends BaseController
|
||||||
* @param DisconnectRequest $request
|
* @param DisconnectRequest $request
|
||||||
* @return \Illuminate\Http\Response
|
* @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
|
* @var \App\Models\Company $company
|
||||||
*/
|
*/
|
||||||
$company = auth()->user()->company();
|
$company = auth()->user()->company();
|
||||||
|
|
||||||
$headers = [
|
$response = $storecove
|
||||||
'Content-Type' => 'application/json',
|
->proxy
|
||||||
'Accept' => 'application/json',
|
->setCompany($company)
|
||||||
];
|
->disconnect();
|
||||||
|
|
||||||
if (Ninja::isSelfHost()) {
|
if (data_get($response, 'status') === 'error') {
|
||||||
$headers['X-EInvoice-Token'] = $company->account->e_invoicing_token;
|
return response()->json(data_get($response, 'errors', 'message'), status: $response['code']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Ninja::isHosted()) {
|
|
||||||
$headers['X-EInvoice-Secret'] = config('ninja.hosted_einvoice_secret');
|
|
||||||
}
|
|
||||||
|
|
||||||
nlog($headers);
|
|
||||||
|
|
||||||
$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,
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($response->successful()) {
|
|
||||||
$company->legal_entity_id = null;
|
$company->legal_entity_id = null;
|
||||||
$company->tax_data = $this->unsetVatNumbers($company->tax_data);
|
$company->tax_data = $this->unsetVatNumbers($company->tax_data);
|
||||||
|
|
||||||
|
|
@ -207,10 +155,7 @@ class EInvoicePeppolController extends BaseController
|
||||||
|
|
||||||
$company->save();
|
$company->save();
|
||||||
|
|
||||||
return response()->noContent();
|
return response()->json();
|
||||||
}
|
|
||||||
|
|
||||||
return response()->noContent(status: 500);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -223,9 +168,8 @@ class EInvoicePeppolController extends BaseController
|
||||||
* @param Storecove $storecove
|
* @param Storecove $storecove
|
||||||
* @return \Illuminate\Http\JsonResponse
|
* @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();
|
$company = auth()->user()->company();
|
||||||
$tax_data = $company->tax_data;
|
$tax_data = $company->tax_data;
|
||||||
|
|
||||||
|
|
@ -235,20 +179,22 @@ class EInvoicePeppolController extends BaseController
|
||||||
return response()->json(['message' => 'Identifier already exists for this region.'], 400);
|
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;
|
$tax_data->regions->EU->subregions->{$request->country}->vat_number = $request->vat_number;
|
||||||
$company->tax_data = $tax_data;
|
$company->tax_data = $tax_data;
|
||||||
$company->save();
|
$company->save();
|
||||||
|
|
||||||
return response()->json(['message' => 'ok'], 200);
|
return response()->json(['message' => 'ok'], 200);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private function unsetVatNumbers(mixed $taxData): mixed
|
private function unsetVatNumbers(mixed $taxData): mixed
|
||||||
{
|
{
|
||||||
if (isset($taxData->regions->EU->subregions)) {
|
if (isset($taxData->regions->EU->subregions)) {
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
class AddTaxIdentifierRequest extends FormRequest
|
class AddTaxIdentifierRequest extends FormRequest
|
||||||
{
|
{
|
||||||
private array $vat_regex_patterns = [
|
public static array $vat_regex_patterns = [
|
||||||
'DE' => '/^DE\d{9}$/',
|
'DE' => '/^DE\d{9}$/',
|
||||||
'AT' => '/^ATU\d{8}$/',
|
'AT' => '/^ATU\d{8}$/',
|
||||||
'BE' => '/^BE0\d{9}$/',
|
'BE' => '/^BE0\d{9}$/',
|
||||||
|
|
@ -66,14 +66,14 @@ class AddTaxIdentifierRequest extends FormRequest
|
||||||
public function rules(): array
|
public function rules(): array
|
||||||
{
|
{
|
||||||
return [
|
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' => [
|
'vat_number' => [
|
||||||
'required',
|
'required',
|
||||||
'string',
|
'string',
|
||||||
'bail',
|
'bail',
|
||||||
function ($attribute, $value, $fail) {
|
function ($attribute, $value, $fail) {
|
||||||
if ($this->country && isset($this->vat_regex_patterns[$this->country])) {
|
if ($this->country && isset(self::$vat_regex_patterns[$this->country])) {
|
||||||
if (!preg_match($this->vat_regex_patterns[$this->country], $value)) {
|
if (!preg_match(self::$vat_regex_patterns[$this->country], $value)) {
|
||||||
$fail(ctrans('texts.invalid_vat_number'));
|
$fail(ctrans('texts.invalid_vat_number'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -89,6 +89,7 @@ class AddTaxIdentifierRequest extends FormRequest
|
||||||
if (isset($input['country'])) {
|
if (isset($input['country'])) {
|
||||||
$country = $this->country();
|
$country = $this->country();
|
||||||
$input['country'] = $country->iso_3166_2;
|
$input['country'] = $country->iso_3166_2;
|
||||||
|
$input['country_id'] = $country->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->replace($input);
|
$this->replace($input);
|
||||||
|
|
|
||||||
|
|
@ -262,6 +262,35 @@ class Storecove
|
||||||
return $r;
|
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
|
* CreateLegalEntity
|
||||||
*
|
*
|
||||||
|
|
@ -320,7 +349,7 @@ class Storecove
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function getLegalEntity($id)
|
public function getLegalEntity($id): array|\Illuminate\Http\Client\Response
|
||||||
{
|
{
|
||||||
|
|
||||||
$uri = "legal_entities/{$id}";
|
$uri = "legal_entities/{$id}";
|
||||||
|
|
@ -401,7 +430,7 @@ class Storecove
|
||||||
* @return mixed
|
* @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";
|
$uri = "legal_entities/{$legal_entity_id}/additional_tax_identifiers";
|
||||||
|
|
@ -477,13 +506,17 @@ class Storecove
|
||||||
* @param int $legal_entity_id
|
* @param int $legal_entity_id
|
||||||
* @return bool
|
* @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}";
|
$uri = "/legal_entities/{$legal_entity_id}";
|
||||||
|
|
||||||
$r = $this->httpClient($uri, (HttpVerb::DELETE)->value, []);
|
$r = $this->httpClient($uri, (HttpVerb::DELETE)->value, []);
|
||||||
|
|
||||||
return $r->successful();
|
if ($r->successful()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,92 @@ class StorecoveProxy
|
||||||
return $this->remoteRequest($uri, $payload); //abstract the http calls
|
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
|
* handleResponseError
|
||||||
*
|
*
|
||||||
|
|
@ -63,7 +149,6 @@ class StorecoveProxy
|
||||||
*/
|
*/
|
||||||
private function handleResponseError($response): array
|
private function handleResponseError($response): array
|
||||||
{
|
{
|
||||||
|
|
||||||
$error = [
|
$error = [
|
||||||
'status' => 'error',
|
'status' => 'error',
|
||||||
'message' => 'Unknown error occurred',
|
'message' => 'Unknown error occurred',
|
||||||
|
|
@ -92,14 +177,15 @@ class StorecoveProxy
|
||||||
$error['message'] = 'Resource not found';
|
$error['message'] = 'Resource not found';
|
||||||
}
|
}
|
||||||
|
|
||||||
nlog(['Storecove API Error' => [
|
nlog([
|
||||||
|
'Storecove API Error' => [
|
||||||
'status' => $response->status(),
|
'status' => $response->status(),
|
||||||
'body' => $response->body(),
|
'body' => $response->body(),
|
||||||
'error' => $error
|
'error' => $error,
|
||||||
]]);
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
return $error;
|
return $error;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function remoteRequest(string $uri, array $payload = []): array
|
private function remoteRequest(string $uri, array $payload = []): array
|
||||||
|
|
|
||||||
|
|
@ -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/setup', [EInvoicePeppolController::class, 'setup'])->name('einvoice.peppol.setup');
|
||||||
Route::post('einvoice/peppol/disconnect', [EInvoicePeppolController::class, 'disconnect'])->name('einvoice.peppol.disconnect');
|
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::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::post('einvoice/token/update', EInvoiceTokenController::class)->name('einvoice.token.update');
|
||||||
Route::get('einvoice/quota', [EInvoiceController::class, 'quota'])->name('einvoice.quota');
|
Route::get('einvoice/quota', [EInvoiceController::class, 'quota'])->name('einvoice.quota');
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue