From 57866333a89b45cadfbdbdbef4233da39b2d2b77 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 16 Aug 2024 07:26:03 +1000 Subject: [PATCH 1/6] Minor fixes --- app/Export/CSV/InvoiceItemExport.php | 4 ---- app/Export/CSV/PurchaseOrderItemExport.php | 4 ---- app/Models/Invoice.php | 28 +++++++++++----------- app/Models/PurchaseOrder.php | 28 +++++++++++----------- app/Providers/RouteServiceProvider.php | 2 +- app/Services/Client/Merge.php | 7 ++++++ 6 files changed, 36 insertions(+), 37 deletions(-) diff --git a/app/Export/CSV/InvoiceItemExport.php b/app/Export/CSV/InvoiceItemExport.php index b2b13b523acf..ef372c83752f 100644 --- a/app/Export/CSV/InvoiceItemExport.php +++ b/app/Export/CSV/InvoiceItemExport.php @@ -229,10 +229,6 @@ class InvoiceItemExport extends BaseExport // $entity['currency'] = $invoice->client->currency() ? $invoice->client->currency()->code : $invoice->company->currency()->code; // } - // if(array_key_exists('type', $entity)) { - // $entity['type'] = $invoice->typeIdString($entity['type']); - // } - // if(array_key_exists('tax_category', $entity)) { // $entity['tax_category'] = $invoice->taxTypeString($entity['tax_category']); // } diff --git a/app/Export/CSV/PurchaseOrderItemExport.php b/app/Export/CSV/PurchaseOrderItemExport.php index 4892436a6015..bbbcc62dc52c 100644 --- a/app/Export/CSV/PurchaseOrderItemExport.php +++ b/app/Export/CSV/PurchaseOrderItemExport.php @@ -213,10 +213,6 @@ class PurchaseOrderItemExport extends BaseExport // $entity['currency'] = $purchase_order->vendor->currency() ? $purchase_order->vendor->currency()->code : $purchase_order->company->currency()->code; // } - // if(array_key_exists('type', $entity)) { - // $entity['type'] = $purchase_order->typeIdString($entity['type']); - // } - // if(array_key_exists('tax_category', $entity)) { // $entity['tax_category'] = $purchase_order->taxTypeString($entity['tax_category']); // } diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index 4b98faa0c6c6..cc81e6b440fe 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -714,22 +714,22 @@ class Invoice extends BaseModel return $tax_type; } - public function typeIdString($id) - { - $type = ''; - match($id) { - '1' => $type = ctrans('texts.product'), - '2' => $type = ctrans('texts.service'), - '3' => $type = ctrans('texts.gateway_fees'), - '4' => $type = ctrans('texts.gateway_fees'), - '5' => $type = ctrans('texts.late_fees'), - '6' => $type = ctrans('texts.expense'), - default => $type = ctrans('texts.product'), - }; + // public function typeIdString($id) + // { + // $type = ''; + // match($id) { + // '1' => $type = ctrans('texts.product'), + // '2' => $type = ctrans('texts.service'), + // '3' => $type = ctrans('texts.gateway_fees'), + // '4' => $type = ctrans('texts.gateway_fees'), + // '5' => $type = ctrans('texts.late_fees'), + // '6' => $type = ctrans('texts.expense'), + // default => $type = ctrans('texts.product'), + // }; - return $type; + // return $type; - } + // } public function reminderSchedule(): string { diff --git a/app/Models/PurchaseOrder.php b/app/Models/PurchaseOrder.php index d536310fd881..3d20ae4275e3 100644 --- a/app/Models/PurchaseOrder.php +++ b/app/Models/PurchaseOrder.php @@ -353,22 +353,22 @@ class PurchaseOrder extends BaseModel return ctrans('texts.purchase_order'); } - public function typeIdString($id): string - { - $type = ''; - match($id) { - '1' => $type = ctrans('texts.product'), - '2' => $type = ctrans('texts.service'), - '3' => $type = ctrans('texts.gateway_fees'), - '4' => $type = ctrans('texts.gateway_fees'), - '5' => $type = ctrans('texts.late_fees'), - '6' => $type = ctrans('texts.expense'), - default => $type = ctrans('texts.product'), - }; + // public function typeIdString($id): string + // { + // $type = ''; + // match($id) { + // '1' => $type = ctrans('texts.product'), + // '2' => $type = ctrans('texts.service'), + // '3' => $type = ctrans('texts.gateway_fees'), + // '4' => $type = ctrans('texts.gateway_fees'), + // '5' => $type = ctrans('texts.late_fees'), + // '6' => $type = ctrans('texts.expense'), + // default => $type = ctrans('texts.product'), + // }; - return $type; + // return $type; - } + // } public function taxTypeString($id): string { diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 6421b53ca446..09250b10dcfa 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -65,7 +65,7 @@ class RouteServiceProvider extends ServiceProvider if (Ninja::isSelfHost()) { return Limit::none(); } else { - return Limit::perMinute(500)->by($request->ip()); + return Limit::perMinute(800)->by($request->ip()); } }); diff --git a/app/Services/Client/Merge.php b/app/Services/Client/Merge.php index b88fe879eb9f..46e01704b16a 100644 --- a/app/Services/Client/Merge.php +++ b/app/Services/Client/Merge.php @@ -31,9 +31,16 @@ class Merge extends AbstractService public function run() { + nlog("merging {$this->mergable_client->id} into {$this->client->id}"); + nlog("balance pre {$this->client->balance}"); + nlog("paid_to_date pre {$this->client->paid_to_date}"); + $this->client->balance += $this->mergable_client->balance; $this->client->paid_to_date += $this->mergable_client->paid_to_date; $this->client->save(); + + nlog("balance post {$this->client->balance}"); + nlog("paid_to_date post {$this->client->paid_to_date}"); $this->updateLedger($this->mergable_client->balance); From af73fc2e51f44be37bb1d035830adce587d1113e Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 19 Aug 2024 07:42:49 +1000 Subject: [PATCH 2/6] Improve expense XML parsing --- app/Filters/ProjectFilters.php | 2 +- app/Http/Controllers/ExpenseController.php | 13 ++--- .../Requests/Expense/EDocumentRequest.php | 4 +- app/Jobs/EDocument/ImportEDocument.php | 50 +++++++++++-------- .../EDocument/Imports/ZugferdEDocument.php | 34 +++++++------ 5 files changed, 57 insertions(+), 46 deletions(-) diff --git a/app/Filters/ProjectFilters.php b/app/Filters/ProjectFilters.php index 311e3465ca13..8b848472bd62 100644 --- a/app/Filters/ProjectFilters.php +++ b/app/Filters/ProjectFilters.php @@ -60,7 +60,7 @@ class ProjectFilters extends QueryFilters { $sort_col = explode('|', $sort); - if (!is_array($sort_col) || count($sort_col) != 2) { + if (!is_array($sort_col) || count($sort_col) != 2 || !in_array($sort_col[0], \Illuminate\Support\Facades\Schema::getColumnListing('projects'))) { return $this->builder; } diff --git a/app/Http/Controllers/ExpenseController.php b/app/Http/Controllers/ExpenseController.php index 0553b5dd3aec..3c2028c6f874 100644 --- a/app/Http/Controllers/ExpenseController.php +++ b/app/Http/Controllers/ExpenseController.php @@ -584,14 +584,15 @@ class ExpenseController extends BaseController return $this->itemResponse($expense->fresh()); } - public function edocument(EDocumentRequest $request): string + public function edocument(EDocumentRequest $request) { - if ($request->hasFile("documents")) { - return (new ImportEDocument($request->file("documents")[0]->get(), $request->file("documents")[0]->getClientOriginalName()))->handle(); - } - else { - return "No file found"; + $user = auth()->user(); + + foreach($request->file("documents") as $file) { + ImportEDocument::dispatch($file->get(), $file->getClientOriginalName(), $user->company()); } + return response()->json(['message' => 'Processing....'], 200); + } } diff --git a/app/Http/Requests/Expense/EDocumentRequest.php b/app/Http/Requests/Expense/EDocumentRequest.php index 5428eda9822d..643c3cd6fc33 100644 --- a/app/Http/Requests/Expense/EDocumentRequest.php +++ b/app/Http/Requests/Expense/EDocumentRequest.php @@ -25,9 +25,9 @@ class EDocumentRequest extends Request $rules = []; if ($this->file('documents') && is_array($this->file('documents'))) { - $rules['documents.*'] = $this->fileValidation(); + $rules['documents.*'] = 'required|file|max:1000000|mimes:xml'; } elseif ($this->file('documents')) { - $rules['documents'] = $this->fileValidation(); + $rules['documents'] = 'required|file|max:1000000|mimes:xml'; } return $rules; } diff --git a/app/Jobs/EDocument/ImportEDocument.php b/app/Jobs/EDocument/ImportEDocument.php index 13fb22de94f8..e92860faf81c 100644 --- a/app/Jobs/EDocument/ImportEDocument.php +++ b/app/Jobs/EDocument/ImportEDocument.php @@ -11,14 +11,16 @@ namespace App\Jobs\EDocument; -use App\Models\Expense; -use App\Services\EDocument\Imports\ZugferdEDocument; use Exception; +use App\Models\Company; +use App\Models\Expense; use Illuminate\Bus\Queueable; use Illuminate\Queue\SerializesModels; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; +use Illuminate\Queue\Middleware\WithoutOverlapping; +use App\Services\EDocument\Imports\ZugferdEDocument; class ImportEDocument implements ShouldQueue { @@ -27,14 +29,10 @@ class ImportEDocument implements ShouldQueue use Queueable; use SerializesModels; - public $deleteWhenMissingModels = true; - private string $file_name; - private readonly string $file_content; + public $tries = 1; - public function __construct(string $file_content, string $file_name) + public function __construct(private readonly string $file_content, private string $file_name, private Company $company) { - $this->file_content = $file_content; - $this->file_name = $file_name; } /** @@ -45,20 +43,30 @@ class ImportEDocument implements ShouldQueue */ public function handle(): Expense { - if (str_contains($this->file_name, ".xml")){ - switch (true) { - case stristr($this->file_content, "urn:cen.eu:en16931:2017"): - case stristr($this->file_content, "urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0"): - case stristr($this->file_content, "urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_2.1"): - case stristr($this->file_content, "urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_2.0"): - return (new ZugferdEDocument($this->file_content, $this->file_name))->run(); - default: - throw new Exception("E-Invoice standard not supported"); - } - } - else { - throw new Exception("File type not supported"); + + switch (true) { + case stristr($this->file_content, "urn:cen.eu:en16931:2017"): + case stristr($this->file_content, "urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0"): + case stristr($this->file_content, "urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_2.1"): + case stristr($this->file_content, "urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_2.0"): + return (new ZugferdEDocument($this->file_content, $this->file_name, $this->company))->run(); + default: + throw new Exception("E-Invoice standard not supported"); } } + + public function middleware() + { + return [new WithoutOverlapping($this->company->company_key)]; + } + + public function failed($exception = null) + { + if ($exception) { + nlog("EXCEPTION:: ImportEDocument:: ".$exception->getMessage()); + } + + config(['queue.failed.driver' => null]); + } } diff --git a/app/Services/EDocument/Imports/ZugferdEDocument.php b/app/Services/EDocument/Imports/ZugferdEDocument.php index 2f2384998201..f03d298a66a5 100644 --- a/app/Services/EDocument/Imports/ZugferdEDocument.php +++ b/app/Services/EDocument/Imports/ZugferdEDocument.php @@ -11,19 +11,20 @@ namespace App\Services\EDocument\Imports; -use App\Factory\ExpenseFactory; -use App\Factory\VendorFactory; -use App\Jobs\Util\UploadFile; -use App\Models\Country; -use App\Models\Currency; -use App\Models\Expense; -use App\Models\Vendor; -use App\Services\AbstractService; -use App\Utils\TempFile; use Exception; +use App\Models\Vendor; +use App\Models\Company; +use App\Models\Country; +use App\Models\Expense; +use App\Utils\TempFile; +use App\Models\Currency; +use App\Jobs\Util\UploadFile; +use App\Factory\VendorFactory; +use App\Factory\ExpenseFactory; +use App\Services\AbstractService; use horstoeko\zugferd\ZugferdDocumentReader; -use horstoeko\zugferdvisualizer\renderer\ZugferdVisualizerLaravelRenderer; use horstoeko\zugferdvisualizer\ZugferdVisualizer; +use horstoeko\zugferdvisualizer\renderer\ZugferdVisualizerLaravelRenderer; class ZugferdEDocument extends AbstractService { public ZugferdDocumentReader|string $document; @@ -31,7 +32,7 @@ class ZugferdEDocument extends AbstractService { /** * @throws Exception */ - public function __construct(public string $tempdocument, public string $documentname) + public function __construct(public string $tempdocument, public string $documentname, public Company $company) { # curl -X POST http://localhost:8000/api/v1/edocument/upload -H "Content-Type: multipart/form-data" -H "X-API-TOKEN: 7tdDdkz987H3AYIWhNGXy8jTjJIoDhkAclCDLE26cTCj1KYX7EBHC66VEitJwWhn" -H "X-Requested-With: XMLHttpRequest" -F _method=PUT -F documents[]=@einvoice.xml } @@ -42,13 +43,14 @@ class ZugferdEDocument extends AbstractService { public function run(): Expense { /** @var \App\Models\User $user */ - $user = auth()->user(); + $user = $this->company->owner(); + $this->document = ZugferdDocumentReader::readAndGuessFromContent($this->tempdocument); $this->document->getDocumentInformation($documentno, $documenttypecode, $documentdate, $invoiceCurrency, $taxCurrency, $documentname, $documentlanguage, $effectiveSpecifiedPeriod); $this->document->getDocumentSummation($grandTotalAmount, $duePayableAmount, $lineTotalAmount, $chargeTotalAmount, $allowanceTotalAmount, $taxBasisTotalAmount, $taxTotalAmount, $roundingAmount, $totalPrepaidAmount); /** @var \App\Models\Expense $expense */ - $expense = Expense::where("company_id", $user->company()->id)->where('amount', $grandTotalAmount)->where("transaction_reference", $documentno)->whereDate("date", $documentdate)->first(); + $expense = Expense::where("company_id", $this->company->id)->where('amount', $grandTotalAmount)->where("transaction_reference", $documentno)->whereDate("date", $documentdate)->first(); if (!$expense) { // The document does not exist as an expense // Handle accordingly @@ -59,10 +61,10 @@ class ZugferdEDocument extends AbstractService { $visualizer->setPdfPaperSize('A4-P'); $visualizer->setTemplate('edocument.xinvoice'); - $expense = ExpenseFactory::create($user->company()->id, $user->id); + $expense = ExpenseFactory::create($this->company->id, $user->id); $expense->date = $documentdate; $expense->public_notes = $documentno; - $expense->currency_id = Currency::whereCode($invoiceCurrency)->first()->id ?? $user->company()->settings->currency_id; + $expense->currency_id = Currency::whereCode($invoiceCurrency)->first()->id ?? $this->company->settings->currency_id; $expense->save(); $origin_file = TempFile::UploadedFileFromRaw($this->tempdocument, $this->documentname, "application/xml"); @@ -98,7 +100,7 @@ class ZugferdEDocument extends AbstractService { // Vendor found $expense->vendor_id = $vendor->id; } else { - $vendor = VendorFactory::create($user->company()->id, $user->id); + $vendor = VendorFactory::create($this->company->id, $user->id); $vendor->name = $name; if ($taxid != null) { $vendor->vat_number = $taxid; From 4e8197a6232ba1254f852c9d2edfcad36145b9f6 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 19 Aug 2024 11:45:34 +1000 Subject: [PATCH 3/6] peppol --- .../EDocument/Gateway/Storecove/Storecove.php | 1 - app/Services/EDocument/Standards/Peppol.php | 140 ++++++++--- .../Einvoice/Storecove/StorecoveTest.php | 233 +++++++++++++++++- 3 files changed, 328 insertions(+), 46 deletions(-) diff --git a/app/Services/EDocument/Gateway/Storecove/Storecove.php b/app/Services/EDocument/Gateway/Storecove/Storecove.php index 9734abfa587e..be840d084625 100644 --- a/app/Services/EDocument/Gateway/Storecove/Storecove.php +++ b/app/Services/EDocument/Gateway/Storecove/Storecove.php @@ -98,7 +98,6 @@ class Storecove { public function sendJsonDocument($document) { - $payload = [ "legalEntityId" => 290868, "idempotencyGuid" => \Illuminate\Support\Str::uuid(), diff --git a/app/Services/EDocument/Standards/Peppol.php b/app/Services/EDocument/Standards/Peppol.php index 9b0dbfba7092..6afe2024807a 100644 --- a/app/Services/EDocument/Standards/Peppol.php +++ b/app/Services/EDocument/Standards/Peppol.php @@ -112,8 +112,8 @@ class Peppol extends AbstractService 'HR' => 'VAT', 'HU' => 'VAT', 'IE' => 'VAT', - 'IT' => 'IVA', //tested - Requires a Customer Party Identification (VAT number) - 'IT' => 'CF', //tested - Requires a Customer Party Identification (VAT number) + 'IT' => 'IVA', //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.' 'LT' => 'VAT', 'LU' => 'VAT', 'LV' => 'VAT', @@ -158,10 +158,13 @@ class Peppol extends AbstractService // 0 1 2 3 // ["Country" => ["B2X","Legal","Tax","Routing"], private array $routing_rules = [ - "US" => ["B","DUNS, GLN, LEI","US:EIN, US:SSN","DUNS, GLN, LEI"], - "CA" => ["B","CA:CBN","","CA:CBN"], - "MX" => ["B","MX:RFC","","MX:RFC"], - "AU" => ["B+G","AU:ABN","","AU:ABN"], + "US" => [ + ["B","DUNS, GLN, LEI","US:EIN","DUNS, GLN, LEI"], + // ["B","DUNS, GLN, LEI","US:SSN","DUNS, GLN, LEI"], + ], + "CA" => ["B","CA:CBN",false,"CA:CBN"], + "MX" => ["B","MX:RFC",false,"MX:RFC"], + "AU" => ["B+G","AU:ABN",false,"AU:ABN"], "NZ" => ["B+G","GLN","NZ:GST","GLN"], "CH" => ["B+G","CH:UIDB","CH:VAT","CH:UIDB"], "IS" => ["B+G","IS:KTNR","IS:VAT","IS:KTNR"], @@ -170,7 +173,7 @@ class Peppol extends AbstractService "AD" => ["B+G","","AD:VAT","AD:VAT"], "AL" => ["B+G","","AL:VAT","AL:VAT"], "AT" => [ - ["G","AT:GOV","","9915:b"], + ["G","AT:GOV",false,"9915:b"], ["B","","AT:VAT","AT:VAT"], ], "BA" => ["B+G","","BA:VAT","BA:VAT"], @@ -179,7 +182,7 @@ class Peppol extends AbstractService "CY" => ["B+G","","CY:VAT","CY:VAT"], "CZ" => ["B+G","","CZ:VAT","CZ:VAT"], "DE" => [ - ["G","DE:LWID","","DE:LWID"], + ["G","DE:LWID",false,"DE:LWID"], ["B","","DE:VAT","DE:VAT"], ], "DK" => ["B+G","DK:DIGST","DK:ERST","DK:DIGST"], @@ -187,7 +190,7 @@ class Peppol extends AbstractService "ES" => ["B","","ES:VAT","ES:VAT"], "FI" => ["B+G","FI:OVT","FI:VAT","FI:OVT"], "FR" => [ - ["G","FR:SIRET + customerAssignedAccountIdValue","","0009:11000201100044"], + ["G","FR:SIRET + customerAssignedAccountIdValue",false,"0009:11000201100044"], ["B","FR:SIRENE or FR:SIRET","FR:VAT","FR:SIRENE or FR:SIRET"], ], "GR" => ["B+G","","GR:VAT","GR:VAT"], @@ -195,10 +198,11 @@ class Peppol extends AbstractService "HU" => ["B+G","","HU:VAT","HU:VAT"], "IE" => ["B+G","","IE:VAT","IE:VAT"], "IT" => [ - ["G (Peppol)","","IT:IVA","IT:CUUO"], - ["B (SDI)","","IT:CF and/or IT:IVA","IT:CUUO"], - ["C (SDI)","","IT:CF","Email"], - ["G (SDI)","","IT:IVA","IT:CUUO"], + ["G","","IT:IVA","IT:CUUO"], // (Peppol) + ["B","","IT:IVA","IT:CUUO"], // (SDI) + // ["B","","IT:CF","IT:CUUO"], // (SDI) + ["C","","IT:CF","Email"],// (SDI) + ["G","","IT:IVA","IT:CUUO"],// (SDI) ], "LT" => ["B+G","LT:LEC","LT:VAT","LT:LEC"], "LU" => ["B+G","LU:MAT","LU:VAT","LU:VAT"], @@ -207,7 +211,7 @@ class Peppol extends AbstractService "ME" => ["B+G","","ME:VAT","ME:VAT"], "MK" => ["B+G","","MK:VAT","MK:VAT"], "MT" => ["B+G","","MT:VAT","MT:VAT"], - "NL" => ["G","NL:OINO","","NL:OINO"], + "NL" => ["G","NL:OINO",false,"NL:OINO"], "NL" => ["B","NL:KVK","NL:VAT","NL:KVK or NL:VAT"], "PL" => ["G+B","","PL:VAT","PL:VAT"], "PT" => ["G+B","","PT:VAT","PT:VAT"], @@ -223,12 +227,12 @@ class Peppol extends AbstractService "JP" => ["B","JP:SST","JP:IIN","JP:SST"], "MY" => ["B","MY:EIF","MY:TIN","MY:EIF"], "SG" => [ - ["G","SG:UEN","","0195:SGUENT08GA0028A"], - ["B","SG:UEN","SG:GST (optional)","SG:UEN"], + ["G","SG:UEN",false,"0195:SGUENT08GA0028A"], + ["B","SG:UEN","SG:GST","SG:UEN"], ], "GB" => ["B","","GB:VAT","GB:VAT"], "SA" => ["B","","SA:TIN","Email"], - "Other" => ["B","DUNS, GLN, LEI","","DUNS, GLN, LEI"], + "Other" => ["B","DUNS, GLN, LEI",false,"DUNS, GLN, LEI"], ]; private Company $company; @@ -726,6 +730,31 @@ class Peppol extends AbstractService return $asp; } + 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; + + match($this->invoice->client->classification){ + "business" => $code = "B", + "government" => $code = "G", + "individual" => $code = "C", + default => $code = false, + }; + + if(count($rules) > 1){ + + foreach($rules as $rule) + { + if(stripos($rule[0], $code) !== false) { + return $rule[2]; + } + } + } + + return false; + + } + private function getAccountingCustomerParty(): AccountingCustomerParty { @@ -736,10 +765,13 @@ class Peppol extends AbstractService if(strlen($this->invoice->client->vat_number ?? '') > 1) { $pi = new PartyIdentification; + $vatID = new ID; - $vatID->schemeID = 'CH:MWST'; + + if($scheme = $this->resolveTaxScheme()) + $vatID->schemeID = $scheme; + $vatID->value = $this->invoice->client->vat_number; - $pi->ID = $vatID; $party->PartyIdentification[] = $pi; @@ -1055,26 +1087,34 @@ class Peppol extends AbstractService /** * Builds the Routing object for StoreCove * - * @param string $schemeId - * @param string $id + * @param array $identifiers * @return array */ - private function buildRouting(string $schemeId, string $id): array + private function buildRouting(array $identifiers): array { return [ "routing" => [ - "publicIdentifiers" => [ - [ - "scheme" => $schemeId, - "id" => $id - ] - ] + "eIdentifiers" => + $identifiers, + ] ]; } + private function setEmailRouting(string $email): self + { + $meta = $this->getStorecoveMeta(); + $emails = isset($meta['routing']['emails']) ? $meta['routing']['emails'] : ($meta['routing']['emails'] = []); + + array_push($emails, $email); + + $this->setStorecoveMeta($emails); + + return $this; + } + /** * setStorecoveMeta * @@ -1150,7 +1190,7 @@ class Peppol extends AbstractService if($this->invoice->client->classification == 'government') { //routing "b" for production "test" for test environment - $this->setStorecoveMeta($this->buildRouting('AT:GOV', "b")); + $this->setStorecoveMeta($this->buildRouting(["scheme" => 'AT:GOV', "id" => 'b'])); //for government clients this must be set. $this->setCustomerAssignedAccountId(true); @@ -1239,7 +1279,11 @@ class Peppol extends AbstractService if($this->invoice->client->classification == 'government'){ //route to SIRET 0009:11000201100044 - $this->setStorecoveMeta($this->buildRouting('FR:SIRET', "0009:11000201100044")); + $this->setStorecoveMeta($this->buildRouting([ + ["scheme" => 'FR:SIRET', "id" => '11000201100044'] + + // ["scheme" => 'FR:SIRET', "id" => '0009:11000201100044'] + ])); // The SIRET / 0009 identifier of the final recipient is to be included in the invoice.accountingCustomerParty.publicIdentifiers array. $this->setCustomerAssignedAccountId(true); @@ -1248,11 +1292,19 @@ class Peppol extends AbstractService if(strlen($this->invoice->client->id_number ?? '') == 9) { //SIREN - $this->setStorecoveMeta($this->buildRouting('FR:SIREN', "0002:{$this->invoice->client->id_number}")); + $this->setStorecoveMeta($this->buildRouting([ + ["scheme" => 'FR:SIRET', "id" => "{$this->invoice->client->id_number}"] + + // ["scheme" => 'FR:SIRET', "id" => "0002:{$this->invoice->client->id_number}"] + ])); } else { //SIRET - $this->setStorecoveMeta($this->buildRouting('FR:SIRET', "0009:{$this->invoice->client->id_number}")); + $this->setStorecoveMeta($this->buildRouting([ + ["scheme" => 'FR:SIRET', "id" => "{$this->invoice->client->id_number}"] + + // ["scheme" => 'FR:SIRET', "id" => "0009:{$this->invoice->client->id_number}"] + ])); } // Apparently this is not a special field according to support @@ -1271,18 +1323,24 @@ class Peppol extends AbstractService // IT Sender, IT Receiver, B2B/B2G // Provide the receiver IT:VAT and the receiver IT:CUUO (codice destinatario) - if($this->invoice->client->classification == 'government' && $this->invoice->company->country()->iso_3166_2 == 'IT') { - - $this->setStorecoveMeta($this->buildRouting('IT:VAT', $this->invoice->client->routing_id)); - + 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([ + ["scheme" => 'IT:IVA', "id" => $this->invoice->client->vat_number], + ["scheme" => 'IT:CUUO', "id" => $this->invoice->client->routing_id] + ])); return $this; } // IT Sender, IT Receiver, B2C // 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') { - - $this->setStorecoveMeta($this->buildRouting('IT:CF', $this->invoice->client->routing_id)); + nlog("business receiver"); + + $this->setStorecoveMeta($this->buildRouting([ + ["scheme" => 'IT:CF', "id" => $this->invoice->client->vat_number], + ["scheme" => 'IT:CUUO', "id" => $this->invoice->client->routing_id] + ])); return $this; } @@ -1293,7 +1351,10 @@ class Peppol extends AbstractService $code = $this->getClientRoutingCode(); - $this->setStorecoveMeta($this->buildRouting($code, $this->invoice->client->vat_number)); + nlog("foreign receiver"); + $this->setStorecoveMeta($this->buildRouting([ + ["scheme" => $code, "id" => $this->invoice->client->vat_number] + ])); return $this; } @@ -1311,7 +1372,6 @@ class Peppol extends AbstractService return $this; } - // non-IT Sender, IT Receiver, B2B/B2G // Provide the receiver IT:VAT and the receiver IT:CUUO (codice destinatario) diff --git a/tests/Integration/Einvoice/Storecove/StorecoveTest.php b/tests/Integration/Einvoice/Storecove/StorecoveTest.php index 92acb6ad09e0..36bcf1bb4fde 100644 --- a/tests/Integration/Einvoice/Storecove/StorecoveTest.php +++ b/tests/Integration/Einvoice/Storecove/StorecoveTest.php @@ -19,6 +19,7 @@ use Tests\MockAccountData; use App\DataMapper\InvoiceItem; use App\DataMapper\ClientSettings; use App\DataMapper\CompanySettings; +use App\Models\ClientContact; use App\Services\EDocument\Standards\Peppol; use Illuminate\Foundation\Testing\DatabaseTransactions; use InvoiceNinja\EInvoice\Models\Peppol\PaymentMeans; @@ -398,6 +399,170 @@ $x = ' } + + private function createITData($business = true) + { + + $this->routing_id = 294636; + + $settings = CompanySettings::defaults(); + $settings->company_logo = 'https://pdf.invoicing.co/favicon-v2.png'; + $settings->website = 'www.invoiceninja.it'; + $settings->address1 = 'Via del Corso, 28'; + $settings->address2 = 'Palazzo delle Telecomunicazioni'; + $settings->city = 'Roma'; + $settings->state = 'Lazio'; + $settings->postal_code = '00187'; + $settings->phone = '06 1234567'; + $settings->email = $this->faker->unique()->safeEmail(); + $settings->country_id = '380'; // Italy's ISO country code + $settings->vat_number = 'IT92443356490'; // Italian VAT number + $settings->id_number = 'RM 123456'; // Typical Italian 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.p.A.', + 'website' => 'https://www.impresa-esempio.it', + 'private_notes' => 'Queste sono note private per il cliente di prova.', + 'balance' => 0, + 'paid_to_date' => 0, + 'vat_number' => 'IT92443356489', // Italian VAT number with IT prefix + 'id_number' => 'B12345678', // Typical format for Italian company registration numbers + 'custom_value1' => '2024-07-22 10:00:00', + 'custom_value2' => 'blu', // Italian for blue + 'custom_value3' => 'parolaesempio', // Italian for sample word + 'custom_value4' => 'test@esempio.it', + 'address1' => 'Via Esempio 123', + 'address2' => '2º Piano, Ufficio 45', + 'city' => 'Roma', + 'state' => 'Lazio', + 'postal_code' => '00187', + 'country_id' => '380', // Italy + 'shipping_address1' => 'Via Esempio 123', + 'shipping_address2' => '2º Piano, Ufficio 45', + 'shipping_city' => 'Roma', + 'shipping_state' => 'Lazio', + 'shipping_postal_code' => '00187', + 'shipping_country_id' => '380', // Italy + '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', + ]); + + $c2 = + Client::create([ + 'company_id' => $company->id, + 'user_id' => $this->user->id, + 'name' => 'Impresa Esempio S.p.A.', + 'website' => 'https://www.impresa-esempio.it', + 'private_notes' => 'Queste sono note private per il cliente di prova.', + 'balance' => 0, + 'paid_to_date' => 0, + 'vat_number' => 'RSSMRA85M01H501Z', // Italian VAT number with IT prefix + 'id_number' => 'B12345678', // Typical format for Italian company registration numbers + 'custom_value1' => '2024-07-22 10:00:00', + 'custom_value2' => 'blu', // Italian for blue + 'custom_value3' => 'parolaesempio', // Italian for sample word + 'custom_value4' => 'test@esempio.it', + 'address1' => 'Via Esempio 123', + 'address2' => '2º Piano, Ufficio 45', + 'city' => 'Roma', + 'state' => 'Lazio', + 'postal_code' => '00187', + 'country_id' => '380', // Italy + 'shipping_address1' => 'Via Esempio 123', + 'shipping_address2' => '2º Piano, Ufficio 45', + 'shipping_city' => 'Roma', + 'shipping_state' => 'Lazio', + 'shipping_postal_code' => '00187', + 'shipping_country_id' => '380', // Italy + 'settings' => ClientSettings::defaults(), + 'client_hash' => \Illuminate\Support\Str::random(32), + 'routing_id' => 'SCSCSCS', + 'classification' => 'individual', + ]); + + + ClientContact::factory()->create([ + 'company_id' => $company->id, + 'user_id' => $this->user->id, + 'client_id' => $c2->id, + 'first_name' => 'Contact First', + 'last_name' => 'Contact Last', + 'email' => 'david+c2@invoiceninja.com', + ]); + + + $item = new InvoiceItem(); + $item->product_key = "Product Key"; + $item->notes = "Product Description"; + $item->cost = 10; + $item->quantity = 10; + $item->tax_rate1 = 22; + $item->tax_name1 = 'IVA'; + + $invoice = Invoice::factory()->create([ + 'company_id' => $company->id, + 'user_id' => $this->user->id, + 'client_id' => $business ? $c->id : $c2->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; + + } + private function createESData() { $this->routing_id = 293098; @@ -468,7 +633,7 @@ $x = ' 'shipping_country_id' => '724', // Spain 'settings' => ClientSettings::Defaults(), 'client_hash' => \Illuminate\Support\Str::random(32), - 'routing_id' => '', + 'routing_id' => 'SCSCSC', ]); $item = new InvoiceItem(); @@ -726,7 +891,7 @@ $x = ' } - public function testAtGovernmentRules() + public function PestAtGovernmentRules() { $this->routing_id = 293801; @@ -758,6 +923,65 @@ $x = ' } + public function testItRules() + { + $invoice = $this->createITData(); + + $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); + + + //test individual sending + + nlog("Individual"); + +$invoice = $this->createITData(false); + +$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(); + +$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 PestAtRules() { $this->routing_id = 293801; @@ -790,8 +1014,7 @@ $x = ' } - - public function RestFrRules() + public function PtestFrRules() { $invoice = $this->createFRData(); @@ -822,7 +1045,7 @@ $x = ' } - public function RtestEsRules() + public function PtestEsRules() { $invoice = $this->createESData(); From aed30cb572cca1ccedffea8a5a74b88b88879ae1 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 19 Aug 2024 14:06:27 +1000 Subject: [PATCH 4/6] Peppol --- app/Services/EDocument/Standards/Peppol.php | 113 +++++++---- .../EDocument/Standards/Peppol/RO.php | 149 ++++++++++++++ .../Einvoice/Storecove/StorecoveTest.php | 184 ++++++++++++++++-- 3 files changed, 391 insertions(+), 55 deletions(-) create mode 100644 app/Services/EDocument/Standards/Peppol/RO.php diff --git a/app/Services/EDocument/Standards/Peppol.php b/app/Services/EDocument/Standards/Peppol.php index 6afe2024807a..b797e58eaef0 100644 --- a/app/Services/EDocument/Standards/Peppol.php +++ b/app/Services/EDocument/Standards/Peppol.php @@ -19,6 +19,7 @@ use App\Helpers\Invoice\InvoiceSum; use InvoiceNinja\EInvoice\EInvoice; use App\Utils\Traits\NumberFormatter; use App\Helpers\Invoice\InvoiceSumInclusive; +use App\Services\EDocument\Standards\Peppol\RO; use InvoiceNinja\EInvoice\Models\Peppol\PaymentMeans; use InvoiceNinja\EInvoice\Models\Peppol\ItemType\Item; 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\FinancialAccountType\PayeeFinancialAccount; use InvoiceNinja\EInvoice\Models\Peppol\IdentifierType\CustomerAssignedAccountID; +use InvoiceNinja\EInvoice\Models\Peppol\LocationType\PhysicalLocation; class Peppol extends AbstractService { @@ -112,8 +114,8 @@ class Peppol extends AbstractService 'HR' => 'VAT', 'HU' => 'VAT', 'IE' => 'VAT', - 'IT' => 'IVA', //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.' + '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.' Cannot test currently 'LT' => 'VAT', 'LU' => 'VAT', 'LV' => 'VAT', @@ -732,7 +734,9 @@ class Peppol extends AbstractService 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){ "business" => $code = "B", @@ -741,18 +745,18 @@ class Peppol extends AbstractService default => $code = false, }; - if(count($rules) > 1){ + //single array + if(is_array($rules) && !is_array($rules[0])) + return $rules[2]; - foreach($rules as $rule) - { - if(stripos($rule[0], $code) !== false) { - return $rule[2]; - } + foreach($rules as $rule) + { + if(stripos($rule[0], $code) !== false) { + return $rule[2]; } } return false; - } private function getAccountingCustomerParty(): AccountingCustomerParty @@ -796,7 +800,11 @@ class Peppol extends AbstractService $address->Country = $country; $party->PostalAddress = $address; - $party->PhysicalLocation = $address; + + $physical_location = new PhysicalLocation(); + $physical_location->Address = $address; + + $party->PhysicalLocation = $physical_location;; $contact = new Contact(); $contact->ElectronicMail = $this->invoice->client->present()->email(); @@ -935,7 +943,16 @@ class Peppol extends AbstractService return null; } + + 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 * @@ -1105,12 +1122,20 @@ class Peppol extends AbstractService private function setEmailRouting(string $email): self { + nlog($email); + $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; } @@ -1125,8 +1150,9 @@ class Peppol extends AbstractService */ 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; } @@ -1324,24 +1350,26 @@ class Peppol extends AbstractService // IT Sender, IT Receiver, B2B/B2G // 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') { - nlog("italian business/government receiver"); + $this->setStorecoveMeta($this->buildRouting([ ["scheme" => 'IT:IVA', "id" => $this->invoice->client->vat_number], ["scheme" => 'IT:CUUO', "id" => $this->invoice->client->routing_id] ])); + return $this; } // IT Sender, IT Receiver, B2C // 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') { - nlog("business receiver"); - + $this->setStorecoveMeta($this->buildRouting([ ["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; } @@ -1429,27 +1457,34 @@ class Peppol extends AbstractService 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 + ], + ], + ]]; + + $this->setStorecoveMeta($meta); + + $this->setStorecoveMeta($this->buildRouting([ + ["scheme" => 'RO:VAT', "id" => $this->invoice->client->vat_number], + ])); - // "routing": { - // "eIdentifiers": [ - // { - // "scheme": "RO:VAT", - // "id": "RO010101010" - // } - // ], - // "networks": [ - // { - // "application": "ro-anaf", - // "settings": { - // "enabled": true - // } - // } - // ] - // } - // Note this will only work if your LegalEntity has been setup for this network. - // 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! - // The city field for county RO-B must be SECTOR1 - SECTOR6. + $ro = new RO($this->invoice); + + $client_state = $this->getClientSetting('Invoice.AccountingSupplierParty.Party.PostalAddress.Address.CountrySubentity'); + $client_city = $this->getClientSetting('Invoice.AccountingCustomerParty.Party.PostalAddress.Address.CityName'); + + $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; + $this->p_invoice->AccountingCustomerParty->Party->PhysicalLocation->Address->CountrySubentity = $resolved_state; + $this->p_invoice->AccountingCustomerParty->Party->PhysicalLocation->Address->CityName = $resolved_city; return $this; } diff --git a/app/Services/EDocument/Standards/Peppol/RO.php b/app/Services/EDocument/Standards/Peppol/RO.php new file mode 100644 index 000000000000..936fc413e0ad --- /dev/null +++ b/app/Services/EDocument/Standards/Peppol/RO.php @@ -0,0 +1,149 @@ + '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; + } + +} \ No newline at end of file diff --git a/tests/Integration/Einvoice/Storecove/StorecoveTest.php b/tests/Integration/Einvoice/Storecove/StorecoveTest.php index 36bcf1bb4fde..32c373d70647 100644 --- a/tests/Integration/Einvoice/Storecove/StorecoveTest.php +++ b/tests/Integration/Einvoice/Storecove/StorecoveTest.php @@ -891,6 +891,158 @@ $x = ' } + 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() { $this->routing_id = 293801; @@ -923,7 +1075,7 @@ $x = ' } - public function testItRules() + public function PtestItRules() { $invoice = $this->createITData(); @@ -956,28 +1108,28 @@ $x = ' 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"}}}]}}'); -foreach($stub as $key => $value) { - $e_invoice->{$key} = $value; -} + $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(); + $invoice->e_invoice = $e_invoice; + $invoice->save(); -$p = new Peppol($invoice); + $p = new Peppol($invoice); -$p->run(); -$xml = $p->toXml(); -nlog($xml); + $p->run(); + $xml = $p->toXml(); + nlog($xml); -$identifiers = $p->getStorecoveMeta(); + $identifiers = $p->getStorecoveMeta(); -$sc = new \App\Services\EDocument\Gateway\Storecove\Storecove(); -$sc->sendDocument($xml, $this->routing_id, $identifiers); + $sc = new \App\Services\EDocument\Gateway\Storecove\Storecove(); + $sc->sendDocument($xml, $this->routing_id, $identifiers); } From 609d464ac7d667e59337a734f6565b9f1c91e09c Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 19 Aug 2024 19:17:58 +1000 Subject: [PATCH 5/6] minor fixes --- app/PaymentDrivers/BTCPayPaymentDriver.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/app/PaymentDrivers/BTCPayPaymentDriver.php b/app/PaymentDrivers/BTCPayPaymentDriver.php index b0cd695155b6..4c93c9842c83 100644 --- a/app/PaymentDrivers/BTCPayPaymentDriver.php +++ b/app/PaymentDrivers/BTCPayPaymentDriver.php @@ -90,6 +90,8 @@ class BTCPayPaymentDriver extends BaseDriver public function processWebhookRequest() { + sleep(2); + $webhook_payload = file_get_contents('php://input'); /** @var \stdClass $btcpayRep */ @@ -128,11 +130,15 @@ class BTCPayPaymentDriver extends BaseDriver } $this->setPaymentMethod(GatewayType::CRYPTO); - $this->payment_hash = PaymentHash::whereRaw('BINARY `hash`= ?', [$btcpayRep->metadata->InvoiceNinjaPaymentHash])->firstOrFail(); + $this->payment_hash = PaymentHash::where('hash', $btcpayRep->metadata->InvoiceNinjaPaymentHash)->firstOrFail(); + $StatusId = Payment::STATUS_PENDING; + if ($this->payment_hash->payment_id == null) { - $_invoice = Invoice::with('client')->withTrashed()->find($this->payment_hash->fee_invoice_id); + $_invoice = $this->payment_hash->fee_invoice; + + // Invoice::with('client')->withTrashed()->find($this->payment_hash->fee_invoice_id); $this->client = $_invoice->client; @@ -144,6 +150,7 @@ class BTCPayPaymentDriver extends BaseDriver 'transaction_reference' => $btcpayRep->invoiceId ]; $payment = $this->createPayment($dataPayment, $StatusId); + } else { /** @var \App\Models\Payment $payment */ $payment = Payment::withTrashed()->find($this->payment_hash->payment_id); From 0615ba25edc2d352faa4c648ea18ea62f5fd4d69 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 20 Aug 2024 11:53:10 +1000 Subject: [PATCH 6/6] Fixes for calculate taxes - edge case with Recurring Invoice --- app/DataMapper/Tax/BaseRule.php | 4 + composer.json | 5 +- composer.lock | 395 +++++++++--------- .../forte-credit-card-payment-d2571506.js | 9 - public/build/manifest.json | 2 +- 5 files changed, 205 insertions(+), 210 deletions(-) delete mode 100644 public/build/assets/forte-credit-card-payment-d2571506.js diff --git a/app/DataMapper/Tax/BaseRule.php b/app/DataMapper/Tax/BaseRule.php index 016a38840db9..cecf5fd3a83a 100644 --- a/app/DataMapper/Tax/BaseRule.php +++ b/app/DataMapper/Tax/BaseRule.php @@ -17,6 +17,7 @@ use App\Models\Invoice; use App\Models\Product; use App\DataProviders\USStates; use App\DataMapper\Tax\ZipTax\Response; +use App\Models\RecurringInvoice; class BaseRule implements RuleInterface { @@ -403,6 +404,9 @@ class BaseRule implements RuleInterface { $lock_invoices = $this->client->getSetting('lock_invoices'); + if($this->invoice instanceof RecurringInvoice) + return true; + switch ($lock_invoices) { case 'off': return true; diff --git a/composer.json b/composer.json index cba4ad290b11..611eb3c9cd12 100644 --- a/composer.json +++ b/composer.json @@ -130,8 +130,7 @@ "app/Helpers/Generic.php", "app/Helpers/ClientPortal.php" ], - "classmap": [ - ] + "classmap": [] }, "autoload-dev": { "psr-4": { @@ -202,4 +201,4 @@ ], "minimum-stability": "dev", "prefer-stable": true -} +} \ No newline at end of file diff --git a/composer.lock b/composer.lock index 4fb0ae985936..6f1ecb0217d9 100644 --- a/composer.lock +++ b/composer.lock @@ -535,16 +535,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.319.0", + "version": "3.320.1", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "a5c408d4cd1945d5fc817f45e46383634b610497" + "reference": "653549ab0e274747a46a96fd375df642704f21e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/a5c408d4cd1945d5fc817f45e46383634b610497", - "reference": "a5c408d4cd1945d5fc817f45e46383634b610497", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/653549ab0e274747a46a96fd375df642704f21e2", + "reference": "653549ab0e274747a46a96fd375df642704f21e2", "shasum": "" }, "require": { @@ -627,9 +627,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.319.0" + "source": "https://github.com/aws/aws-sdk-php/tree/3.320.1" }, - "time": "2024-08-07T18:05:51+00:00" + "time": "2024-08-15T18:07:13+00:00" }, { "name": "bacon/bacon-qr-code", @@ -1119,23 +1119,23 @@ }, { "name": "dasprid/enum", - "version": "1.0.5", + "version": "1.0.6", "source": { "type": "git", "url": "https://github.com/DASPRiD/Enum.git", - "reference": "6faf451159fb8ba4126b925ed2d78acfce0dc016" + "reference": "8dfd07c6d2cf31c8da90c53b83c026c7696dda90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/DASPRiD/Enum/zipball/6faf451159fb8ba4126b925ed2d78acfce0dc016", - "reference": "6faf451159fb8ba4126b925ed2d78acfce0dc016", + "url": "https://api.github.com/repos/DASPRiD/Enum/zipball/8dfd07c6d2cf31c8da90c53b83c026c7696dda90", + "reference": "8dfd07c6d2cf31c8da90c53b83c026c7696dda90", "shasum": "" }, "require": { "php": ">=7.1 <9.0" }, "require-dev": { - "phpunit/phpunit": "^7 | ^8 | ^9", + "phpunit/phpunit": "^7 || ^8 || ^9 || ^10 || ^11", "squizlabs/php_codesniffer": "*" }, "type": "library", @@ -1163,9 +1163,9 @@ ], "support": { "issues": "https://github.com/DASPRiD/Enum/issues", - "source": "https://github.com/DASPRiD/Enum/tree/1.0.5" + "source": "https://github.com/DASPRiD/Enum/tree/1.0.6" }, - "time": "2023-08-25T16:18:39+00:00" + "time": "2024-08-09T14:30:48+00:00" }, { "name": "dflydev/apache-mime-types", @@ -1303,16 +1303,16 @@ }, { "name": "doctrine/dbal", - "version": "4.0.4", + "version": "4.1.0", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "50fda19f80724b55ff770bb4ff352407008e63c5" + "reference": "2377cd41609aa51bee822c8d207317a3f363a558" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/50fda19f80724b55ff770bb4ff352407008e63c5", - "reference": "50fda19f80724b55ff770bb4ff352407008e63c5", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/2377cd41609aa51bee822c8d207317a3f363a558", + "reference": "2377cd41609aa51bee822c8d207317a3f363a558", "shasum": "" }, "require": { @@ -1325,13 +1325,13 @@ "doctrine/coding-standard": "12.0.0", "fig/log-test": "^1", "jetbrains/phpstorm-stubs": "2023.2", - "phpstan/phpstan": "1.11.5", + "phpstan/phpstan": "1.11.7", "phpstan/phpstan-phpunit": "1.4.0", "phpstan/phpstan-strict-rules": "^1.6", - "phpunit/phpunit": "10.5.22", + "phpunit/phpunit": "10.5.28", "psalm/plugin-phpunit": "0.19.0", "slevomat/coding-standard": "8.13.1", - "squizlabs/php_codesniffer": "3.10.1", + "squizlabs/php_codesniffer": "3.10.2", "symfony/cache": "^6.3.8|^7.0", "symfony/console": "^5.4|^6.3|^7.0", "vimeo/psalm": "5.24.0" @@ -1391,7 +1391,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/4.0.4" + "source": "https://github.com/doctrine/dbal/tree/4.1.0" }, "funding": [ { @@ -1407,7 +1407,7 @@ "type": "tidelift" } ], - "time": "2024-06-19T11:57:23+00:00" + "time": "2024-08-15T07:37:07+00:00" }, { "name": "doctrine/deprecations", @@ -2522,7 +2522,7 @@ }, { "name": "google/apiclient-services", - "version": "v0.367.0", + "version": "v0.368.0", "source": { "type": "git", "url": "https://github.com/googleapis/google-api-php-client-services.git", @@ -2560,7 +2560,7 @@ ], "support": { "issues": "https://github.com/googleapis/google-api-php-client-services/issues", - "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.367.0" + "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.368.0" }, "time": "2024-07-11T01:08:44+00:00" }, @@ -4489,16 +4489,16 @@ }, { "name": "laravel/framework", - "version": "v11.19.0", + "version": "v11.20.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "5e103d499e9ee5bcfc184412d034c4e516b87085" + "reference": "3cd7593dd9b67002fc416b46616f4d4d1da3e571" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/5e103d499e9ee5bcfc184412d034c4e516b87085", - "reference": "5e103d499e9ee5bcfc184412d034c4e516b87085", + "url": "https://api.github.com/repos/laravel/framework/zipball/3cd7593dd9b67002fc416b46616f4d4d1da3e571", + "reference": "3cd7593dd9b67002fc416b46616f4d4d1da3e571", "shasum": "" }, "require": { @@ -4691,20 +4691,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2024-07-30T15:22:41+00:00" + "time": "2024-08-06T14:39:21+00:00" }, { "name": "laravel/pint", - "version": "v1.17.1", + "version": "v1.17.2", "source": { "type": "git", "url": "https://github.com/laravel/pint.git", - "reference": "b5b6f716db298671c1dfea5b1082ec2c0ae7064f" + "reference": "e8a88130a25e3f9d4d5785e6a1afca98268ab110" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pint/zipball/b5b6f716db298671c1dfea5b1082ec2c0ae7064f", - "reference": "b5b6f716db298671c1dfea5b1082ec2c0ae7064f", + "url": "https://api.github.com/repos/laravel/pint/zipball/e8a88130a25e3f9d4d5785e6a1afca98268ab110", + "reference": "e8a88130a25e3f9d4d5785e6a1afca98268ab110", "shasum": "" }, "require": { @@ -4715,13 +4715,13 @@ "php": "^8.1.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.59.3", - "illuminate/view": "^10.48.12", - "larastan/larastan": "^2.9.7", + "friendsofphp/php-cs-fixer": "^3.61.1", + "illuminate/view": "^10.48.18", + "larastan/larastan": "^2.9.8", "laravel-zero/framework": "^10.4.0", "mockery/mockery": "^1.6.12", "nunomaduro/termwind": "^1.15.1", - "pestphp/pest": "^2.34.8" + "pestphp/pest": "^2.35.0" }, "bin": [ "builds/pint" @@ -4757,7 +4757,7 @@ "issues": "https://github.com/laravel/pint/issues", "source": "https://github.com/laravel/pint" }, - "time": "2024-08-01T09:06:33+00:00" + "time": "2024-08-06T15:11:54+00:00" }, { "name": "laravel/prompts", @@ -4819,26 +4819,27 @@ }, { "name": "laravel/serializable-closure", - "version": "v1.3.3", + "version": "v1.3.4", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "3dbf8a8e914634c48d389c1234552666b3d43754" + "reference": "61b87392d986dc49ad5ef64e75b1ff5fee24ef81" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/3dbf8a8e914634c48d389c1234552666b3d43754", - "reference": "3dbf8a8e914634c48d389c1234552666b3d43754", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/61b87392d986dc49ad5ef64e75b1ff5fee24ef81", + "reference": "61b87392d986dc49ad5ef64e75b1ff5fee24ef81", "shasum": "" }, "require": { "php": "^7.3|^8.0" }, "require-dev": { - "nesbot/carbon": "^2.61", + "illuminate/support": "^8.0|^9.0|^10.0|^11.0", + "nesbot/carbon": "^2.61|^3.0", "pestphp/pest": "^1.21.3", "phpstan/phpstan": "^1.8.2", - "symfony/var-dumper": "^5.4.11" + "symfony/var-dumper": "^5.4.11|^6.2.0|^7.0.0" }, "type": "library", "extra": { @@ -4875,7 +4876,7 @@ "issues": "https://github.com/laravel/serializable-closure/issues", "source": "https://github.com/laravel/serializable-closure" }, - "time": "2023-11-08T14:08:06+00:00" + "time": "2024-08-02T07:48:17+00:00" }, { "name": "laravel/slack-notification-channel", @@ -5282,16 +5283,16 @@ }, { "name": "league/commonmark", - "version": "2.5.1", + "version": "2.5.2", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "ac815920de0eff6de947eac0a6a94e5ed0fb147c" + "reference": "df09d5b6a4188f8f3c3ab2e43a109076a5eeb767" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/ac815920de0eff6de947eac0a6a94e5ed0fb147c", - "reference": "ac815920de0eff6de947eac0a6a94e5ed0fb147c", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/df09d5b6a4188f8f3c3ab2e43a109076a5eeb767", + "reference": "df09d5b6a4188f8f3c3ab2e43a109076a5eeb767", "shasum": "" }, "require": { @@ -5384,7 +5385,7 @@ "type": "tidelift" } ], - "time": "2024-07-24T12:52:09+00:00" + "time": "2024-08-14T10:56:57+00:00" }, { "name": "league/config", @@ -7063,20 +7064,20 @@ }, { "name": "nette/utils", - "version": "v4.0.4", + "version": "v4.0.5", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "d3ad0aa3b9f934602cb3e3902ebccf10be34d218" + "reference": "736c567e257dbe0fcf6ce81b4d6dbe05c6899f96" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/d3ad0aa3b9f934602cb3e3902ebccf10be34d218", - "reference": "d3ad0aa3b9f934602cb3e3902ebccf10be34d218", + "url": "https://api.github.com/repos/nette/utils/zipball/736c567e257dbe0fcf6ce81b4d6dbe05c6899f96", + "reference": "736c567e257dbe0fcf6ce81b4d6dbe05c6899f96", "shasum": "" }, "require": { - "php": ">=8.0 <8.4" + "php": "8.0 - 8.4" }, "conflict": { "nette/finder": "<3", @@ -7143,9 +7144,9 @@ ], "support": { "issues": "https://github.com/nette/utils/issues", - "source": "https://github.com/nette/utils/tree/v4.0.4" + "source": "https://github.com/nette/utils/tree/v4.0.5" }, - "time": "2024-01-17T16:50:36+00:00" + "time": "2024-08-07T15:39:19+00:00" }, { "name": "nikic/php-parser", @@ -8219,16 +8220,16 @@ }, { "name": "phpseclib/phpseclib", - "version": "3.0.39", + "version": "3.0.41", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "211ebc399c6e73c225a018435fe5ae209d1d1485" + "reference": "621c73f7dcb310b61de34d1da4c4204e8ace6ceb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/211ebc399c6e73c225a018435fe5ae209d1d1485", - "reference": "211ebc399c6e73c225a018435fe5ae209d1d1485", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/621c73f7dcb310b61de34d1da4c4204e8ace6ceb", + "reference": "621c73f7dcb310b61de34d1da4c4204e8ace6ceb", "shasum": "" }, "require": { @@ -8309,7 +8310,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/3.0.39" + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.41" }, "funding": [ { @@ -8325,7 +8326,7 @@ "type": "tidelift" } ], - "time": "2024-06-24T06:27:33+00:00" + "time": "2024-08-12T00:13:54+00:00" }, { "name": "phpstan/phpdoc-parser", @@ -9661,16 +9662,16 @@ }, { "name": "sentry/sentry", - "version": "4.8.1", + "version": "4.9.0", "source": { "type": "git", "url": "https://github.com/getsentry/sentry-php.git", - "reference": "61770efd8b7888e0bdd7d234f0ba67b066e47d04" + "reference": "788ec170f51ebb22f2809a1e3f78b19ccd39b70d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/61770efd8b7888e0bdd7d234f0ba67b066e47d04", - "reference": "61770efd8b7888e0bdd7d234f0ba67b066e47d04", + "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/788ec170f51ebb22f2809a1e3f78b19ccd39b70d", + "reference": "788ec170f51ebb22f2809a1e3f78b19ccd39b70d", "shasum": "" }, "require": { @@ -9734,7 +9735,7 @@ ], "support": { "issues": "https://github.com/getsentry/sentry-php/issues", - "source": "https://github.com/getsentry/sentry-php/tree/4.8.1" + "source": "https://github.com/getsentry/sentry-php/tree/4.9.0" }, "funding": [ { @@ -9746,27 +9747,27 @@ "type": "custom" } ], - "time": "2024-07-16T13:45:27+00:00" + "time": "2024-08-08T14:40:50+00:00" }, { "name": "sentry/sentry-laravel", - "version": "4.7.1", + "version": "4.8.0", "source": { "type": "git", "url": "https://github.com/getsentry/sentry-laravel.git", - "reference": "d70415f19f35806acee5bcbc7403e9cb8fb5252c" + "reference": "2bbcb7e81097993cf64d5b296eaa6d396cddd5a7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/getsentry/sentry-laravel/zipball/d70415f19f35806acee5bcbc7403e9cb8fb5252c", - "reference": "d70415f19f35806acee5bcbc7403e9cb8fb5252c", + "url": "https://api.github.com/repos/getsentry/sentry-laravel/zipball/2bbcb7e81097993cf64d5b296eaa6d396cddd5a7", + "reference": "2bbcb7e81097993cf64d5b296eaa6d396cddd5a7", "shasum": "" }, "require": { "illuminate/support": "^6.0 | ^7.0 | ^8.0 | ^9.0 | ^10.0 | ^11.0", "nyholm/psr7": "^1.0", "php": "^7.2 | ^8.0", - "sentry/sentry": "^4.7", + "sentry/sentry": "^4.9", "symfony/psr-http-message-bridge": "^1.0 | ^2.0 | ^6.0 | ^7.0" }, "require-dev": { @@ -9823,7 +9824,7 @@ ], "support": { "issues": "https://github.com/getsentry/sentry-laravel/issues", - "source": "https://github.com/getsentry/sentry-laravel/tree/4.7.1" + "source": "https://github.com/getsentry/sentry-laravel/tree/4.8.0" }, "funding": [ { @@ -9835,7 +9836,7 @@ "type": "custom" } ], - "time": "2024-07-17T13:27:43+00:00" + "time": "2024-08-15T19:03:01+00:00" }, { "name": "setasign/fpdf", @@ -12505,6 +12506,82 @@ ], "time": "2024-05-31T15:07:36+00:00" }, + { + "name": "symfony/polyfill-php81", + "version": "v1.30.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "3fb075789fb91f9ad9af537c4012d523085bd5af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/3fb075789fb91f9ad9af537c4012d523085bd5af", + "reference": "3fb075789fb91f9ad9af537c4012d523085bd5af", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.30.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-06-19T12:30:46+00:00" + }, { "name": "symfony/polyfill-php83", "version": "v1.30.0", @@ -14079,16 +14156,16 @@ }, { "name": "twig/intl-extra", - "version": "v3.10.0", + "version": "v3.11.0", "source": { "type": "git", "url": "https://github.com/twigphp/intl-extra.git", - "reference": "693f6beb8ca91fc6323e01b3addf983812f65c93" + "reference": "e9cadd61342e71e45b2f4f0558122433fd7e4566" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/intl-extra/zipball/693f6beb8ca91fc6323e01b3addf983812f65c93", - "reference": "693f6beb8ca91fc6323e01b3addf983812f65c93", + "url": "https://api.github.com/repos/twigphp/intl-extra/zipball/e9cadd61342e71e45b2f4f0558122433fd7e4566", + "reference": "e9cadd61342e71e45b2f4f0558122433fd7e4566", "shasum": "" }, "require": { @@ -14127,7 +14204,7 @@ "twig" ], "support": { - "source": "https://github.com/twigphp/intl-extra/tree/v3.10.0" + "source": "https://github.com/twigphp/intl-extra/tree/v3.11.0" }, "funding": [ { @@ -14139,20 +14216,20 @@ "type": "tidelift" } ], - "time": "2024-05-11T07:35:57+00:00" + "time": "2024-06-21T06:25:01+00:00" }, { "name": "twig/twig", - "version": "v3.10.3", + "version": "v3.11.0", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "67f29781ffafa520b0bbfbd8384674b42db04572" + "reference": "e80fb8ebba85c7341a97a9ebf825d7fd4b77708d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/67f29781ffafa520b0bbfbd8384674b42db04572", - "reference": "67f29781ffafa520b0bbfbd8384674b42db04572", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/e80fb8ebba85c7341a97a9ebf825d7fd4b77708d", + "reference": "e80fb8ebba85c7341a97a9ebf825d7fd4b77708d", "shasum": "" }, "require": { @@ -14160,7 +14237,8 @@ "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-ctype": "^1.8", "symfony/polyfill-mbstring": "^1.3", - "symfony/polyfill-php80": "^1.22" + "symfony/polyfill-php80": "^1.22", + "symfony/polyfill-php81": "^1.29" }, "require-dev": { "psr/container": "^1.0|^2.0", @@ -14206,7 +14284,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.10.3" + "source": "https://github.com/twigphp/Twig/tree/v3.11.0" }, "funding": [ { @@ -14218,7 +14296,7 @@ "type": "tidelift" } ], - "time": "2024-05-16T10:04:27+00:00" + "time": "2024-08-08T16:15:16+00:00" }, { "name": "twilio/sdk", @@ -15453,16 +15531,16 @@ }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.61.1", + "version": "v3.62.0", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "94a87189f55814e6cabca2d9a33b06de384a2ab8" + "reference": "627692f794d35c43483f34b01d94740df2a73507" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/94a87189f55814e6cabca2d9a33b06de384a2ab8", - "reference": "94a87189f55814e6cabca2d9a33b06de384a2ab8", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/627692f794d35c43483f34b01d94740df2a73507", + "reference": "627692f794d35c43483f34b01d94740df2a73507", "shasum": "" }, "require": { @@ -15544,7 +15622,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.61.1" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.62.0" }, "funding": [ { @@ -15552,7 +15630,7 @@ "type": "github" } ], - "time": "2024-07-31T14:33:15+00:00" + "time": "2024-08-07T17:03:09+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -16134,16 +16212,16 @@ }, { "name": "phpmyadmin/sql-parser", - "version": "5.9.0", + "version": "5.9.1", "source": { "type": "git", "url": "https://github.com/phpmyadmin/sql-parser.git", - "reference": "011fa18a4e55591fac6545a821921dd1d61c6984" + "reference": "169a9f11f1957ea36607c9b29eac1b48679f1ecc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpmyadmin/sql-parser/zipball/011fa18a4e55591fac6545a821921dd1d61c6984", - "reference": "011fa18a4e55591fac6545a821921dd1d61c6984", + "url": "https://api.github.com/repos/phpmyadmin/sql-parser/zipball/169a9f11f1957ea36607c9b29eac1b48679f1ecc", + "reference": "169a9f11f1957ea36607c9b29eac1b48679f1ecc", "shasum": "" }, "require": { @@ -16161,8 +16239,7 @@ "phpstan/extension-installer": "^1.1", "phpstan/phpstan": "^1.9.12", "phpstan/phpstan-phpunit": "^1.3.3", - "phpunit/php-code-coverage": "*", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "phpunit/phpunit": "^8.5 || ^9.6", "psalm/plugin-phpunit": "^0.16.1", "vimeo/psalm": "^4.11", "zumba/json-serializer": "~3.0.2" @@ -16218,20 +16295,20 @@ "type": "other" } ], - "time": "2024-01-20T20:34:02+00:00" + "time": "2024-08-13T19:01:01+00:00" }, { "name": "phpstan/phpstan", - "version": "1.11.9", + "version": "1.11.10", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "e370bcddadaede0c1716338b262346f40d296f82" + "reference": "640410b32995914bde3eed26fa89552f9c2c082f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e370bcddadaede0c1716338b262346f40d296f82", - "reference": "e370bcddadaede0c1716338b262346f40d296f82", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/640410b32995914bde3eed26fa89552f9c2c082f", + "reference": "640410b32995914bde3eed26fa89552f9c2c082f", "shasum": "" }, "require": { @@ -16276,7 +16353,7 @@ "type": "github" } ], - "time": "2024-08-01T16:25:18+00:00" + "time": "2024-08-08T09:02:50+00:00" }, { "name": "phpunit/php-code-coverage", @@ -16601,16 +16678,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.5.29", + "version": "10.5.30", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "8e9e80872b4e8064401788ee8a32d40b4455318f" + "reference": "b15524febac0153876b4ba9aab3326c2ee94c897" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/8e9e80872b4e8064401788ee8a32d40b4455318f", - "reference": "8e9e80872b4e8064401788ee8a32d40b4455318f", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b15524febac0153876b4ba9aab3326c2ee94c897", + "reference": "b15524febac0153876b4ba9aab3326c2ee94c897", "shasum": "" }, "require": { @@ -16631,7 +16708,7 @@ "phpunit/php-timer": "^6.0.0", "sebastian/cli-parser": "^2.0.1", "sebastian/code-unit": "^2.0.0", - "sebastian/comparator": "^5.0.1", + "sebastian/comparator": "^5.0.2", "sebastian/diff": "^5.1.1", "sebastian/environment": "^6.1.0", "sebastian/exporter": "^5.1.2", @@ -16682,7 +16759,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.29" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.30" }, "funding": [ { @@ -16698,7 +16775,7 @@ "type": "tidelift" } ], - "time": "2024-07-30T11:08:00+00:00" + "time": "2024-08-13T06:09:37+00:00" }, { "name": "react/cache", @@ -17400,16 +17477,16 @@ }, { "name": "sebastian/comparator", - "version": "5.0.1", + "version": "5.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "2db5010a484d53ebf536087a70b4a5423c102372" + "reference": "2d3e04c3b4c1e84a5e7382221ad8883c8fbc4f53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2db5010a484d53ebf536087a70b4a5423c102372", - "reference": "2db5010a484d53ebf536087a70b4a5423c102372", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2d3e04c3b4c1e84a5e7382221ad8883c8fbc4f53", + "reference": "2d3e04c3b4c1e84a5e7382221ad8883c8fbc4f53", "shasum": "" }, "require": { @@ -17420,7 +17497,7 @@ "sebastian/exporter": "^5.0" }, "require-dev": { - "phpunit/phpunit": "^10.3" + "phpunit/phpunit": "^10.4" }, "type": "library", "extra": { @@ -17465,7 +17542,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.1" + "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.2" }, "funding": [ { @@ -17473,7 +17550,7 @@ "type": "github" } ], - "time": "2023-08-14T13:18:12+00:00" + "time": "2024-08-12T06:03:08+00:00" }, { "name": "sebastian/complexity", @@ -18588,82 +18665,6 @@ }, "time": "2024-07-21T01:46:03+00:00" }, - { - "name": "symfony/polyfill-php81", - "version": "v1.30.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "3fb075789fb91f9ad9af537c4012d523085bd5af" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/3fb075789fb91f9ad9af537c4012d523085bd5af", - "reference": "3fb075789fb91f9ad9af537c4012d523085bd5af", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php81\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.30.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-06-19T12:30:46+00:00" - }, { "name": "symfony/stopwatch", "version": "v7.1.1", diff --git a/public/build/assets/forte-credit-card-payment-d2571506.js b/public/build/assets/forte-credit-card-payment-d2571506.js deleted file mode 100644 index f83e7ebe4209..000000000000 --- a/public/build/assets/forte-credit-card-payment-d2571506.js +++ /dev/null @@ -1,9 +0,0 @@ -var r=Object.defineProperty;var l=(n,e,t)=>e in n?r(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var d=(n,e,t)=>(l(n,typeof e!="symbol"?e+"":e,t),t);/** - * 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://opensource.org/licenses/AAL - */class c{constructor(e){d(this,"handleAuthorization",()=>{var e=$("#my-card"),t={api_login_id:this.apiLoginId,card_number:e.CardJs("cardNumber").replace(/[^\d]/g,""),expire_year:e.CardJs("expiryYear").replace(/[^\d]/g,""),expire_month:e.CardJs("expiryMonth").replace(/[^\d]/g,""),cvv:document.getElementById("cvv").value.replace(/[^\d]/g,"")};return document.getElementById("pay-now")&&(document.getElementById("pay-now").disabled=!0,document.querySelector("#pay-now > svg").classList.remove("hidden"),document.querySelector("#pay-now > span").classList.add("hidden")),forte.createToken(t).success(this.successResponseHandler).error(this.failedResponseHandler),!1});d(this,"successResponseHandler",e=>{document.getElementById("payment_token").value=e.onetime_token,document.getElementById("card_brand").value=e.card_type,document.getElementById("expire_year").value=e.expire_year,document.getElementById("expire_month").value=e.expire_month,document.getElementById("last_4").value=e.last_4;let t=document.querySelector("input[name=token-billing-checkbox]:checked");return t&&(document.getElementById("store_card").value=t.value),document.getElementById("server_response").submit(),!1});d(this,"failedResponseHandler",e=>{var t='
  • '+e.response_description+"
