From efeb5bec7406bf42ef32008950b835d667560735 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 20 Apr 2024 09:25:54 +1000 Subject: [PATCH 01/11] Show required fields --- app/Livewire/RequiredClientInfo.php | 65 +++++++++++++++-------------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/app/Livewire/RequiredClientInfo.php b/app/Livewire/RequiredClientInfo.php index 7514bac436..5899522a0c 100644 --- a/app/Livewire/RequiredClientInfo.php +++ b/app/Livewire/RequiredClientInfo.php @@ -377,42 +377,45 @@ $_contact->push(); public function checkFields() { - MultiDB::setDb($this->db); - $_contact = ClientContact::withTrashed()->find($this->contact_id); + + $this->show_form = true; - foreach ($this->fields as $index => $field) { - $_field = $this->mappings[$field['name']]; + // MultiDB::setDb($this->db); + // $_contact = ClientContact::withTrashed()->find($this->contact_id); - if (Str::startsWith($field['name'], 'client_')) { - if (empty($_contact->client->{$_field}) - || is_null($_contact->client->{$_field}) - // || in_array($_field, $this->client_address_array) - ) { - $this->show_form = true; - } else { - $this->fields[$index]['filled'] = true; - } - } + // foreach ($this->fields as $index => $field) { + // $_field = $this->mappings[$field['name']]; - if (Str::startsWith($field['name'], 'contact_')) { - if (empty($_contact->{$_field}) || is_null($_contact->{$_field}) || str_contains($_contact->{$_field}, '@example.com')) { - $this->show_form = true; - } else { - $this->fields[$index]['filled'] = true; - } - } - } + // if (Str::startsWith($field['name'], 'client_')) { + // if (empty($_contact->client->{$_field}) + // || is_null($_contact->client->{$_field}) + // // || in_array($_field, $this->client_address_array) + // ) { + // $this->show_form = true; + // } else { + // $this->fields[$index]['filled'] = true; + // } + // } - $left = collect($this->fields) - ->filter(fn ($field) => !array_key_exists('filled', $field)) - ->count(); + // if (Str::startsWith($field['name'], 'contact_')) { + // if (empty($_contact->{$_field}) || is_null($_contact->{$_field}) || str_contains($_contact->{$_field}, '@example.com')) { + // $this->show_form = true; + // } else { + // $this->fields[$index]['filled'] = true; + // } + // } + // } - if ($left === 0) { - $this->dispatch( - 'passed-required-fields-check', - client_postal_code: $this->contact->client->postal_code - ); - } + // $left = collect($this->fields) + // ->filter(fn ($field) => !array_key_exists('filled', $field)) + // ->count(); + + // if ($left === 0) { + // $this->dispatch( + // 'passed-required-fields-check', + // client_postal_code: $this->contact->client->postal_code + // ); + // } } public function showCopyBillingCheckbox(): bool From ecad93afffdda1a840a2cef7f2e27c9258d78a74 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 20 Apr 2024 09:26:10 +1000 Subject: [PATCH 02/11] Updated translations --- app/Livewire/RequiredClientInfo.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Livewire/RequiredClientInfo.php b/app/Livewire/RequiredClientInfo.php index 5899522a0c..909c3462d3 100644 --- a/app/Livewire/RequiredClientInfo.php +++ b/app/Livewire/RequiredClientInfo.php @@ -379,7 +379,7 @@ $_contact->push(); { $this->show_form = true; - +//@todo - need to make this optional // MultiDB::setDb($this->db); // $_contact = ClientContact::withTrashed()->find($this->contact_id); From 45f378eb9de935e0bd4cfbd17f1addd671859119 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 20 Apr 2024 10:58:29 +1000 Subject: [PATCH 03/11] Minor fixes --- .../ClientPortal/QuoteController.php | 3 +++ app/Mail/Engine/PaymentEmailEngine.php | 2 +- app/Services/EDocument/Standards/RoEInvoice.php | 17 ++++++++++++++++- app/Utils/HtmlEngine.php | 2 +- lang/en/texts.php | 2 +- 5 files changed, 22 insertions(+), 4 deletions(-) diff --git a/app/Http/Controllers/ClientPortal/QuoteController.php b/app/Http/Controllers/ClientPortal/QuoteController.php index 93dabdbdc9..52c5ccf584 100644 --- a/app/Http/Controllers/ClientPortal/QuoteController.php +++ b/app/Http/Controllers/ClientPortal/QuoteController.php @@ -178,6 +178,9 @@ class QuoteController extends Controller ->where('client_id', auth()->guard('contact')->user()->client->id) ->where('company_id', auth()->guard('contact')->user()->client->company_id) ->whereIn('status_id', [Quote::STATUS_DRAFT, Quote::STATUS_SENT]) + ->where(function ($q){ + $q->whereNull('due_date')->orWhere('due_date', '>=', now()); + }) ->withTrashed() ->get(); diff --git a/app/Mail/Engine/PaymentEmailEngine.php b/app/Mail/Engine/PaymentEmailEngine.php index ed5510dd73..32613b80f1 100644 --- a/app/Mail/Engine/PaymentEmailEngine.php +++ b/app/Mail/Engine/PaymentEmailEngine.php @@ -392,7 +392,7 @@ class PaymentEmailEngine extends BaseEmailEngine $invoice_list = '

'; foreach ($this->payment->invoices as $invoice) { - $invoice_list .= ctrans('texts.invoice_number_short')." {$invoice->number} ".Number::formatMoney($invoice->pivot->amount, $this->client).'
'; + $invoice_list .= ctrans('texts.invoice_number_short')." {$invoice->number} ".Number::formatMoney($invoice->pivot->amount, $this->client).'\n'; } return $invoice_list; diff --git a/app/Services/EDocument/Standards/RoEInvoice.php b/app/Services/EDocument/Standards/RoEInvoice.php index 9d58e0431e..553ecca6f5 100644 --- a/app/Services/EDocument/Standards/RoEInvoice.php +++ b/app/Services/EDocument/Standards/RoEInvoice.php @@ -205,6 +205,9 @@ class RoEInvoice extends AbstractService } elseif (!empty($item->tax_name3)) { $taxName = $item->tax_name3; } + else { + $taxName = ''; + } } $supplier_party = $this->createParty($company, $companyVatNr, $coEmail, $coPhone, $companyIdn, $coFullName, 'company', $taxName); @@ -238,6 +241,8 @@ class RoEInvoice extends AbstractService $taxRatePercent = $item->tax_rate2; } elseif (!empty($item->tax_rate3)) { $taxRatePercent = $item->tax_rate3; + }else { + $taxRatePercent = 0; } if (!empty($item->tax_name1)) { @@ -246,6 +251,8 @@ class RoEInvoice extends AbstractService $taxNameScheme = $item->tax_name2; } elseif (!empty($item->tax_name3)) { $taxNameScheme = $item->tax_name3; + } else { + $taxNameScheme = ''; } $invoicing_data = $this->invoice->calc(); @@ -270,7 +277,7 @@ class RoEInvoice extends AbstractService return $ubl_invoice; } - private function createParty($company, $vatNr, $eMail, $phone, $idNr, $fullName, $compType, $taxNameScheme) + private function createParty($company, $vatNr, $eMail, $phone, $idNr, $fullName, $compType, $taxNameScheme = '') { $party = new Party(); $party->setPartyIdentification(preg_replace('/^RO/', '', $vatNr)); @@ -352,7 +359,15 @@ class RoEInvoice extends AbstractService ->setId($this->resolveTaxCode($item->tax_id ?? 1)) ->setPercent($item->tax_rate3) ->setTaxScheme(((new TaxScheme())->setId(($item->tax_name3 === 'TVA') ? 'VAT' : $item->tax_name3))); + }else { + + $classifiedTaxCategory = (new ClassifiedTaxCategory()) + ->setId($this->resolveTaxCode($item->tax_id ?? 8)) + ->setPercent(0) + ->setTaxScheme(((new TaxScheme())->setId(($item->tax_name3 === 'TVA') ? 'VAT' : $item->tax_name3))); + } + $invoiceLine = (new InvoiceLine()) ->setId($index + 1) ->setInvoicedQuantity($item->quantity) diff --git a/app/Utils/HtmlEngine.php b/app/Utils/HtmlEngine.php index 1495d341f0..226f824902 100644 --- a/app/Utils/HtmlEngine.php +++ b/app/Utils/HtmlEngine.php @@ -323,7 +323,7 @@ class HtmlEngine $data['$portal_url'] = ['value' => $this->invitation->getPortalLink(), 'label' => '']; $data['$entity_number'] = &$data['$number']; - $data['$invoice.discount'] = ['value' => Number::formatMoney($this->entity_calc->getTotalDiscount(), $this->client) ?: ' ', 'label' => ($this->entity->is_amount_discount) ? ctrans('texts.discount') : ctrans('texts.discount').' '.$this->entity->discount.'%']; + $data['$invoice.discount'] = ['value' => Number::formatMoney($this->entity_calc->getTotalDiscount(), $this->client) ?: ' ', 'label' => ($this->entity->is_amount_discount) ? ctrans('texts.discount') : ctrans('texts.discount').' '.(float)$this->entity->discount.'%']; $data['$discount'] = &$data['$invoice.discount']; $data['$subtotal'] = ['value' => Number::formatMoney($this->entity_calc->getSubTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.subtotal')]; $data['$gross_subtotal'] = ['value' => Number::formatMoney($this->entity_calc->getGrossSubTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.subtotal')]; diff --git a/lang/en/texts.php b/lang/en/texts.php index 8d406b4238..e542e667e9 100644 --- a/lang/en/texts.php +++ b/lang/en/texts.php @@ -4170,7 +4170,7 @@ $lang = array( 'one_time_purchases' => 'One time purchases', 'recurring_purchases' => 'Recurring purchases', 'you_might_be_interested_in_following' => 'You might be interested in the following', - 'quotes_with_status_sent_can_be_approved' => 'Only quotes with "Sent" status can be approved.', + 'quotes_with_status_sent_can_be_approved' => 'Only quotes with "Sent" status can be approved. Expired quotes cannot be approved.', 'no_quotes_available_for_download' => 'No quotes available for download.', 'copyright' => 'Copyright', 'user_created_user' => ':user created :created_user at :time', From 8d5b8e231989bf594340603296e0844bab594369 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 22 Apr 2024 14:38:29 +1000 Subject: [PATCH 04/11] Tokenization for paypal advanced cards --- app/Models/Gateway.php | 2 + app/Models/GatewayType.php | 5 + app/PaymentDrivers/PayPal/PayPalWebhook.php | 61 ++++++++ .../PayPalRestPaymentDriver.php | 101 ++++++++++--- lang/en/texts.php | 1 + .../gateways/paypal/ppcp/card.blade.php | 134 +++++++++++++++--- 6 files changed, 259 insertions(+), 45 deletions(-) diff --git a/app/Models/Gateway.php b/app/Models/Gateway.php index 7932cb3a56..f862caf91f 100644 --- a/app/Models/Gateway.php +++ b/app/Models/Gateway.php @@ -194,6 +194,7 @@ class Gateway extends StaticModel GatewayType::PAYPAL => ['refund' => false, 'token_billing' => false], GatewayType::CREDIT_CARD => ['refund' => false, 'token_billing' => false], GatewayType::VENMO => ['refund' => false, 'token_billing' => false], + GatewayType::PAYPAL_ADVANCED_CARDS => ['refund' => false, 'token_billing' => true], // GatewayType::SEPA => ['refund' => false, 'token_billing' => false], // GatewayType::BANCONTACT => ['refund' => false, 'token_billing' => false], // GatewayType::EPS => ['refund' => false, 'token_billing' => false], @@ -207,6 +208,7 @@ class Gateway extends StaticModel GatewayType::PAYPAL => ['refund' => false, 'token_billing' => false], GatewayType::CREDIT_CARD => ['refund' => false, 'token_billing' => false], GatewayType::VENMO => ['refund' => false, 'token_billing' => false], + GatewayType::PAYPAL_ADVANCED_CARDS => ['refund' => false, 'token_billing' => true], // GatewayType::SEPA => ['refund' => false, 'token_billing' => false], // GatewayType::BANCONTACT => ['refund' => false, 'token_billing' => false], // GatewayType::EPS => ['refund' => false, 'token_billing' => false], diff --git a/app/Models/GatewayType.php b/app/Models/GatewayType.php index 473838f4e2..f30d5c97cb 100644 --- a/app/Models/GatewayType.php +++ b/app/Models/GatewayType.php @@ -91,6 +91,8 @@ class GatewayType extends StaticModel public const PAYLATER = 28; + public const PAYPAL_ADVANCED_CARDS = 29; + public function gateway() { return $this->belongsTo(Gateway::class); @@ -158,6 +160,9 @@ class GatewayType extends StaticModel return ctrans('texts.mybank'); case self::PAYLATER: return ctrans('texts.paypal_paylater'); + case self::PAYPAL_ADVANCED_CARDS: + return ctrans('texts.credit_card'); + default: return ' '; } diff --git a/app/PaymentDrivers/PayPal/PayPalWebhook.php b/app/PaymentDrivers/PayPal/PayPalWebhook.php index 0d800d826d..fa08542af0 100644 --- a/app/PaymentDrivers/PayPal/PayPalWebhook.php +++ b/app/PaymentDrivers/PayPal/PayPalWebhook.php @@ -399,3 +399,64 @@ class PayPalWebhook implements ShouldQueue } } */ + + +/** token created + * { + "id":"WH-1KN88282901968003-82E75604WM969463F", + "event_version":"1.0", + "create_time":"2022-08-15T14:13:48.978Z", + "resource_type":"payment_token", + "resource_version":"3.0", + "event_type":"VAULT.PAYMENT-TOKEN.CREATED", + "summary":"A payment token has been created.", + "resource":{ + "time_created":"2022-08-15T07:13:48.964PDT", + "links":[ + { + "href":"https://api-m.sandbox.paypal.com/v3/vault/payment-tokens/9n6724m", + "rel":"self", + "method":"GET", + "encType":"application/json" + }, + { + "href":"https://api-m.sandbox.paypal.com/v3/vault/payment-tokens/9n6724m", + "rel":"delete", + "method":"DELETE", + "encType":"application/json" + } + ], + "id":"9n6724m", + "payment_source":{ + "card":{ + "last_digits":"1111", + "brand":"VISA", + "expiry":"2027-02", + "billing_address":{ + "address_line_1":"2211 N First Street", + "address_line_2":"17.3.160", + "admin_area_2":"San Jose", + "admin_area_1":"CA", + "postal_code":"95131", + "country_code":"US" + } + } + }, + "customer":{ + "id":"695922590" + } + }, + "links":[ + { + "href":"https://api-m.sandbox.paypal.com/v1/notifications/webhooks-events/WH-1KN88282901968003-82E75604WM969463F", + "rel":"self", + "method":"GET" + }, + { + "href":"https://api-m.sandbox.paypal.com/v1/notifications/webhooks-events/WH-1KN88282901968003-82E75604WM969463F/resend", + "rel":"resend", + "method":"POST" + } + ] + } + */ \ No newline at end of file diff --git a/app/PaymentDrivers/PayPalRestPaymentDriver.php b/app/PaymentDrivers/PayPalRestPaymentDriver.php index cdad6a880e..047f02df15 100644 --- a/app/PaymentDrivers/PayPalRestPaymentDriver.php +++ b/app/PaymentDrivers/PayPalRestPaymentDriver.php @@ -52,6 +52,7 @@ class PayPalRestPaymentDriver extends BaseDriver 3 => 'paypal', 1 => 'card', 25 => 'venmo', + 29 => 'paypal_advanced_cards', // 9 => 'sepa', // 12 => 'bancontact', // 17 => 'eps', @@ -117,6 +118,7 @@ class PayPalRestPaymentDriver extends BaseDriver "3" => $method = PaymentType::PAYPAL, "25" => $method = PaymentType::VENMO, "28" => $method = PaymentType::PAY_LATER, + "29" => $method = PaymentType::CREDIT_CARD_OTHER, }; return $method; @@ -208,6 +210,10 @@ return render('gateways.paypal.pay', $data); } + public function processTokenPayment(array $response) { + + } + public function processPaymentResponse($request) { @@ -216,6 +222,9 @@ return render('gateways.paypal.pay', $data); $request['gateway_response'] = str_replace("Error: ", "", $request['gateway_response']); $response = json_decode($request['gateway_response'], true); + if(isset($response['gateway_response']['token']) && strlen($response['gateway_response']['token']) > 2) + return $this->processTokenPayment($response); + // nlog($response); //capture $orderID = $response['orderID']; @@ -272,6 +281,8 @@ return render('gateways.paypal.pay', $data); if(isset($response['status']) && $response['status'] == 'COMPLETED' && isset($response['purchase_units'])) { + nlog($response->json()); + $data = [ 'payment_type' => $this->getPaymentMethod($request->gateway_type_id), 'amount' => $response['purchase_units'][0]['payments']['captures'][0]['amount']['value'], @@ -281,8 +292,40 @@ return render('gateways.paypal.pay', $data); $payment = $this->createPayment($data, \App\Models\Payment::STATUS_COMPLETED); + if ($request->has('store_card') && $request->input('store_card') === true) { + $payment_source = $response->json()['payment_source']; + + if(isset($payment_source['card']) && ($payment_source['card']['attributes']['vault']['status'] ?? false) && $payment_source['card']['attributes']['vault']['status'] == 'VAULTED'){ + + $last4 = $payment_source['card']['last_digits']; + $expiry = $payment_source['card']['expiry']; //'2025-01' + $expiry_meta = explode('-', $expiry); + $brand = $payment_source['card']['brand']; + + $payment_meta = new \stdClass(); + $payment_meta->exp_month = $expiry_meta[1] ?? ''; + $payment_meta->exp_year = $expiry_meta[0] ?? $expiry; + $payment_meta->brand = $brand; + $payment_meta->last4 = $last4; + $payment_meta->type = GatewayType::CREDIT_CARD; + + $token = $payment_source['card']['attributes']['vault']['id']; // 09f28652d01257021 + $gateway_customer_reference = $payment_source['card']['attributes']['vault']['customer']['id']; //rbTHnLsZqE; + + $data['token'] = $token; + $data['payment_method_id'] = GatewayType::PAYPAL_ADVANCED_CARDS; + $data['payment_meta'] = $payment_meta; + $data['payment_method_id'] = GatewayType::CREDIT_CARD; + + $additional['gateway_customer_reference'] = $gateway_customer_reference; + + $this->storeGatewayToken($data, $additional); + + } + } + SystemLogger::dispatch( - ['response' => $response, 'data' => $data], + ['response' => $response->json(), 'data' => $data], SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_SUCCESS, SystemLog::TYPE_PAYPAL, @@ -329,32 +372,40 @@ return render('gateways.paypal.pay', $data); private function getPaymentSource(): array { - - if($this->gateway_type_id == 1) { + //@todo - roll back here for advanced payments vs hosted card fields. + if($this->gateway_type_id == GatewayType::PAYPAL_ADVANCED_CARDS) { return [ "card" => [ "attributes" => [ "verification" => [ "method" => "SCA_WHEN_REQUIRED", //SCA_ALWAYS + // "method" => "SCA_ALWAYS", //SCA_ALWAYS + ], + "vault" => [ + "store_in_vault" => "ON_SUCCESS", //must listen to this webhook - VAULT.PAYMENT-TOKEN.CREATED webhook. ], ], - "name" => $this->client->present()->primary_contact_name(), - "email_address" => $this->client->present()->email(), - "address" => [ - "address_line_1" => $this->client->address1, - "address_line_2" => $this->client->address2, - "admin_area_2" => $this->client->city, - "admin_area_1" => $this->client->state, - "postal_code" => $this->client->postal_code, - "country_code" => $this->client->country->iso_3166_2, - ], - "experience_context" => [ - "user_action" => "PAY_NOW" - ], + "experience_context" => [ + "shipping_preference" => "SET_PROVIDED_ADDRESS" + ], + // "name" => $this->client->present()->primary_contact_name(), + // "email_address" => $this->client->present()->email(), + // "address" => [ + // "address_line_1" => $this->client->address1, + // "address_line_2" => $this->client->address2, + // "admin_area_2" => $this->client->city, + // "admin_area_1" => $this->client->state, + // "postal_code" => $this->client->postal_code, + // "country_code" => $this->client->country->iso_3166_2, + // ], + // "experience_context" => [ + // "user_action" => "PAY_NOW" + // ], "stored_credential" => [ - "payment_initiator" => "MERCHANT", //"CUSTOMER" who initiated the transaction? - "payment_type" => "UNSCHEDULED", + // "payment_initiator" => "MERCHANT", //"CUSTOMER" who initiated the transaction? + "payment_initiator" => "CUSTOMER", //"" who initiated the transaction? + "payment_type" => "UNSCHEDULED", //UNSCHEDULED "usage"=> "DERIVED", ], ], @@ -406,9 +457,9 @@ return render('gateways.paypal.pay', $data); "custom_id" => $this->payment_hash->hash, "description" => ctrans('texts.invoice_number') . '# ' . $invoice->number, "invoice_id" => $invoice->number, - "payment_instruction" => [ - "disbursement_mode" => "INSTANT", - ], + // "payment_instruction" => [ + // "disbursement_mode" => "INSTANT", + // ], $this->getShippingAddress(), "amount" => [ "value" => (string) $data['amount_with_fee'], @@ -440,6 +491,8 @@ return render('gateways.paypal.pay', $data); $order['purchase_units'][0]["shipping"] = $shipping; } + nlog($order); + $r = $this->gatewayRequest('/v2/checkout/orders', 'post', $order); // nlog($r->json()); @@ -463,7 +516,11 @@ return render('gateways.paypal.pay', $data); ], ] - : null; + : [ + "name" => [ + "full_name" => $this->client->present()->name() + ] + ]; } diff --git a/lang/en/texts.php b/lang/en/texts.php index e542e667e9..970d5f6c83 100644 --- a/lang/en/texts.php +++ b/lang/en/texts.php @@ -5296,6 +5296,7 @@ $lang = array( 'rappen_rounding' => 'Rappen Rounding', 'rappen_rounding_help' => 'Round amount to 5 cents', 'assign_group' => 'Assign group', + 'paypal_advanced_cards' => 'Advanced Card Payments', ); return $lang; diff --git a/resources/views/portal/ninja2020/gateways/paypal/ppcp/card.blade.php b/resources/views/portal/ninja2020/gateways/paypal/ppcp/card.blade.php index aea037e366..dc40aa436b 100644 --- a/resources/views/portal/ninja2020/gateways/paypal/ppcp/card.blade.php +++ b/resources/views/portal/ninja2020/gateways/paypal/ppcp/card.blade.php @@ -12,26 +12,48 @@ + + + @include('portal.ninja2020.gateways.includes.payment_details') +
+ @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.pay_with')]) + @if (count($tokens) > 0) + @foreach ($tokens as $token) + + @endforeach + @endisset + + + + @endcomponent +
- - +
- - @include('portal.ninja2020.gateways.includes.pay_now') + + @include('portal.ninja2020.gateways.includes.save_card')
+ @include('portal.ninja2020.gateways.includes.pay_now') + @endsection @section('gateway_footer') @@ -70,14 +92,32 @@ }, onApprove: function(data, actions) { + const { liabilityShift, orderID } = data; + if(liabilityShift) { + + /* Handle liability shift. More information in 3D Secure response parameters */ + // console.log("inside liability shift") + // console.log(liabilityShift) + // console.log(orderID); + // console.log(data); + //doesn't really do anything as failure is linked in SUBMIT. We only hit here after a successful return + //and where SCA is optional? + + } + var errorDetail = Array.isArray(data.details) && data.details[0]; if (errorDetail && ['INSTRUMENT_DECLINED', 'PAYER_ACTION_REQUIRED'].includes(errorDetail.issue)) { return actions.restart(); } - console.log("on approve"); - console.log(data); - console.log(actions); + // console.log("on approve"); + // console.log(data); + // console.log(actions); + let storeCard = document.querySelector('input[name=token-billing-checkbox]:checked'); + + if (storeCard) { + document.getElementById("store_card").value = storeCard.value; + } document.getElementById("gateway_response").value = JSON.stringify( data ); document.getElementById("server_response").submit(); @@ -88,16 +128,15 @@ window.location.href = "/client/invoices/"; }, - // onError: function(error) { + onError: function(error) { + // console.log("on error") + // console.log(error); + document.getElementById('errors').textContent = `Sorry, your transaction could not be processed...\n\n${error.message}`; + document.getElementById('errors').hidden = false; - // document.getElementById('errors').textContent = `Sorry, your transaction could not be processed...\n\n${error.message}`; - // document.getElementById('errors').hidden = false; - - // // document.getElementById("gateway_response").value = error; - // // document.getElementById("server_response").submit(); - // }, + }, onClick: function (){ } @@ -110,7 +149,7 @@ const numberField = cardField.NumberField({ inputEvents: { onChange: (event)=> { - console.log("returns a stateObject", event); + // console.log("returns a stateObject", event); } }, }); @@ -119,7 +158,7 @@ const cvvField = cardField.CVVField({ inputEvents: { onChange: (event)=> { - console.log("returns a stateObject", event); + // console.log("returns a stateObject", event); } }, }); @@ -128,7 +167,7 @@ const expiryField = cardField.ExpiryField({ inputEvents: { onChange: (event)=> { - console.log("returns a stateObject", event); + // console.log("returns a stateObject", event); } }, }); @@ -142,16 +181,20 @@ document.getElementById('pay-now').disabled = true; document.querySelector('#pay-now > svg').classList.remove('hidden'); document.querySelector('#pay-now > svg').classList.add('justify-center'); + + document.querySelector('#pay-now > svg').classList.add('mx-auto'); + document.querySelector('#pay-now > svg').classList.add('item-center'); + document.querySelector('#pay-now > span').classList.add('hidden'); cardField.submit().then((response) => { - console.log("then"); - console.log(response); - // lets goooo + // console.log("then"); + // console.log(response); }).catch((error) => { - console.log(error); + // console.log("catch error") + // console.log(error); document.getElementById('pay-now').disabled = false; document.querySelector('#pay-now > svg').classList.add('hidden'); @@ -180,4 +223,49 @@ + + + @endpush \ No newline at end of file From 28418465832b9abe1b41c0ebe648d6b001746c81 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 22 Apr 2024 14:51:05 +1000 Subject: [PATCH 05/11] Adjustments for parsing dates --- .../Bank/Nordigen/Transformer/TransactionTransformer.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/Helpers/Bank/Nordigen/Transformer/TransactionTransformer.php b/app/Helpers/Bank/Nordigen/Transformer/TransactionTransformer.php index b5495f14cf..183e2181f6 100644 --- a/app/Helpers/Bank/Nordigen/Transformer/TransactionTransformer.php +++ b/app/Helpers/Bank/Nordigen/Transformer/TransactionTransformer.php @@ -191,7 +191,11 @@ class TransactionTransformer implements BankRevenueInterface $date_format_default = $date_format->format; } - return Carbon::createFromFormat("d-m-Y", $input)->setTimezone($timezone_name)->format($date_format_default) ?? $input; + try { + return Carbon::createFromFormat("d-m-Y", $input)->setTimezone($timezone_name)->format($date_format_default) ?? $input; + } catch (\Exception $e) { + return $input; + } } } From de7bd17a5eb0cd7556f6d4f093a407f5df1f6029 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 22 Apr 2024 22:37:34 +1000 Subject: [PATCH 06/11] Paypal rest token payments --- .../PayPalRestPaymentDriver.php | 190 ++++++---- composer.lock | 346 +++++++++--------- .../gateways/paypal/ppcp/card.blade.php | 18 +- 3 files changed, 318 insertions(+), 236 deletions(-) diff --git a/app/PaymentDrivers/PayPalRestPaymentDriver.php b/app/PaymentDrivers/PayPalRestPaymentDriver.php index 047f02df15..247d586843 100644 --- a/app/PaymentDrivers/PayPalRestPaymentDriver.php +++ b/app/PaymentDrivers/PayPalRestPaymentDriver.php @@ -22,6 +22,7 @@ use Illuminate\Support\Str; use App\Jobs\Util\SystemLogger; use App\Utils\Traits\MakesHash; use App\Exceptions\PaymentFailed; +use App\Models\ClientGatewayToken; use Illuminate\Support\Facades\Http; class PayPalRestPaymentDriver extends BaseDriver @@ -169,9 +170,9 @@ class PayPalRestPaymentDriver extends BaseDriver $data['currency'] = $this->client->currency()->code; -// return render('gateways.paypal.ppcp.card', $data); +return render('gateways.paypal.ppcp.card', $data); -return render('gateways.paypal.pay', $data); +// return render('gateways.paypal.pay', $data); } @@ -210,7 +211,64 @@ return render('gateways.paypal.pay', $data); } - public function processTokenPayment(array $response) { + public function processTokenPayment($request, array $response) { + + $cgt = ClientGatewayToken::where('client_id', $this->client->id) + ->where('token', $request['token']) + ->firstOrFail(); + nlog("process token"); + + nlog($request->all()); + nlog($response); + + $orderId = $response['orderID']; + $r = $this->gatewayRequest("/v1/checkout/orders/{$orderId}/", 'delete', ['body' => '']); + + nlog($r); + + $data['amount_with_fee'] = $this->payment_hash->data->amount_with_fee; + $data["payment_source"] = [ + "card" => [ + "vault_id" => $cgt->token, + "stored_credential" => [ + "payment_initiator" => "MERCHANT", + "payment_type" => "UNSCHEDULED", + "usage" => "SUBSEQUENT", + // "previous_transaction_reference" => $cgt->gateway_customer_reference, + ], + ], + ]; + + $orderId = $this->createOrder($data); + + nlog("post order creation"); + nlog($orderId); + + $r = $this->gatewayRequest("/v2/checkout/orders/{$orderId}", 'get', ['body' => '']); + nlog($r); + + $response = $r->json(); + nlog($response); + + $data = [ + 'payment_type' => $this->getPaymentMethod($this->gateway_type_id), + 'amount' => $response['purchase_units'][0]['payments']['captures'][0]['amount']['value'], + 'transaction_reference' => $response['purchase_units'][0]['payments']['captures'][0]['id'], + 'gateway_type_id' => $this->gateway_type_id, + ]; + + $payment = $this->createPayment($data, \App\Models\Payment::STATUS_COMPLETED); + + SystemLogger::dispatch( + ['response' => $response, 'data' => $data], + SystemLog::CATEGORY_GATEWAY_RESPONSE, + SystemLog::EVENT_GATEWAY_SUCCESS, + SystemLog::TYPE_PAYPAL, + $this->client, + $this->client->company, + ); + + return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)]); } @@ -221,9 +279,10 @@ return render('gateways.paypal.pay', $data); $request['gateway_response'] = str_replace("Error: ", "", $request['gateway_response']); $response = json_decode($request['gateway_response'], true); + nlog($request->all()); - if(isset($response['gateway_response']['token']) && strlen($response['gateway_response']['token']) > 2) - return $this->processTokenPayment($response); + if($request->has('token') && strlen($request->input('token')) > 2) + return $this->processTokenPayment($request, $response); // nlog($response); //capture @@ -281,59 +340,7 @@ return render('gateways.paypal.pay', $data); if(isset($response['status']) && $response['status'] == 'COMPLETED' && isset($response['purchase_units'])) { - nlog($response->json()); - - $data = [ - 'payment_type' => $this->getPaymentMethod($request->gateway_type_id), - 'amount' => $response['purchase_units'][0]['payments']['captures'][0]['amount']['value'], - 'transaction_reference' => $response['purchase_units'][0]['payments']['captures'][0]['id'], - 'gateway_type_id' => GatewayType::PAYPAL, - ]; - - $payment = $this->createPayment($data, \App\Models\Payment::STATUS_COMPLETED); - - if ($request->has('store_card') && $request->input('store_card') === true) { - $payment_source = $response->json()['payment_source']; - - if(isset($payment_source['card']) && ($payment_source['card']['attributes']['vault']['status'] ?? false) && $payment_source['card']['attributes']['vault']['status'] == 'VAULTED'){ - - $last4 = $payment_source['card']['last_digits']; - $expiry = $payment_source['card']['expiry']; //'2025-01' - $expiry_meta = explode('-', $expiry); - $brand = $payment_source['card']['brand']; - - $payment_meta = new \stdClass(); - $payment_meta->exp_month = $expiry_meta[1] ?? ''; - $payment_meta->exp_year = $expiry_meta[0] ?? $expiry; - $payment_meta->brand = $brand; - $payment_meta->last4 = $last4; - $payment_meta->type = GatewayType::CREDIT_CARD; - - $token = $payment_source['card']['attributes']['vault']['id']; // 09f28652d01257021 - $gateway_customer_reference = $payment_source['card']['attributes']['vault']['customer']['id']; //rbTHnLsZqE; - - $data['token'] = $token; - $data['payment_method_id'] = GatewayType::PAYPAL_ADVANCED_CARDS; - $data['payment_meta'] = $payment_meta; - $data['payment_method_id'] = GatewayType::CREDIT_CARD; - - $additional['gateway_customer_reference'] = $gateway_customer_reference; - - $this->storeGatewayToken($data, $additional); - - } - } - - SystemLogger::dispatch( - ['response' => $response->json(), 'data' => $data], - SystemLog::CATEGORY_GATEWAY_RESPONSE, - SystemLog::EVENT_GATEWAY_SUCCESS, - SystemLog::TYPE_PAYPAL, - $this->client, - $this->client->company, - ); - - return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)]); + return $this->createNinjaPayment($request, $response); } else { @@ -357,6 +364,64 @@ return render('gateways.paypal.pay', $data); } + private function createNinjaPayment($request, $response) { + + nlog($response->json()); + + $data = [ + 'payment_type' => $this->getPaymentMethod($request->gateway_type_id), + 'amount' => $response['purchase_units'][0]['payments']['captures'][0]['amount']['value'], + 'transaction_reference' => $response['purchase_units'][0]['payments']['captures'][0]['id'], + 'gateway_type_id' => GatewayType::PAYPAL, + ]; + + $payment = $this->createPayment($data, \App\Models\Payment::STATUS_COMPLETED); + + if ($request->has('store_card') && $request->input('store_card') === true) { + $payment_source = $response->json()['payment_source']; + + if(isset($payment_source['card']) && ($payment_source['card']['attributes']['vault']['status'] ?? false) && $payment_source['card']['attributes']['vault']['status'] == 'VAULTED') { + + $last4 = $payment_source['card']['last_digits']; + $expiry = $payment_source['card']['expiry']; //'2025-01' + $expiry_meta = explode('-', $expiry); + $brand = $payment_source['card']['brand']; + + $payment_meta = new \stdClass(); + $payment_meta->exp_month = $expiry_meta[1] ?? ''; + $payment_meta->exp_year = $expiry_meta[0] ?? $expiry; + $payment_meta->brand = $brand; + $payment_meta->last4 = $last4; + $payment_meta->type = GatewayType::CREDIT_CARD; + + $token = $payment_source['card']['attributes']['vault']['id']; // 09f28652d01257021 + $gateway_customer_reference = $payment_source['card']['attributes']['vault']['customer']['id']; //rbTHnLsZqE; + + $data['token'] = $token; + $data['payment_method_id'] = GatewayType::PAYPAL_ADVANCED_CARDS; + $data['payment_meta'] = $payment_meta; + $data['payment_method_id'] = GatewayType::CREDIT_CARD; + + $additional['gateway_customer_reference'] = $gateway_customer_reference; + + $this->storeGatewayToken($data, $additional); + + } + } + + SystemLogger::dispatch( + ['response' => $response->json(), 'data' => $data], + SystemLog::CATEGORY_GATEWAY_RESPONSE, + SystemLog::EVENT_GATEWAY_SUCCESS, + SystemLog::TYPE_PAYPAL, + $this->client, + $this->client->company, + ); + + return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)]); + + } + private function getClientToken(): string { @@ -449,7 +514,6 @@ return render('gateways.paypal.pay', $data); })->implode("\n"); $order = [ - "intent" => "CAPTURE", "payment_source" => $this->getPaymentSource(), "purchase_units" => [ @@ -457,9 +521,6 @@ return render('gateways.paypal.pay', $data); "custom_id" => $this->payment_hash->hash, "description" => ctrans('texts.invoice_number') . '# ' . $invoice->number, "invoice_id" => $invoice->number, - // "payment_instruction" => [ - // "disbursement_mode" => "INSTANT", - // ], $this->getShippingAddress(), "amount" => [ "value" => (string) $data['amount_with_fee'], @@ -491,6 +552,9 @@ return render('gateways.paypal.pay', $data); $order['purchase_units'][0]["shipping"] = $shipping; } + if(isset($data['payment_source'])) + $order['payment_source'] = $data['payment_source']; + nlog($order); $r = $this->gatewayRequest('/v2/checkout/orders', 'post', $order); @@ -564,6 +628,8 @@ return render('gateways.paypal.pay', $data); 'Accept' => 'application/json', 'Content-type' => 'application/json', 'Accept-Language' => 'en_US', + 'PayPal-Partner-Attribution-Id' => 'invoiceninja_SP_PPCP', + 'PayPal-Request-Id' => Str::uuid()->toString(), ], $headers); } diff --git a/composer.lock b/composer.lock index 3f234bf476..698624de85 100644 --- a/composer.lock +++ b/composer.lock @@ -100,16 +100,16 @@ }, { "name": "amphp/amp", - "version": "v3.0.0", + "version": "v3.0.1", "source": { "type": "git", "url": "https://github.com/amphp/amp.git", - "reference": "aaf0ec1d5a2c20b523258995a10e80c1fb765871" + "reference": "ff63f10210adb6e83335e0e25522bac5cd7dc4e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/amp/zipball/aaf0ec1d5a2c20b523258995a10e80c1fb765871", - "reference": "aaf0ec1d5a2c20b523258995a10e80c1fb765871", + "url": "https://api.github.com/repos/amphp/amp/zipball/ff63f10210adb6e83335e0e25522bac5cd7dc4e2", + "reference": "ff63f10210adb6e83335e0e25522bac5cd7dc4e2", "shasum": "" }, "require": { @@ -119,7 +119,7 @@ "require-dev": { "amphp/php-cs-fixer-config": "^2", "phpunit/phpunit": "^9", - "psalm/phar": "^4.13" + "psalm/phar": "5.23.1" }, "type": "library", "autoload": { @@ -169,7 +169,7 @@ ], "support": { "issues": "https://github.com/amphp/amp/issues", - "source": "https://github.com/amphp/amp/tree/v3.0.0" + "source": "https://github.com/amphp/amp/tree/v3.0.1" }, "funding": [ { @@ -177,7 +177,7 @@ "type": "github" } ], - "time": "2022-12-18T16:52:44+00:00" + "time": "2024-04-18T15:24:36+00:00" }, { "name": "amphp/byte-stream", @@ -256,16 +256,16 @@ }, { "name": "amphp/cache", - "version": "v2.0.0", + "version": "v2.0.1", "source": { "type": "git", "url": "https://github.com/amphp/cache.git", - "reference": "218bb3888d380eb9dd926cd06f803573c84391d3" + "reference": "46912e387e6aa94933b61ea1ead9cf7540b7797c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/cache/zipball/218bb3888d380eb9dd926cd06f803573c84391d3", - "reference": "218bb3888d380eb9dd926cd06f803573c84391d3", + "url": "https://api.github.com/repos/amphp/cache/zipball/46912e387e6aa94933b61ea1ead9cf7540b7797c", + "reference": "46912e387e6aa94933b61ea1ead9cf7540b7797c", "shasum": "" }, "require": { @@ -309,7 +309,7 @@ "homepage": "https://amphp.org/cache", "support": { "issues": "https://github.com/amphp/cache/issues", - "source": "https://github.com/amphp/cache/tree/v2.0.0" + "source": "https://github.com/amphp/cache/tree/v2.0.1" }, "funding": [ { @@ -317,20 +317,20 @@ "type": "github" } ], - "time": "2023-01-09T21:04:12+00:00" + "time": "2024-04-19T03:38:06+00:00" }, { "name": "amphp/dns", - "version": "v2.1.1", + "version": "v2.1.2", "source": { "type": "git", "url": "https://github.com/amphp/dns.git", - "reference": "3e3f413fbbaacd9632b1612941b363fa26a72e52" + "reference": "04c88e67bef804203df934703bd422ea72f46b0e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/dns/zipball/3e3f413fbbaacd9632b1612941b363fa26a72e52", - "reference": "3e3f413fbbaacd9632b1612941b363fa26a72e52", + "url": "https://api.github.com/repos/amphp/dns/zipball/04c88e67bef804203df934703bd422ea72f46b0e", + "reference": "04c88e67bef804203df934703bd422ea72f46b0e", "shasum": "" }, "require": { @@ -397,7 +397,7 @@ ], "support": { "issues": "https://github.com/amphp/dns/issues", - "source": "https://github.com/amphp/dns/tree/v2.1.1" + "source": "https://github.com/amphp/dns/tree/v2.1.2" }, "funding": [ { @@ -405,7 +405,7 @@ "type": "github" } ], - "time": "2024-01-30T23:25:30+00:00" + "time": "2024-04-19T03:49:29+00:00" }, { "name": "amphp/parallel", @@ -622,16 +622,16 @@ }, { "name": "amphp/process", - "version": "v2.0.2", + "version": "v2.0.3", "source": { "type": "git", "url": "https://github.com/amphp/process.git", - "reference": "a79dc87100be857db2c4bbfd5369585a6d1e658c" + "reference": "52e08c09dec7511d5fbc1fb00d3e4e79fc77d58d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/process/zipball/a79dc87100be857db2c4bbfd5369585a6d1e658c", - "reference": "a79dc87100be857db2c4bbfd5369585a6d1e658c", + "url": "https://api.github.com/repos/amphp/process/zipball/52e08c09dec7511d5fbc1fb00d3e4e79fc77d58d", + "reference": "52e08c09dec7511d5fbc1fb00d3e4e79fc77d58d", "shasum": "" }, "require": { @@ -678,7 +678,7 @@ "homepage": "https://amphp.org/process", "support": { "issues": "https://github.com/amphp/process/issues", - "source": "https://github.com/amphp/process/tree/v2.0.2" + "source": "https://github.com/amphp/process/tree/v2.0.3" }, "funding": [ { @@ -686,7 +686,7 @@ "type": "github" } ], - "time": "2024-02-13T20:38:21+00:00" + "time": "2024-04-19T03:13:44+00:00" }, { "name": "amphp/serialization", @@ -748,16 +748,16 @@ }, { "name": "amphp/socket", - "version": "v2.3.0", + "version": "v2.3.1", "source": { "type": "git", "url": "https://github.com/amphp/socket.git", - "reference": "acc0a2f65ab498025ba5641f7cce499c4b1ed4b5" + "reference": "58e0422221825b79681b72c50c47a930be7bf1e1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/socket/zipball/acc0a2f65ab498025ba5641f7cce499c4b1ed4b5", - "reference": "acc0a2f65ab498025ba5641f7cce499c4b1ed4b5", + "url": "https://api.github.com/repos/amphp/socket/zipball/58e0422221825b79681b72c50c47a930be7bf1e1", + "reference": "58e0422221825b79681b72c50c47a930be7bf1e1", "shasum": "" }, "require": { @@ -820,7 +820,7 @@ ], "support": { "issues": "https://github.com/amphp/socket/issues", - "source": "https://github.com/amphp/socket/tree/v2.3.0" + "source": "https://github.com/amphp/socket/tree/v2.3.1" }, "funding": [ { @@ -828,7 +828,7 @@ "type": "github" } ], - "time": "2024-03-19T20:01:53+00:00" + "time": "2024-04-21T14:33:03+00:00" }, { "name": "amphp/sync", @@ -1384,16 +1384,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.304.2", + "version": "3.304.8", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "2435079c3e1a08148d955de15ec090018114f35a" + "reference": "0079eaa0a0eaef2d73d0a4a11389cdfce1d33189" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/2435079c3e1a08148d955de15ec090018114f35a", - "reference": "2435079c3e1a08148d955de15ec090018114f35a", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/0079eaa0a0eaef2d73d0a4a11389cdfce1d33189", + "reference": "0079eaa0a0eaef2d73d0a4a11389cdfce1d33189", "shasum": "" }, "require": { @@ -1473,9 +1473,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.304.2" + "source": "https://github.com/aws/aws-sdk-php/tree/3.304.8" }, - "time": "2024-04-10T18:05:32+00:00" + "time": "2024-04-19T18:13:09+00:00" }, { "name": "bacon/bacon-qr-code", @@ -2018,21 +2018,21 @@ }, { "name": "daverandom/libdns", - "version": "v2.0.3", + "version": "v2.1.0", "source": { "type": "git", "url": "https://github.com/DaveRandom/LibDNS.git", - "reference": "42c2d700d1178c9f9e78664793463f7f1aea248c" + "reference": "b84c94e8fe6b7ee4aecfe121bfe3b6177d303c8a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/DaveRandom/LibDNS/zipball/42c2d700d1178c9f9e78664793463f7f1aea248c", - "reference": "42c2d700d1178c9f9e78664793463f7f1aea248c", + "url": "https://api.github.com/repos/DaveRandom/LibDNS/zipball/b84c94e8fe6b7ee4aecfe121bfe3b6177d303c8a", + "reference": "b84c94e8fe6b7ee4aecfe121bfe3b6177d303c8a", "shasum": "" }, "require": { "ext-ctype": "*", - "php": ">=7.0" + "php": ">=7.1" }, "suggest": { "ext-intl": "Required for IDN support" @@ -2056,9 +2056,9 @@ ], "support": { "issues": "https://github.com/DaveRandom/LibDNS/issues", - "source": "https://github.com/DaveRandom/LibDNS/tree/v2.0.3" + "source": "https://github.com/DaveRandom/LibDNS/tree/v2.1.0" }, - "time": "2022-09-20T18:15:38+00:00" + "time": "2024-04-12T12:12:48+00:00" }, { "name": "dflydev/apache-mime-types", @@ -3413,22 +3413,22 @@ }, { "name": "goetas-webservices/xsd2php-runtime", - "version": "v0.2.16", + "version": "v0.2.17", "source": { "type": "git", "url": "https://github.com/goetas-webservices/xsd2php-runtime.git", - "reference": "4a24dc8ead032dae6cf82168a46702a31f7db42f" + "reference": "be15c48cda6adfab82e180a69dfa1937e208cfe1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/goetas-webservices/xsd2php-runtime/zipball/4a24dc8ead032dae6cf82168a46702a31f7db42f", - "reference": "4a24dc8ead032dae6cf82168a46702a31f7db42f", + "url": "https://api.github.com/repos/goetas-webservices/xsd2php-runtime/zipball/be15c48cda6adfab82e180a69dfa1937e208cfe1", + "reference": "be15c48cda6adfab82e180a69dfa1937e208cfe1", "shasum": "" }, "require": { "jms/serializer": "^1.2|^2.0|^3.0", "php": ">=7.1", - "symfony/yaml": "^2.2|^3.0|^4.0|^5.0|^6.0" + "symfony/yaml": "^2.2|^3.0|^4.0|^5.0|^6.0|^7.0" }, "conflict": { "jms/serializer": "1.4.1|1.6.1|1.6.2" @@ -3467,9 +3467,9 @@ ], "support": { "issues": "https://github.com/goetas-webservices/xsd2php-runtime/issues", - "source": "https://github.com/goetas-webservices/xsd2php-runtime/tree/v0.2.16" + "source": "https://github.com/goetas-webservices/xsd2php-runtime/tree/v0.2.17" }, - "time": "2022-02-04T09:31:42+00:00" + "time": "2024-04-12T22:55:31+00:00" }, { "name": "google/apiclient", @@ -3542,16 +3542,16 @@ }, { "name": "google/apiclient-services", - "version": "v0.343.0", + "version": "v0.345.0", "source": { "type": "git", "url": "https://github.com/googleapis/google-api-php-client-services.git", - "reference": "8cb869e5c413b0e9d4aeada3d83df5e2ce388154" + "reference": "a975dae4c06d304b020eda3f53e7c3402b32132d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/8cb869e5c413b0e9d4aeada3d83df5e2ce388154", - "reference": "8cb869e5c413b0e9d4aeada3d83df5e2ce388154", + "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/a975dae4c06d304b020eda3f53e7c3402b32132d", + "reference": "a975dae4c06d304b020eda3f53e7c3402b32132d", "shasum": "" }, "require": { @@ -3580,9 +3580,9 @@ ], "support": { "issues": "https://github.com/googleapis/google-api-php-client-services/issues", - "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.343.0" + "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.345.0" }, - "time": "2024-04-06T00:58:16+00:00" + "time": "2024-04-21T01:02:15+00:00" }, { "name": "google/auth", @@ -4404,16 +4404,16 @@ }, { "name": "horstoeko/orderx", - "version": "v1.0.20", + "version": "v1.0.21", "source": { "type": "git", "url": "https://github.com/horstoeko/orderx.git", - "reference": "d8957cc0fea19b098d799a0c438a73504e7b326c" + "reference": "eaa2bd74b03c6845a38ef4611501cc4e70adbef7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/horstoeko/orderx/zipball/d8957cc0fea19b098d799a0c438a73504e7b326c", - "reference": "d8957cc0fea19b098d799a0c438a73504e7b326c", + "url": "https://api.github.com/repos/horstoeko/orderx/zipball/eaa2bd74b03c6845a38ef4611501cc4e70adbef7", + "reference": "eaa2bd74b03c6845a38ef4611501cc4e70adbef7", "shasum": "" }, "require": { @@ -4466,9 +4466,9 @@ ], "support": { "issues": "https://github.com/horstoeko/orderx/issues", - "source": "https://github.com/horstoeko/orderx/tree/v1.0.20" + "source": "https://github.com/horstoeko/orderx/tree/v1.0.21" }, - "time": "2024-03-21T04:28:54+00:00" + "time": "2024-04-18T04:14:03+00:00" }, { "name": "horstoeko/stringmanagement", @@ -4526,16 +4526,16 @@ }, { "name": "horstoeko/zugferd", - "version": "v1.0.38", + "version": "v1.0.41", "source": { "type": "git", "url": "https://github.com/horstoeko/zugferd.git", - "reference": "47730d3d01c1229f22d75193d68bc43ea16bcdb7" + "reference": "dee8f7efd017de6e637621e30808aff420641d5a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/horstoeko/zugferd/zipball/47730d3d01c1229f22d75193d68bc43ea16bcdb7", - "reference": "47730d3d01c1229f22d75193d68bc43ea16bcdb7", + "url": "https://api.github.com/repos/horstoeko/zugferd/zipball/dee8f7efd017de6e637621e30808aff420641d5a", + "reference": "dee8f7efd017de6e637621e30808aff420641d5a", "shasum": "" }, "require": { @@ -4548,6 +4548,7 @@ "setasign/fpdf": "^1", "setasign/fpdi": "^2", "smalot/pdfparser": "^0|^2", + "symfony/process": "^5|^6", "symfony/validator": "^5|^6", "symfony/yaml": "^5|^6" }, @@ -4594,9 +4595,9 @@ ], "support": { "issues": "https://github.com/horstoeko/zugferd/issues", - "source": "https://github.com/horstoeko/zugferd/tree/v1.0.38" + "source": "https://github.com/horstoeko/zugferd/tree/v1.0.41" }, - "time": "2024-04-05T03:38:38+00:00" + "time": "2024-04-18T03:57:58+00:00" }, { "name": "http-interop/http-factory-guzzle", @@ -5526,16 +5527,16 @@ }, { "name": "laravel/framework", - "version": "v10.48.7", + "version": "v10.48.8", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "118c686992f4b90d4da6deaf0901315c337bbaf9" + "reference": "8e9ab6da362f268170fe815127aed5ec7d303697" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/118c686992f4b90d4da6deaf0901315c337bbaf9", - "reference": "118c686992f4b90d4da6deaf0901315c337bbaf9", + "url": "https://api.github.com/repos/laravel/framework/zipball/8e9ab6da362f268170fe815127aed5ec7d303697", + "reference": "8e9ab6da362f268170fe815127aed5ec7d303697", "shasum": "" }, "require": { @@ -5729,20 +5730,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2024-04-10T14:57:20+00:00" + "time": "2024-04-16T14:26:04+00:00" }, { "name": "laravel/prompts", - "version": "v0.1.18", + "version": "v0.1.19", "source": { "type": "git", "url": "https://github.com/laravel/prompts.git", - "reference": "3b5e6b03f1f1175574b5a32331d99c9819da9848" + "reference": "0ab75ac3434d9f610c5691758a6146a3d1940c18" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/prompts/zipball/3b5e6b03f1f1175574b5a32331d99c9819da9848", - "reference": "3b5e6b03f1f1175574b5a32331d99c9819da9848", + "url": "https://api.github.com/repos/laravel/prompts/zipball/0ab75ac3434d9f610c5691758a6146a3d1940c18", + "reference": "0ab75ac3434d9f610c5691758a6146a3d1940c18", "shasum": "" }, "require": { @@ -5784,9 +5785,9 @@ ], "support": { "issues": "https://github.com/laravel/prompts/issues", - "source": "https://github.com/laravel/prompts/tree/v0.1.18" + "source": "https://github.com/laravel/prompts/tree/v0.1.19" }, - "time": "2024-04-04T17:41:50+00:00" + "time": "2024-04-16T14:20:35+00:00" }, { "name": "laravel/serializable-closure", @@ -5911,26 +5912,28 @@ }, { "name": "laravel/socialite", - "version": "v5.12.1", + "version": "v5.13.0", "source": { "type": "git", "url": "https://github.com/laravel/socialite.git", - "reference": "7dae1b072573809f32ab6dcf4aebb57c8b3e8acf" + "reference": "a03e9b2f63d8125f61952fe4f5b75d70fd7c8286" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/socialite/zipball/7dae1b072573809f32ab6dcf4aebb57c8b3e8acf", - "reference": "7dae1b072573809f32ab6dcf4aebb57c8b3e8acf", + "url": "https://api.github.com/repos/laravel/socialite/zipball/a03e9b2f63d8125f61952fe4f5b75d70fd7c8286", + "reference": "a03e9b2f63d8125f61952fe4f5b75d70fd7c8286", "shasum": "" }, "require": { "ext-json": "*", + "firebase/php-jwt": "^6.4", "guzzlehttp/guzzle": "^6.0|^7.0", "illuminate/contracts": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0", "illuminate/http": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0", "illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0", "league/oauth1-client": "^1.10.1", - "php": "^7.2|^8.0" + "php": "^7.2|^8.0", + "phpseclib/phpseclib": "^3.0" }, "require-dev": { "mockery/mockery": "^1.0", @@ -5977,7 +5980,7 @@ "issues": "https://github.com/laravel/socialite/issues", "source": "https://github.com/laravel/socialite" }, - "time": "2024-02-16T08:58:20+00:00" + "time": "2024-04-15T18:09:46+00:00" }, { "name": "laravel/tinker", @@ -7494,16 +7497,16 @@ }, { "name": "mollie/mollie-api-php", - "version": "v2.66.0", + "version": "v2.67.0", "source": { "type": "git", "url": "https://github.com/mollie/mollie-api-php.git", - "reference": "d7d09ac62a565e818bf49d04acb2f0432da758a9" + "reference": "cf15c53127aaaac9b39d3c9772bf3f4c8ee16bd2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mollie/mollie-api-php/zipball/d7d09ac62a565e818bf49d04acb2f0432da758a9", - "reference": "d7d09ac62a565e818bf49d04acb2f0432da758a9", + "url": "https://api.github.com/repos/mollie/mollie-api-php/zipball/cf15c53127aaaac9b39d3c9772bf3f4c8ee16bd2", + "reference": "cf15c53127aaaac9b39d3c9772bf3f4c8ee16bd2", "shasum": "" }, "require": { @@ -7580,9 +7583,9 @@ ], "support": { "issues": "https://github.com/mollie/mollie-api-php/issues", - "source": "https://github.com/mollie/mollie-api-php/tree/v2.66.0" + "source": "https://github.com/mollie/mollie-api-php/tree/v2.67.0" }, - "time": "2024-03-19T13:33:42+00:00" + "time": "2024-04-12T07:06:01+00:00" }, { "name": "moneyphp/money", @@ -7674,16 +7677,16 @@ }, { "name": "monolog/monolog", - "version": "3.5.0", + "version": "3.6.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "c915e2634718dbc8a4a15c61b0e62e7a44e14448" + "reference": "4b18b21a5527a3d5ffdac2fd35d3ab25a9597654" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/c915e2634718dbc8a4a15c61b0e62e7a44e14448", - "reference": "c915e2634718dbc8a4a15c61b0e62e7a44e14448", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/4b18b21a5527a3d5ffdac2fd35d3ab25a9597654", + "reference": "4b18b21a5527a3d5ffdac2fd35d3ab25a9597654", "shasum": "" }, "require": { @@ -7706,7 +7709,7 @@ "phpstan/phpstan": "^1.9", "phpstan/phpstan-deprecation-rules": "^1.0", "phpstan/phpstan-strict-rules": "^1.4", - "phpunit/phpunit": "^10.1", + "phpunit/phpunit": "^10.5.17", "predis/predis": "^1.1 || ^2", "ruflin/elastica": "^7", "symfony/mailer": "^5.4 || ^6", @@ -7759,7 +7762,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/3.5.0" + "source": "https://github.com/Seldaek/monolog/tree/3.6.0" }, "funding": [ { @@ -7771,7 +7774,7 @@ "type": "tidelift" } ], - "time": "2023-10-27T15:32:31+00:00" + "time": "2024-04-12T21:02:21+00:00" }, { "name": "mtdowling/jmespath.php", @@ -8806,16 +8809,16 @@ }, { "name": "paragonie/sodium_compat", - "version": "v1.20.1", + "version": "v1.21.0", "source": { "type": "git", "url": "https://github.com/paragonie/sodium_compat.git", - "reference": "1840b98d228bdad83869b191d7e51f9bb6624d8d" + "reference": "102bcf2312dc21c16c7c93fd44a6d2a2e1343e26" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/sodium_compat/zipball/1840b98d228bdad83869b191d7e51f9bb6624d8d", - "reference": "1840b98d228bdad83869b191d7e51f9bb6624d8d", + "url": "https://api.github.com/repos/paragonie/sodium_compat/zipball/102bcf2312dc21c16c7c93fd44a6d2a2e1343e26", + "reference": "102bcf2312dc21c16c7c93fd44a6d2a2e1343e26", "shasum": "" }, "require": { @@ -8886,9 +8889,9 @@ ], "support": { "issues": "https://github.com/paragonie/sodium_compat/issues", - "source": "https://github.com/paragonie/sodium_compat/tree/v1.20.1" + "source": "https://github.com/paragonie/sodium_compat/tree/v1.21.0" }, - "time": "2024-04-05T21:00:10+00:00" + "time": "2024-04-19T09:18:28+00:00" }, { "name": "payfast/payfast-php-sdk", @@ -11116,16 +11119,16 @@ }, { "name": "sabre/xml", - "version": "4.0.4", + "version": "4.0.5", "source": { "type": "git", "url": "https://github.com/sabre-io/xml.git", - "reference": "99caa5dd248776ca6a1e1d2cfdef556a3fa63456" + "reference": "c29e49fcf9ca8ca058b1e350ee9abe4205c0de89" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sabre-io/xml/zipball/99caa5dd248776ca6a1e1d2cfdef556a3fa63456", - "reference": "99caa5dd248776ca6a1e1d2cfdef556a3fa63456", + "url": "https://api.github.com/repos/sabre-io/xml/zipball/c29e49fcf9ca8ca058b1e350ee9abe4205c0de89", + "reference": "c29e49fcf9ca8ca058b1e350ee9abe4205c0de89", "shasum": "" }, "require": { @@ -11137,7 +11140,7 @@ "sabre/uri": ">=2.0,<4.0.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.38", + "friendsofphp/php-cs-fixer": "^3.51", "phpstan/phpstan": "^1.10", "phpunit/phpunit": "^9.6" }, @@ -11181,7 +11184,7 @@ "issues": "https://github.com/sabre-io/xml/issues", "source": "https://github.com/fruux/sabre-xml" }, - "time": "2023-11-09T10:47:15+00:00" + "time": "2024-04-18T10:44:25+00:00" }, { "name": "sentry/sdk", @@ -15552,22 +15555,22 @@ }, { "name": "twig/intl-extra", - "version": "v3.8.0", + "version": "v3.9.2", "source": { "type": "git", "url": "https://github.com/twigphp/intl-extra.git", - "reference": "7b3db67c700735f473a265a97e1adaeba3e6ca0c" + "reference": "39865e5d13165016a8e7ab8cc648ad2f7aa4b639" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/intl-extra/zipball/7b3db67c700735f473a265a97e1adaeba3e6ca0c", - "reference": "7b3db67c700735f473a265a97e1adaeba3e6ca0c", + "url": "https://api.github.com/repos/twigphp/intl-extra/zipball/39865e5d13165016a8e7ab8cc648ad2f7aa4b639", + "reference": "39865e5d13165016a8e7ab8cc648ad2f7aa4b639", "shasum": "" }, "require": { "php": ">=7.2.5", - "symfony/intl": "^5.4|^6.0|^7.0", - "twig/twig": "^3.0" + "symfony/intl": "^5.4|^6.4|^7.0", + "twig/twig": "^3.9" }, "require-dev": { "symfony/phpunit-bridge": "^6.4|^7.0" @@ -15600,7 +15603,7 @@ "twig" ], "support": { - "source": "https://github.com/twigphp/intl-extra/tree/v3.8.0" + "source": "https://github.com/twigphp/intl-extra/tree/v3.9.2" }, "funding": [ { @@ -15612,34 +15615,41 @@ "type": "tidelift" } ], - "time": "2023-11-21T17:27:48+00:00" + "time": "2024-04-17T12:41:53+00:00" }, { "name": "twig/twig", - "version": "v3.8.0", + "version": "v3.9.3", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "9d15f0ac07f44dc4217883ec6ae02fd555c6f71d" + "reference": "a842d75fed59cdbcbd3a3ad7fb9eb768fc350d58" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/9d15f0ac07f44dc4217883ec6ae02fd555c6f71d", - "reference": "9d15f0ac07f44dc4217883ec6ae02fd555c6f71d", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/a842d75fed59cdbcbd3a3ad7fb9eb768fc350d58", + "reference": "a842d75fed59cdbcbd3a3ad7fb9eb768fc350d58", "shasum": "" }, "require": { "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-ctype": "^1.8", "symfony/polyfill-mbstring": "^1.3", "symfony/polyfill-php80": "^1.22" }, "require-dev": { "psr/container": "^1.0|^2.0", - "symfony/phpunit-bridge": "^5.4.9|^6.3|^7.0" + "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0" }, "type": "library", "autoload": { + "files": [ + "src/Resources/core.php", + "src/Resources/debug.php", + "src/Resources/escaper.php", + "src/Resources/string_loader.php" + ], "psr-4": { "Twig\\": "src/" } @@ -15672,7 +15682,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.8.0" + "source": "https://github.com/twigphp/Twig/tree/v3.9.3" }, "funding": [ { @@ -15684,7 +15694,7 @@ "type": "tidelift" } ], - "time": "2023-11-21T18:54:41+00:00" + "time": "2024-04-18T11:59:33+00:00" }, { "name": "twilio/sdk", @@ -16923,16 +16933,16 @@ }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.53.0", + "version": "v3.54.0", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "69a19093a9ded8d1baac62ed6c009b8bc148d008" + "reference": "2aecbc8640d7906c38777b3dcab6f4ca79004d08" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/69a19093a9ded8d1baac62ed6c009b8bc148d008", - "reference": "69a19093a9ded8d1baac62ed6c009b8bc148d008", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/2aecbc8640d7906c38777b3dcab6f4ca79004d08", + "reference": "2aecbc8640d7906c38777b3dcab6f4ca79004d08", "shasum": "" }, "require": { @@ -17004,7 +17014,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.53.0" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.54.0" }, "funding": [ { @@ -17012,7 +17022,7 @@ "type": "github" } ], - "time": "2024-04-08T15:03:00+00:00" + "time": "2024-04-17T08:12:13+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -17126,16 +17136,16 @@ }, { "name": "larastan/larastan", - "version": "v2.9.2", + "version": "v2.9.5", "source": { "type": "git", "url": "https://github.com/larastan/larastan.git", - "reference": "a79b46b96060504b400890674b83f66aa7f5db6d" + "reference": "101f1a4470f87326f4d3995411d28679d8800abe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/larastan/larastan/zipball/a79b46b96060504b400890674b83f66aa7f5db6d", - "reference": "a79b46b96060504b400890674b83f66aa7f5db6d", + "url": "https://api.github.com/repos/larastan/larastan/zipball/101f1a4470f87326f4d3995411d28679d8800abe", + "reference": "101f1a4470f87326f4d3995411d28679d8800abe", "shasum": "" }, "require": { @@ -17148,15 +17158,15 @@ "illuminate/pipeline": "^9.52.16 || ^10.28.0 || ^11.0", "illuminate/support": "^9.52.16 || ^10.28.0 || ^11.0", "php": "^8.0.2", - "phpmyadmin/sql-parser": "^5.8.2", - "phpstan/phpstan": "^1.10.50" + "phpmyadmin/sql-parser": "^5.9.0", + "phpstan/phpstan": "^1.10.66" }, "require-dev": { "doctrine/coding-standard": "^12.0", - "nikic/php-parser": "^4.17.1", - "orchestra/canvas": "^7.11.1 || ^8.11.0 || ^9.0.0", - "orchestra/testbench": "^7.33.0 || ^8.13.0 || ^9.0.0", - "phpunit/phpunit": "^9.6.13 || ^10.5" + "nikic/php-parser": "^4.19.1", + "orchestra/canvas": "^7.11.1 || ^8.11.0 || ^9.0.2", + "orchestra/testbench": "^7.33.0 || ^8.13.0 || ^9.0.3", + "phpunit/phpunit": "^9.6.13 || ^10.5.16" }, "suggest": { "orchestra/testbench": "Using Larastan for analysing a package needs Testbench" @@ -17204,7 +17214,7 @@ ], "support": { "issues": "https://github.com/larastan/larastan/issues", - "source": "https://github.com/larastan/larastan/tree/v2.9.2" + "source": "https://github.com/larastan/larastan/tree/v2.9.5" }, "funding": [ { @@ -17224,7 +17234,7 @@ "type": "patreon" } ], - "time": "2024-02-27T03:16:03+00:00" + "time": "2024-04-16T19:13:34+00:00" }, { "name": "maximebf/debugbar", @@ -17740,16 +17750,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.10.66", + "version": "1.10.67", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "94779c987e4ebd620025d9e5fdd23323903950bd" + "reference": "16ddbe776f10da6a95ebd25de7c1dbed397dc493" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/94779c987e4ebd620025d9e5fdd23323903950bd", - "reference": "94779c987e4ebd620025d9e5fdd23323903950bd", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/16ddbe776f10da6a95ebd25de7c1dbed397dc493", + "reference": "16ddbe776f10da6a95ebd25de7c1dbed397dc493", "shasum": "" }, "require": { @@ -17792,13 +17802,9 @@ { "url": "https://github.com/phpstan", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", - "type": "tidelift" } ], - "time": "2024-03-28T16:17:31+00:00" + "time": "2024-04-16T07:22:02+00:00" }, { "name": "phpunit/php-code-coverage", @@ -18123,16 +18129,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.5.17", + "version": "10.5.19", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "c1f736a473d21957ead7e94fcc029f571895abf5" + "reference": "c726f0de022368f6ed103e452a765d3304a996a4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c1f736a473d21957ead7e94fcc029f571895abf5", - "reference": "c1f736a473d21957ead7e94fcc029f571895abf5", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c726f0de022368f6ed103e452a765d3304a996a4", + "reference": "c726f0de022368f6ed103e452a765d3304a996a4", "shasum": "" }, "require": { @@ -18204,7 +18210,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.17" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.19" }, "funding": [ { @@ -18220,7 +18226,7 @@ "type": "tidelift" } ], - "time": "2024-04-05T04:39:01+00:00" + "time": "2024-04-17T14:06:18+00:00" }, { "name": "sebastian/cli-parser", @@ -19271,16 +19277,16 @@ }, { "name": "spatie/ignition", - "version": "1.13.1", + "version": "1.13.2", "source": { "type": "git", "url": "https://github.com/spatie/ignition.git", - "reference": "889bf1dfa59e161590f677728b47bf4a6893983b" + "reference": "952798e239d9969e4e694b124c2cc222798dbb28" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/ignition/zipball/889bf1dfa59e161590f677728b47bf4a6893983b", - "reference": "889bf1dfa59e161590f677728b47bf4a6893983b", + "url": "https://api.github.com/repos/spatie/ignition/zipball/952798e239d9969e4e694b124c2cc222798dbb28", + "reference": "952798e239d9969e4e694b124c2cc222798dbb28", "shasum": "" }, "require": { @@ -19350,20 +19356,20 @@ "type": "github" } ], - "time": "2024-03-29T14:03:47+00:00" + "time": "2024-04-16T08:49:17+00:00" }, { "name": "spatie/laravel-ignition", - "version": "2.5.1", + "version": "2.5.2", "source": { "type": "git", "url": "https://github.com/spatie/laravel-ignition.git", - "reference": "0c864b3cbd66ce67a2096c5f743e07ce8f1d6ab9" + "reference": "c93fcadcc4629775c839ac9a90916f07a660266f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-ignition/zipball/0c864b3cbd66ce67a2096c5f743e07ce8f1d6ab9", - "reference": "0c864b3cbd66ce67a2096c5f743e07ce8f1d6ab9", + "url": "https://api.github.com/repos/spatie/laravel-ignition/zipball/c93fcadcc4629775c839ac9a90916f07a660266f", + "reference": "c93fcadcc4629775c839ac9a90916f07a660266f", "shasum": "" }, "require": { @@ -19373,7 +19379,7 @@ "illuminate/support": "^10.0|^11.0", "php": "^8.1", "spatie/flare-client-php": "^1.3.5", - "spatie/ignition": "^1.13", + "spatie/ignition": "^1.13.2", "symfony/console": "^6.2.3|^7.0", "symfony/var-dumper": "^6.2.3|^7.0" }, @@ -19442,7 +19448,7 @@ "type": "github" } ], - "time": "2024-04-02T06:30:22+00:00" + "time": "2024-04-16T08:57:16+00:00" }, { "name": "spaze/phpstan-stripe", diff --git a/resources/views/portal/ninja2020/gateways/paypal/ppcp/card.blade.php b/resources/views/portal/ninja2020/gateways/paypal/ppcp/card.blade.php index dc40aa436b..55b4c3cc11 100644 --- a/resources/views/portal/ninja2020/gateways/paypal/ppcp/card.blade.php +++ b/resources/views/portal/ninja2020/gateways/paypal/ppcp/card.blade.php @@ -50,9 +50,10 @@ @include('portal.ninja2020.gateways.includes.save_card') + @include('portal.ninja2020.gateways.includes.pay_now', ['id' => 'pay-now']) - @include('portal.ninja2020.gateways.includes.pay_now') + @include('portal.ninja2020.gateways.includes.pay_now', ['id' => 'pay-now-token']) @endsection @@ -232,7 +233,9 @@ document .getElementById('save-card--container').style.display = 'none'; document - .getElementById('checkout-form').style.display = 'none'; + .getElementById('checkout-form').classList.add('hidden'); + document + .getElementById('pay-now-token').classList.remove('hidden'); document .getElementById('token').value = e.target.dataset.token; @@ -243,14 +246,21 @@ if (payWithCreditCardToggle) { payWithCreditCardToggle .addEventListener('click', () => { + console.log("Cc"); document .getElementById('save-card--container').style.display = 'grid'; + document + .getElementById('checkout-form').classList.remove('hidden'); + + document + .getElementById('pay-now-token').classList.add('hidden'); + document .getElementById('token').value = null; }); } - let payNowButton = document.getElementById('pay-now'); + let payNowButton = document.getElementById('pay-now-token'); if (payNowButton) { payNowButton @@ -260,7 +270,7 @@ document.getElementById("token").value = token.value; } - document.getElementById("gateway_response").value = JSON.stringify( data ); + document.getElementById("gateway_response").value = JSON.stringify( {token: token.value, orderID: "{!! $order_id !!}"} ); document.getElementById("server_response").submit(); }); From 4921eadc891db6e60d3e18f2e12565a95acc1d92 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 23 Apr 2024 12:45:43 +1000 Subject: [PATCH 07/11] Updates for client reports --- app/Export/CSV/ClientExport.php | 13 ++++- app/Http/Controllers/EmailController.php | 2 +- .../PayPalRestPaymentDriver.php | 2 +- app/PaymentDrivers/Stripe/BankTransfer.php | 26 ++++++++- app/PaymentDrivers/StripePaymentDriver.php | 3 +- .../bank_transfer/bank_details.blade.php | 54 ++++++++++++++++++- 6 files changed, 93 insertions(+), 7 deletions(-) diff --git a/app/Export/CSV/ClientExport.php b/app/Export/CSV/ClientExport.php index c579b34eea..dda304bc99 100644 --- a/app/Export/CSV/ClientExport.php +++ b/app/Export/CSV/ClientExport.php @@ -41,7 +41,6 @@ class ClientExport extends BaseExport 'balance' => 'client.balance', 'city' => 'client.city', 'country' => 'client.country_id', - 'credit_balance' => 'client.credit_balance', 'custom_value1' => 'client.custom_value1', 'custom_value2' => 'client.custom_value2', 'custom_value3' => 'client.custom_value3', @@ -229,6 +228,18 @@ class ClientExport extends BaseExport $entity['client.classification'] = ctrans("texts.{$client->classification}") ?? ''; } + if (in_array('client.industry_id', $this->input['report_keys']) && isset($client->industry_id)) { + $entity['client.industry_id'] = ctrans("texts.industry_{$client->industry->name}") ?? ''; + } + + if (in_array('client.country_id', $this->input['report_keys']) && isset($client->country_id)) { + $entity['client.country_id'] = $client->country->full_name; + } + + if (in_array('client.shipping_country_id', $this->input['report_keys']) && isset($client->shipping_country_id)) { + $entity['client.shipping_country_id'] = $client->shipping_country->full_name; + } + return $entity; } diff --git a/app/Http/Controllers/EmailController.php b/app/Http/Controllers/EmailController.php index e6a837ec64..06cda32333 100644 --- a/app/Http/Controllers/EmailController.php +++ b/app/Http/Controllers/EmailController.php @@ -70,7 +70,7 @@ class EmailController extends BaseController /** @var \App\Models\User $user */ $user = auth()->user(); - if ($request->cc_email && (Ninja::isSelfHost() || $user->account->isPaidHostedClient())) { + if ($request->cc_email && (Ninja::isSelfHost() || $user->account->isPremium())) { foreach($request->cc_email as $email) { $mo->cc[] = new Address($email); diff --git a/app/PaymentDrivers/PayPalRestPaymentDriver.php b/app/PaymentDrivers/PayPalRestPaymentDriver.php index 247d586843..15846cbcc9 100644 --- a/app/PaymentDrivers/PayPalRestPaymentDriver.php +++ b/app/PaymentDrivers/PayPalRestPaymentDriver.php @@ -251,7 +251,7 @@ return render('gateways.paypal.ppcp.card', $data); nlog($response); $data = [ - 'payment_type' => $this->getPaymentMethod($this->gateway_type_id), + 'payment_type' => $this->getPaymentMethod($request->gateway_type_id), 'amount' => $response['purchase_units'][0]['payments']['captures'][0]['amount']['value'], 'transaction_reference' => $response['purchase_units'][0]['payments']['captures'][0]['id'], 'gateway_type_id' => $this->gateway_type_id, diff --git a/app/PaymentDrivers/Stripe/BankTransfer.php b/app/PaymentDrivers/Stripe/BankTransfer.php index acea334a01..d5f02d0858 100644 --- a/app/PaymentDrivers/Stripe/BankTransfer.php +++ b/app/PaymentDrivers/Stripe/BankTransfer.php @@ -76,7 +76,7 @@ class BankTransfer /** * Resolve the bank type based on the currency * - * @return void + * @return array */ private function resolveBankType() { @@ -85,6 +85,7 @@ class BankTransfer 'EUR' => ['type' => 'eu_bank_transfer', 'eu_bank_transfer' => ['country' => $this->stripe->client->country->iso_3166_2]], 'JPY' => ['type' => 'jp_bank_transfer'], 'MXN' => ['type' => 'mx_bank_transfer'], + 'USD' => ['type' => 'us_bank_transfer'], }; } @@ -133,6 +134,7 @@ class BankTransfer 'gbp' => $data['bank_details'] = $this->formatDataforUk($pi), 'eur' => $data['bank_details'] = $this->formatDataforEur($pi), 'jpy' => $data['bank_details'] = $this->formatDataforJp($pi), + 'usd' => $data['bank_details'] = $this->formatDataforUs($pi), }; $payment = $this->processSuccesfulRedirect($pi); @@ -233,6 +235,28 @@ class BankTransfer } + /** + * + * @param PaymentIntent $pi + * @return array + */ + public function formatDataforUs(PaymentIntent $pi): array + { + return [ + 'amount' => Number::formatMoney($this->stripe->convertFromStripeAmount($pi->next_action->display_bank_transfer_instructions->amount_remaining, $this->stripe->client->currency()->precision, $this->stripe->client->currency()), $this->stripe->client), + 'account_holder_name' => $pi->next_action->display_bank_transfer_instructions->financial_addresses[0]->aba->bank_name, + 'account_number' => $pi->next_action->display_bank_transfer_instructions->financial_addresses[0]->aba->account_number, + 'bank_name' => $pi->next_action->display_bank_transfer_instructions->financial_addresses[0]->aba->bank_name, + 'sort_code' => $pi->next_action->display_bank_transfer_instructions->financial_addresses[0]->aba->routing_number, + 'reference' => $pi->next_action->display_bank_transfer_instructions->reference, + 'description' => $pi->description, + 'gateway' => $this->stripe->company_gateway, + 'currency' => $pi->next_action->display_bank_transfer_instructions->currency, + + ]; + } + + /** * processSuccesfulRedirect * diff --git a/app/PaymentDrivers/StripePaymentDriver.php b/app/PaymentDrivers/StripePaymentDriver.php index c0d35cc59e..92f98bb5b6 100644 --- a/app/PaymentDrivers/StripePaymentDriver.php +++ b/app/PaymentDrivers/StripePaymentDriver.php @@ -271,7 +271,8 @@ class StripePaymentDriver extends BaseDriver (in_array($this->client->country->iso_3166_2, ['FR', 'IE', 'NL', 'DE', 'ES']) && $this->client->currency()->code == 'EUR') || ($this->client->country->iso_3166_2 == 'JP' && $this->client->currency()->code == 'JPY') || ($this->client->country->iso_3166_2 == 'MX' && $this->client->currency()->code == 'MXN') || - ($this->client->country->iso_3166_2 == 'GB' && $this->client->currency()->code == 'GBP') + ($this->client->country->iso_3166_2 == 'GB' && $this->client->currency()->code == 'GBP') || + ($this->client->country->iso_3166_2 == 'US' && $this->client->currency()->code == 'USD') ) ) { $types[] = GatewayType::DIRECT_DEBIT; diff --git a/resources/views/portal/ninja2020/gateways/stripe/bank_transfer/bank_details.blade.php b/resources/views/portal/ninja2020/gateways/stripe/bank_transfer/bank_details.blade.php index 82d1d4a2fd..21fd2d92f9 100644 --- a/resources/views/portal/ninja2020/gateways/stripe/bank_transfer/bank_details.blade.php +++ b/resources/views/portal/ninja2020/gateways/stripe/bank_transfer/bank_details.blade.php @@ -172,7 +172,7 @@ @elseif($bank_details['currency'] == 'eur') -
+
{{ ctrans('texts.account_name') }}
@@ -214,7 +214,57 @@ {{ ctrans('texts.stripe_direct_debit_details') }}
- @endif + @elseif($bank_details['currency'] == 'usd') + +
+ {{ ctrans('texts.bank_name') }} +
+
+ {{ $bank_details['bank_name'] }} +
+ +
+ {{ ctrans('texts.account_number') }} +
+
+ {{ $bank_details['account_number'] }} +
+ +
+ {{ ctrans('texts.routing_number') }} +
+
+ {{ $bank_details['sort_code'] }} +
+ +
+ {{ ctrans('texts.reference') }} +
+
+ {{ $bank_details['reference'] }} +
+ +
+ Network +
+
+ ACH / Domestic Wire US +
+ +
+ {{ ctrans('texts.balance_due') }} +
+
+ {{ $bank_details['amount'] }} +
+ +
+
+
+ {{ ctrans('texts.stripe_direct_debit_details') }} +
+ + @endif From 402ac09c22adb0f8b3ab956a9143d6bbbda9e669 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 24 Apr 2024 07:19:56 +1000 Subject: [PATCH 08/11] Remove references from .env.example --- .env.example | 9 --------- app/Http/ValidationRules/Ninja/CanAddUserRule.php | 14 -------------- 2 files changed, 23 deletions(-) diff --git a/.env.example b/.env.example index ea1f4a3207..e9d4cec8ed 100644 --- a/.env.example +++ b/.env.example @@ -28,15 +28,6 @@ REDIS_HOST=127.0.0.1 REDIS_PASSWORD=null REDIS_PORT=6379 -MAIL_MAILER=smtp -MAIL_HOST=smtp.mailtrap.io -MAIL_PORT=2525 -MAIL_USERNAME=null -MAIL_PASSWORD=null -MAIL_ENCRYPTION=null -MAIL_FROM_ADDRESS="user@example.com" -MAIL_FROM_NAME="Self Hosted User" - POSTMARK_API_TOKEN= REQUIRE_HTTPS=false diff --git a/app/Http/ValidationRules/Ninja/CanAddUserRule.php b/app/Http/ValidationRules/Ninja/CanAddUserRule.php index 64e1281c8d..dfdddfe638 100644 --- a/app/Http/ValidationRules/Ninja/CanAddUserRule.php +++ b/app/Http/ValidationRules/Ninja/CanAddUserRule.php @@ -39,20 +39,6 @@ class CanAddUserRule implements Rule return true; } - /* - Check that we have sufficient quota to allow this to happen - - @ 31-01-2024 - changed query to use email instead of user_id - - $count = CompanyUser::query() - ->where('company_user.account_id', $user->account_id) - ->join('users', 'users.id', '=', 'company_user.user_id') - ->whereNull('users.deleted_at') - ->whereNull('company_user.deleted_at') - ->distinct() - ->count('company_user.user_id'); - */ - $count = CompanyUser::query() ->where("company_user.account_id", $user->account_id) ->join("users", "users.id", "=", "company_user.user_id") From 0bd5a9db0c07e6621ccbd2fa5f7048b982d27538 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 24 Apr 2024 09:21:00 +1000 Subject: [PATCH 09/11] minor fixes --- app/Export/CSV/ClientExport.php | 8 ++------ app/Http/Controllers/BaseController.php | 2 +- app/Http/Controllers/CompanyGatewayController.php | 1 - app/Models/BaseModel.php | 2 +- .../ninja2020/gateways/paypal/ppcp/card.blade.php | 14 +++++++------- 5 files changed, 11 insertions(+), 16 deletions(-) diff --git a/app/Export/CSV/ClientExport.php b/app/Export/CSV/ClientExport.php index dda304bc99..5a5b439129 100644 --- a/app/Export/CSV/ClientExport.php +++ b/app/Export/CSV/ClientExport.php @@ -178,14 +178,10 @@ class ClientExport extends BaseExport } elseif (is_array($parts) && $parts[0] == 'contact' && array_key_exists($parts[1], $transformed_contact)) { $entity[$key] = $transformed_contact[$parts[1]]; } else { - // nlog($key); $entity[$key] = $this->decorator->transform($key, $client); - // $entity[$key] = ''; } } - // return $entity; - return $this->decorateAdvancedFields($client, $entity); } @@ -233,11 +229,11 @@ class ClientExport extends BaseExport } if (in_array('client.country_id', $this->input['report_keys']) && isset($client->country_id)) { - $entity['client.country_id'] = $client->country->full_name; + $entity['client.country_id'] = $client->country ? $client->country->full_name : ''; } if (in_array('client.shipping_country_id', $this->input['report_keys']) && isset($client->shipping_country_id)) { - $entity['client.shipping_country_id'] = $client->shipping_country->full_name; + $entity['client.shipping_country_id'] = $client->shipping_country ? $client->shipping_country->full_name : ''; } return $entity; diff --git a/app/Http/Controllers/BaseController.php b/app/Http/Controllers/BaseController.php index c8d7d44b8e..fe6485a8ea 100644 --- a/app/Http/Controllers/BaseController.php +++ b/app/Http/Controllers/BaseController.php @@ -276,7 +276,7 @@ class BaseController extends Controller /** * API Error response. * - * @param string $message The return error message + * @param string|array $message The return error message * @param int $httpErrorCode 404/401/403 etc * @return Response The JSON response * @throws BindingResolutionException diff --git a/app/Http/Controllers/CompanyGatewayController.php b/app/Http/Controllers/CompanyGatewayController.php index f55222d21a..fb3726be9d 100644 --- a/app/Http/Controllers/CompanyGatewayController.php +++ b/app/Http/Controllers/CompanyGatewayController.php @@ -565,7 +565,6 @@ class CompanyGatewayController extends BaseController public function importCustomers(TestCompanyGatewayRequest $request, CompanyGateway $company_gateway) { - // $x = Cache::pull("throttle_polling:import_customers:{$company_gateway->company->company_key}:{$company_gateway->hashed_id}"); //Throttle here if (Cache::has("throttle_polling:import_customers:{$company_gateway->company->company_key}:{$company_gateway->hashed_id}")) diff --git a/app/Models/BaseModel.php b/app/Models/BaseModel.php index d90056f820..2e6e810667 100644 --- a/app/Models/BaseModel.php +++ b/app/Models/BaseModel.php @@ -209,7 +209,7 @@ class BaseModel extends Model * Retrieve the model for a bound value. * * @param mixed $value - * @param null $field + * @param mixed $field * @return Model|null */ public function resolveRouteBinding($value, $field = null) diff --git a/resources/views/portal/ninja2020/gateways/paypal/ppcp/card.blade.php b/resources/views/portal/ninja2020/gateways/paypal/ppcp/card.blade.php index 55b4c3cc11..f303968082 100644 --- a/resources/views/portal/ninja2020/gateways/paypal/ppcp/card.blade.php +++ b/resources/views/portal/ninja2020/gateways/paypal/ppcp/card.blade.php @@ -97,10 +97,10 @@ if(liabilityShift) { /* Handle liability shift. More information in 3D Secure response parameters */ - // console.log("inside liability shift") - // console.log(liabilityShift) - // console.log(orderID); - // console.log(data); + console.log("inside liability shift") + console.log(liabilityShift) + console.log(orderID); + console.log(data); //doesn't really do anything as failure is linked in SUBMIT. We only hit here after a successful return //and where SCA is optional? @@ -175,7 +175,7 @@ expiryField.render("#card-expiry-field-container"); document.getElementById("pay-now").addEventListener('click', (e) => { - + console.log("paynow"); document.getElementById('errors').textContent = ''; document.getElementById('errors').hidden = true; @@ -189,8 +189,8 @@ document.querySelector('#pay-now > span').classList.add('hidden'); cardField.submit().then((response) => { - // console.log("then"); - // console.log(response); + console.log("then"); + console.log(response); }).catch((error) => { From 4739b659246c3a082c1f879c948d9c0f54766720 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 24 Apr 2024 16:32:28 +1000 Subject: [PATCH 10/11] v5.8.51 --- VERSION.txt | 2 +- config/ninja.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/VERSION.txt b/VERSION.txt index 7314459460..7a2658070e 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -5.8.50 \ No newline at end of file +5.8.51 \ No newline at end of file diff --git a/config/ninja.php b/config/ninja.php index 21ea8fbd49..c0749919e0 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -17,8 +17,8 @@ return [ 'require_https' => env('REQUIRE_HTTPS', true), 'app_url' => rtrim(env('APP_URL', ''), '/'), 'app_domain' => env('APP_DOMAIN', 'invoicing.co'), - 'app_version' => env('APP_VERSION', '5.8.50'), - 'app_tag' => env('APP_TAG', '5.8.50'), + 'app_version' => env('APP_VERSION', '5.8.51'), + 'app_tag' => env('APP_TAG', '5.8.51'), 'minimum_client_version' => '5.0.16', 'terms_version' => '1.0.1', 'api_secret' => env('API_SECRET', false), From 8c0d205a08def1e775b7f85b611bfe5e6c5ff81d Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 24 Apr 2024 16:33:09 +1000 Subject: [PATCH 11/11] v5.8.51 --- app/PaymentDrivers/PayPalRestPaymentDriver.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/PaymentDrivers/PayPalRestPaymentDriver.php b/app/PaymentDrivers/PayPalRestPaymentDriver.php index 15846cbcc9..dd3c5475f3 100644 --- a/app/PaymentDrivers/PayPalRestPaymentDriver.php +++ b/app/PaymentDrivers/PayPalRestPaymentDriver.php @@ -170,9 +170,9 @@ class PayPalRestPaymentDriver extends BaseDriver $data['currency'] = $this->client->currency()->code; -return render('gateways.paypal.ppcp.card', $data); +// return render('gateways.paypal.ppcp.card', $data); -// return render('gateways.paypal.pay', $data); +return render('gateways.paypal.pay', $data); }