mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
new payment flow
This commit is contained in:
parent
e1be33314e
commit
6f5a08f87d
@ -25,23 +25,23 @@ class PaymentMethod extends Component
|
|||||||
|
|
||||||
public $methods = [];
|
public $methods = [];
|
||||||
|
|
||||||
public $isLoading = true;
|
public $isLoading = false;
|
||||||
|
|
||||||
public function placeholder()
|
// public function placeholder()
|
||||||
{
|
// {
|
||||||
return <<<'HTML'
|
// return <<<'HTML'
|
||||||
<div class="flex items-center justify-center min-h-screen">
|
// <div class="flex items-center justify-center min-h-screen">
|
||||||
<svg class="animate-spin h-10 w-10 text-gray-500" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
// <svg class="animate-spin h-10 w-10 text-gray-500" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
// <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
// <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||||
</svg>
|
// </svg>
|
||||||
</div>
|
// </div>
|
||||||
HTML;
|
// HTML;
|
||||||
}
|
// }
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
$this->isLoading = true;
|
// $this->isLoading = true;
|
||||||
$this->invoice = $this->context['invoice'];
|
$this->invoice = $this->context['invoice'];
|
||||||
$this->variables = $this->context['variables'];
|
$this->variables = $this->context['variables'];
|
||||||
|
|
||||||
@ -49,20 +49,17 @@ class PaymentMethod extends Component
|
|||||||
|
|
||||||
$this->methods = $this->invoice->client->service()->getPaymentMethods($this->invoice->balance);
|
$this->methods = $this->invoice->client->service()->getPaymentMethods($this->invoice->balance);
|
||||||
|
|
||||||
|
// $this->isLoading = false;
|
||||||
|
// $this->dispatch('loadingCompleted');
|
||||||
|
|
||||||
if(count($this->methods) == 1) {
|
if(count($this->methods) == 1) {
|
||||||
$this->dispatch('payment-method-selected', company_gateway_id: $this->methods[0]['company_gateway_id'], gateway_type_id: $this->methods[0]['gateway_type_id'], amount: $this->invoice->balance);
|
$this->dispatch('singlePaymentMethodFound', company_gateway_id: $this->methods[0]['company_gateway_id'], gateway_type_id: $this->methods[0]['gateway_type_id'], amount: $this->invoice->balance);
|
||||||
}
|
|
||||||
else {
|
|
||||||
$this->isLoading = false;
|
|
||||||
$this->dispatch('loadingCompleted');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
|
|
||||||
//If there is only one payment method, skip display and push straight to the form!!
|
//If there is only one payment method, skip display and push straight to the form!!
|
||||||
return render('components.livewire.payment_method-flow2', ['methods' => $this->methods, 'amount' => $this->invoice->balance]);
|
return render('components.livewire.payment_method-flow2', ['methods' => $this->methods, 'amount' => $this->invoice->balance]);
|
||||||
}
|
}
|
||||||
|
@ -31,18 +31,7 @@ class ProcessPayment extends Component
|
|||||||
|
|
||||||
public $isLoading = true;
|
public $isLoading = true;
|
||||||
|
|
||||||
|
|
||||||
// public function toJSON()
|
|
||||||
// {
|
|
||||||
// nlog("why");
|
|
||||||
// }
|
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
|
||||||
// $this->loadData();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function boot()
|
|
||||||
{
|
{
|
||||||
|
|
||||||
MultiDB::setDb($this->context['invoice']->company->db);
|
MultiDB::setDb($this->context['invoice']->company->db);
|
||||||
@ -68,8 +57,9 @@ class ProcessPayment extends Component
|
|||||||
|
|
||||||
$this->component_view = '';
|
$this->component_view = '';
|
||||||
|
|
||||||
if(!$responder_data['success'])
|
if(!$responder_data['success']) {
|
||||||
throw new PaymentFailed($responder_data['error'], 400);
|
throw new PaymentFailed($responder_data['error'], 400);
|
||||||
|
}
|
||||||
|
|
||||||
$driver = $company_gateway
|
$driver = $company_gateway
|
||||||
->driver($invitation->contact->client)
|
->driver($invitation->contact->client)
|
||||||
@ -116,10 +106,15 @@ class ProcessPayment extends Component
|
|||||||
'company_gateway' => $this->payment_data_payload['company_gateway'],
|
'company_gateway' => $this->payment_data_payload['company_gateway'],
|
||||||
];
|
];
|
||||||
|
|
||||||
// nlog(array_keys($this->payment_data_payload));
|
|
||||||
|
|
||||||
$this->isLoading = false;
|
$this->isLoading = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function boot()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render()
|
public function render()
|
||||||
|
30
app/Livewire/Flow2/RequiredFields.php
Normal file
30
app/Livewire/Flow2/RequiredFields.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2024. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Livewire\Flow2;
|
||||||
|
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class RequiredFields extends Component
|
||||||
|
{
|
||||||
|
public $context;
|
||||||
|
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return render('components.livewire.required-fields');
|
||||||
|
}
|
||||||
|
}
|
42
app/Livewire/Flow2/UnderOverPayment.php
Normal file
42
app/Livewire/Flow2/UnderOverPayment.php
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2024. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Livewire\Flow2;
|
||||||
|
|
||||||
|
use App\Utils\Number;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class UnderOverPayment extends Component
|
||||||
|
{
|
||||||
|
|
||||||
|
public $context;
|
||||||
|
|
||||||
|
public $payableAmount;
|
||||||
|
|
||||||
|
public $currency;
|
||||||
|
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
$invoice = $this->context['invoice'];
|
||||||
|
$invoice_amount = $invoice->partial > 0 ? $invoice->partial : $invoice->balance;
|
||||||
|
$this->currency = $invoice->client->currency();
|
||||||
|
$this->payableAmount = Number::formatValue($invoice_amount, $this->currency);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
|
||||||
|
return render('components.livewire.under-over-payments',[
|
||||||
|
'settings' => $this->context['settings'],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@ -22,6 +22,8 @@ use Livewire\Attributes\Computed;
|
|||||||
use Livewire\Attributes\Reactive;
|
use Livewire\Attributes\Reactive;
|
||||||
use App\Livewire\Flow2\PaymentMethod;
|
use App\Livewire\Flow2\PaymentMethod;
|
||||||
use App\Livewire\Flow2\ProcessPayment;
|
use App\Livewire\Flow2\ProcessPayment;
|
||||||
|
use App\Livewire\Flow2\UnderOverPayment;
|
||||||
|
use App\Utils\Number;
|
||||||
|
|
||||||
class InvoicePay extends Component
|
class InvoicePay extends Component
|
||||||
{
|
{
|
||||||
@ -37,6 +39,12 @@ class InvoicePay extends Component
|
|||||||
|
|
||||||
public $payment_method_accepted = false;
|
public $payment_method_accepted = false;
|
||||||
|
|
||||||
|
public $under_over_payment = false;
|
||||||
|
|
||||||
|
public $required_fields = false;
|
||||||
|
|
||||||
|
public $ready = true;
|
||||||
|
|
||||||
public array $context = [];
|
public array $context = [];
|
||||||
|
|
||||||
#[On('update.context')]
|
#[On('update.context')]
|
||||||
@ -70,9 +78,17 @@ class InvoicePay extends Component
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[On('payable-amount')]
|
||||||
|
public function payableAmount($payable_amount)
|
||||||
|
{
|
||||||
|
$this->context['payable_invoices'][0]['amount'] = Number::parseFloat($payable_amount);
|
||||||
|
$this->under_over_payment = false;
|
||||||
|
}
|
||||||
|
|
||||||
#[On('payment-method-selected')]
|
#[On('payment-method-selected')]
|
||||||
public function paymentMethodSelected($company_gateway_id, $gateway_type_id, $amount)
|
public function paymentMethodSelected($company_gateway_id, $gateway_type_id, $amount)
|
||||||
{
|
{
|
||||||
|
|
||||||
$this->context['company_gateway_id'] = $company_gateway_id;
|
$this->context['company_gateway_id'] = $company_gateway_id;
|
||||||
$this->context['gateway_type_id'] = $gateway_type_id;
|
$this->context['gateway_type_id'] = $gateway_type_id;
|
||||||
$this->context['amount'] = $amount;
|
$this->context['amount'] = $amount;
|
||||||
@ -83,6 +99,8 @@ class InvoicePay extends Component
|
|||||||
|
|
||||||
// $this->invite = \App\Models\InvoiceInvitation::withTrashed()->find($this->invitation_id)->withoutRelations();
|
// $this->invite = \App\Models\InvoiceInvitation::withTrashed()->find($this->invitation_id)->withoutRelations();
|
||||||
$this->payment_method_accepted =true;
|
$this->payment_method_accepted =true;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Computed()]
|
#[Computed()]
|
||||||
@ -94,9 +112,13 @@ class InvoicePay extends Component
|
|||||||
if(!$this->signature_accepted)
|
if(!$this->signature_accepted)
|
||||||
return Signature::class;
|
return Signature::class;
|
||||||
|
|
||||||
|
if($this->under_over_payment)
|
||||||
|
return UnderOverPayment::class;
|
||||||
|
|
||||||
if(!$this->payment_method_accepted)
|
if(!$this->payment_method_accepted)
|
||||||
return PaymentMethod::class;
|
return PaymentMethod::class;
|
||||||
|
|
||||||
|
// if($this->ready)
|
||||||
return ProcessPayment::class;
|
return ProcessPayment::class;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,13 +138,23 @@ class InvoicePay extends Component
|
|||||||
$client = $invite->contact->client;
|
$client = $invite->contact->client;
|
||||||
$variables = ($invite && auth()->guard('contact')->user()->client->getSetting('show_accept_invoice_terms')) ? (new HtmlEngine($invite))->generateLabelsAndValues() : false;
|
$variables = ($invite && auth()->guard('contact')->user()->client->getSetting('show_accept_invoice_terms')) ? (new HtmlEngine($invite))->generateLabelsAndValues() : false;
|
||||||
$settings = $client->getMergedSettings();
|
$settings = $client->getMergedSettings();
|
||||||
|
$this->context['settings'] = $settings;
|
||||||
|
|
||||||
|
//under-over / payment
|
||||||
|
|
||||||
|
//required fields
|
||||||
|
|
||||||
$this->terms_accepted = !$settings->show_accept_invoice_terms;
|
$this->terms_accepted = !$settings->show_accept_invoice_terms;
|
||||||
$this->signature_accepted = !$settings->require_invoice_signature;
|
$this->signature_accepted = !$settings->require_invoice_signature;
|
||||||
|
$this->under_over_payment = $settings->client_portal_allow_over_payment || $settings->client_portal_allow_under_payment;
|
||||||
|
$this->required_fields = false;
|
||||||
|
|
||||||
$this->context['variables'] = $variables;
|
$this->context['variables'] = $variables;
|
||||||
$this->context['invoice'] = $invite->invoice;
|
$this->context['invoice'] = $invite->invoice;
|
||||||
$this->context['settings'] = $settings;
|
$this->context['settings'] = $settings;
|
||||||
|
|
||||||
|
$this->context['payable_invoices'] = ['invoice_id' => $this->context['invoice']->hashed_id, 'amount' => $invite->invoice->partial > 0 ? $invite->invoice->partial : $invite->invoice->balance];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render()
|
public function render()
|
||||||
|
@ -29,6 +29,10 @@
|
|||||||
isLoading = false;
|
isLoading = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Livewire.on('singlePaymentMethodFound', (event) => {
|
||||||
|
$wire.dispatch('payment-method-selected', {company_gateway_id: event.company_gateway_id, gateway_type_id: event.gateway_type_id, amount: event.amount })
|
||||||
|
});
|
||||||
|
|
||||||
const buttons = document.querySelectorAll('.payment-method');
|
const buttons = document.querySelectorAll('.payment-method');
|
||||||
|
|
||||||
buttons.forEach(button => {
|
buttons.forEach(button => {
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
<div>
|
||||||
|
|
||||||
|
</div>
|
@ -0,0 +1,37 @@
|
|||||||
|
<div x-data="{ payableAmount: '{{ $payableAmount }}' }" class="px-4 py-5 bg-white sm:gap-4 sm:px-6">
|
||||||
|
|
||||||
|
<dt class="text-sm font-medium leading-5 text-gray-500">
|
||||||
|
{{ ctrans('texts.payment_amount') }}
|
||||||
|
</dt>
|
||||||
|
<dd class="text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2 flex flex-col">
|
||||||
|
|
||||||
|
<div class="flex items-center">
|
||||||
|
<label>
|
||||||
|
<span class="mt-2">{{ $currency->code }} ({{ $currency->symbol }})</span>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="input mt-0 mr-4 relative"
|
||||||
|
name="payable_amount"
|
||||||
|
x-model="payableAmount"
|
||||||
|
value="{{ $payableAmount }}"/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if($settings->client_portal_allow_under_payment)
|
||||||
|
<span class="mt-1 text-sm text-gray-800">{{ ctrans('texts.minimum_payment') }}: {{ $settings->client_portal_under_payment_minimum }}</span>
|
||||||
|
@endif
|
||||||
|
</dd>
|
||||||
|
|
||||||
|
<div class="bg-white px-4 py-5 flex w-full justify-end">
|
||||||
|
<button
|
||||||
|
class="button button-primary bg-primary payment-method flex items-center justify-center relative py-4"
|
||||||
|
@click="$wire.dispatch('payable-amount', { payable_amount: payableAmount })">
|
||||||
|
<svg class="animate-spin h-5 w-5 text-white hidden" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||||
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||||
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||||
|
</svg>
|
||||||
|
<span>{{ ctrans('texts.next') }}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
Loading…
x
Reference in New Issue
Block a user