";return document.getElementById("forte_errors").innerHTML=t,document.getElementById("pay-now").disabled=!1,document.querySelector("#pay-now > svg").classList.add("hidden"),document.querySelector("#pay-now > span").classList.remove("hidden"),!1});d(this,"handle",()=>{Array.from(document.getElementsByClassName("toggle-payment-with-token")).forEach(o=>o.addEventListener("click",a=>{document.getElementById("save-card--container").style.display="none",document.getElementById("forte--credit-card-container").style.display="none",document.getElementById("token").value=a.target.dataset.token}));let e=document.getElementById("toggle-payment-with-credit-card");e&&e.addEventListener("click",()=>{document.getElementById("save-card--container").style.display="grid",document.getElementById("forte--credit-card-container").style.display="flex",document.getElementById("token").value=null});let t=document.getElementById("pay-now");return t&&t.addEventListener("click",o=>{let a=document.getElementById("token");a.value?this.handlePayNowAction(a.value):this.handleAuthorization()}),this});this.apiLoginId=e,this.cardHolderName=document.getElementById("cardholder_name")}handlePayNowAction(e){document.getElementById("pay-now").disabled=!0,document.querySelector("#pay-now > svg").classList.remove("hidden"),document.querySelector("#pay-now > span").classList.add("hidden"),document.getElementById("token").value=e,document.getElementById("server_response").submit()}}const i=document.querySelector('meta[name="forte-api-login-id"]').content;new c(i).handle(); diff --git a/public/build/manifest.json b/public/build/manifest.json index 1d965290072b..ff5ac2012451 100644 --- a/public/build/manifest.json +++ b/public/build/manifest.json @@ -86,7 +86,7 @@ "src": "resources/js/clients/payments/forte-ach-payment.js" }, "resources/js/clients/payments/forte-credit-card-payment.js": { - "file": "assets/forte-credit-card-payment-d2571506.js", + "file": "assets/forte-credit-card-payment-7bb15431.js", "isEntry": true, "src": "resources/js/clients/payments/forte-credit-card-payment.js" },