mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-11-03 23:27:31 -05:00 
			
		
		
		
	Working on integrating multiple invoice payments
This commit is contained in:
		
							parent
							
								
									73c1f1b767
								
							
						
					
					
						commit
						01312996d8
					
				@ -78,6 +78,7 @@ class InvoiceController extends Controller
 | 
			
		||||
            'key' => $invitation ? $invitation->key : false,
 | 
			
		||||
            'hash' => $hash,
 | 
			
		||||
            'variables' => $variables,
 | 
			
		||||
            'invoices' => [$invoice->hashed_id],
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        if ($request->query('mode') === 'fullscreen') {
 | 
			
		||||
 | 
			
		||||
@ -27,6 +27,8 @@ class PaymentMethod extends Component
 | 
			
		||||
 | 
			
		||||
    public $isLoading = true;
 | 
			
		||||
 | 
			
		||||
    public $amount = 0;
 | 
			
		||||
 | 
			
		||||
     public function placeholder()
 | 
			
		||||
    {
 | 
			
		||||
        return <<<'HTML'
 | 
			
		||||
@ -43,14 +45,16 @@ class PaymentMethod extends Component
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        $this->invoice = $this->context['invoice'];
 | 
			
		||||
        $this->variables = $this->context['variables'];
 | 
			
		||||
        $invoice_amount = $this->invoice->partial > 0 ? $this->invoice->partial : $this->invoice->balance;
 | 
			
		||||
 | 
			
		||||
        $this->variables = $this->context['variables'];
 | 
			
		||||
        $this->amount = isset($this->context['payable_invoices']) ? array_sum(array_column($this->context['payable_invoices'], 'amount')) : $invoice_amount;
 | 
			
		||||
        MultiDB::setDb($this->invoice->company->db);
 | 
			
		||||
 | 
			
		||||
        $this->methods = $this->invoice->client->service()->getPaymentMethods($this->invoice->balance);
 | 
			
		||||
        $this->methods = $this->invoice->client->service()->getPaymentMethods($this->amount);
 | 
			
		||||
 | 
			
		||||
        if(count($this->methods) == 1) {
 | 
			
		||||
            $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);
 | 
			
		||||
            $this->dispatch('singlePaymentMethodFound', company_gateway_id: $this->methods[0]['company_gateway_id'], gateway_type_id: $this->methods[0]['gateway_type_id'], amount: $this->amount);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            $this->isLoading = false;
 | 
			
		||||
@ -61,6 +65,6 @@ class PaymentMethod extends Component
 | 
			
		||||
    public function render()
 | 
			
		||||
    { 
 | 
			
		||||
        //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]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -34,9 +34,6 @@ class ProcessPayment extends Component
 | 
			
		||||
    public function mount()
 | 
			
		||||
    {
 | 
			
		||||
         
 | 
			
		||||
        nlog($this->isLoading);
 | 
			
		||||
 | 
			
		||||
        nlog("inside Process Payment");           
 | 
			
		||||
        MultiDB::setDb($this->context['invoice']->company->db);
 | 
			
		||||
 | 
			
		||||
        $invitation = InvoiceInvitation::find($this->context['invitation_id']);
 | 
			
		||||
 | 
			
		||||
@ -28,21 +28,29 @@ class UnderOverPayment extends Component
 | 
			
		||||
 | 
			
		||||
    public $errors = '';
 | 
			
		||||
 | 
			
		||||
    public $payableInvoices = [];
 | 
			
		||||
 | 
			
		||||
    public function mount()
 | 
			
		||||
    {
 | 
			
		||||
        $invoice = $this->context['invoice'];
 | 
			
		||||
        $this->invoice_amount = $invoice->partial > 0 ? $invoice->partial : $invoice->balance;
 | 
			
		||||
        $this->currency = $invoice->client->currency();
 | 
			
		||||
        $this->payableAmount = Number::formatValue($this->invoice_amount, $this->currency);
 | 
			
		||||
        
 | 
			
		||||
        $this->invoice_amount = array_sum(array_column($this->context['payable_invoices'], 'amount'));
 | 
			
		||||
        $this->currency = $this->context['invitation']->contact->client->currency();
 | 
			
		||||
        $this->payableInvoices = $this->context['payable_invoices'];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function checkValue($value)
 | 
			
		||||
    public function checkValue(array $payableInvoices)
 | 
			
		||||
    {
 | 
			
		||||
        nlog($payableInvoices);
 | 
			
		||||
 | 
			
		||||
        $this->errors = '';
 | 
			
		||||
 | 
			
		||||
        $settings = $this->context['settings'];
 | 
			
		||||
        $input_amount = Number::parseFloat($value);
 | 
			
		||||
        $input_amount = 0;
 | 
			
		||||
 | 
			
		||||
        foreach($payableInvoices as $invoice)
 | 
			
		||||
            $input_amount += Number::parseFloat($invoice['formatted_amount']);
 | 
			
		||||
 | 
			
		||||
        nlog($input_amount);
 | 
			
		||||
 | 
			
		||||
        if($settings->client_portal_allow_under_payment && $settings->client_portal_under_payment_minimum != 0)
 | 
			
		||||
        {
 | 
			
		||||
@ -60,12 +68,11 @@ class UnderOverPayment extends Component
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(!$this->errors)
 | 
			
		||||
            $this->dispatch('payable-amount',  payable_amount: $value );
 | 
			
		||||
            $this->dispatch('payable-amount',  payable_amount: $input_amount );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function render()
 | 
			
		||||
    {
 | 
			
		||||
        
 | 
			
		||||
        return render('components.livewire.under-over-payments',[
 | 
			
		||||
            'settings' => $this->context['settings'],
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
@ -23,12 +23,22 @@ use Livewire\Attributes\Reactive;
 | 
			
		||||
use App\Livewire\Flow2\PaymentMethod;
 | 
			
		||||
use App\Livewire\Flow2\ProcessPayment;
 | 
			
		||||
use App\Livewire\Flow2\UnderOverPayment;
 | 
			
		||||
use App\Models\Invoice;
 | 
			
		||||
use App\Utils\Number;
 | 
			
		||||
use App\Utils\Traits\MakesDates;
 | 
			
		||||
use App\Utils\Traits\MakesHash;
 | 
			
		||||
 | 
			
		||||
class InvoicePay extends Component
 | 
			
		||||
{
 | 
			
		||||
    use MakesDates;
 | 
			
		||||
    use MakesHash;
 | 
			
		||||
 | 
			
		||||
    public $invitation_id;
 | 
			
		||||
 | 
			
		||||
    public $invoices;
 | 
			
		||||
 | 
			
		||||
    public $variables;
 | 
			
		||||
 | 
			
		||||
    public $db;
 | 
			
		||||
 | 
			
		||||
    public $settings;
 | 
			
		||||
@ -86,7 +96,7 @@ class InvoicePay extends Component
 | 
			
		||||
    #[On('payment-method-selected')]
 | 
			
		||||
    public function paymentMethodSelected($company_gateway_id, $gateway_type_id, $amount)
 | 
			
		||||
    {       
 | 
			
		||||
        nlog("payment method selected inside InvoicePay");
 | 
			
		||||
        //@TODO only handles single invoice scenario
 | 
			
		||||
        
 | 
			
		||||
        $this->payment_method_accepted = true;
 | 
			
		||||
 | 
			
		||||
@ -95,11 +105,11 @@ class InvoicePay extends Component
 | 
			
		||||
        $this->context['amount'] = $amount;
 | 
			
		||||
        $this->context['pre_payment'] = false;
 | 
			
		||||
        $this->context['is_recurring'] = false;
 | 
			
		||||
        $this->context['payable_invoices'] = ['invoice_id' => $this->context['invoice']->hashed_id, 'amount' => $this->context['invoice']->balance];
 | 
			
		||||
 | 
			
		||||
        // $this->context['payable_invoices'] = ['invoice_id' => $this->context['invoice']->hashed_id, 'amount' => $amount];
 | 
			
		||||
        
 | 
			
		||||
        $this->context['invitation_id'] = $this->invitation_id;
 | 
			
		||||
        
 | 
			
		||||
        // $this->invite = \App\Models\InvoiceInvitation::withTrashed()->find($this->invitation_id)->withoutRelations();
 | 
			
		||||
        $this->component();
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -136,12 +146,23 @@ class InvoicePay extends Component
 | 
			
		||||
        MultiDB::setDb($this->db);
 | 
			
		||||
 | 
			
		||||
        // @phpstan-ignore-next-line
 | 
			
		||||
        $invite = \App\Models\InvoiceInvitation::with('invoice','contact.client','company')->withTrashed()->find($this->invitation_id);
 | 
			
		||||
        $invite = \App\Models\InvoiceInvitation::with('contact.client','company')->withTrashed()->find($this->invitation_id);
 | 
			
		||||
        $client = $invite->contact->client;
 | 
			
		||||
        $variables = ($invite && auth()->guard('contact')->user()->client->getSetting('show_accept_invoice_terms')) ? (new HtmlEngine($invite))->generateLabelsAndValues() : false;
 | 
			
		||||
        $settings = $client->getMergedSettings();
 | 
			
		||||
        $this->context['settings'] = $settings;
 | 
			
		||||
 | 
			
		||||
        $invoices = Invoice::find($this->transformKeys($this->invoices));
 | 
			
		||||
        $invoices = $invoices->filter(function ($i){
 | 
			
		||||
            
 | 
			
		||||
            $i = $i->service()
 | 
			
		||||
                ->markSent()
 | 
			
		||||
                ->removeUnpaidGatewayFees()
 | 
			
		||||
                ->save();
 | 
			
		||||
 | 
			
		||||
            return $i->isPayable();
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        //under-over / payment
 | 
			
		||||
 | 
			
		||||
        //required fields
 | 
			
		||||
@ -151,11 +172,20 @@ class InvoicePay extends Component
 | 
			
		||||
        $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['invoice'] = $invite->invoice;
 | 
			
		||||
        $this->context['variables'] = $this->variables;
 | 
			
		||||
        $this->context['invoices'] = $invoices;
 | 
			
		||||
        $this->context['settings'] = $settings;
 | 
			
		||||
        $this->context['invitation'] = $invite;
 | 
			
		||||
 | 
			
		||||
        $this->context['payable_invoices'] = ['invoice_id' => $this->context['invoice']->hashed_id, 'amount' => $invite->invoice->partial > 0 ? $invite->invoice->partial : $invite->invoice->balance];
 | 
			
		||||
        $this->context['payable_invoices'] = $invoices->map(function ($i){
 | 
			
		||||
            return [
 | 
			
		||||
                'invoice_id' => $i->hashed_id,
 | 
			
		||||
                'amount' => $i->partial > 0 ? $i->partial : $i->balance,
 | 
			
		||||
                'formatted_amount' => Number::formatValue($i->partial > 0 ? $i->partial : $i->balance, $i->client->currency()),
 | 
			
		||||
                'number' => $i->number,
 | 
			
		||||
                'date' => $i->translateDate($i->date, $i->client->date_format(), $i->client->locale())
 | 
			
		||||
            ];
 | 
			
		||||
        })->toArray();
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -22,7 +22,8 @@ class InvoiceSummary extends Component
 | 
			
		||||
 | 
			
		||||
    public function mount()
 | 
			
		||||
    {
 | 
			
		||||
        $this->invoice = $this->context['invoice'];
 | 
			
		||||
        //@TODO for a single invoice - show all details, for multi-invoices, only show the summaries
 | 
			
		||||
        $this->invoice = $this->context['invitation']->invoice;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function render()
 | 
			
		||||
 | 
			
		||||
@ -102,17 +102,7 @@ class LivewireInstantPayment
 | 
			
		||||
        $invoices = Invoice::query()
 | 
			
		||||
            ->whereIn('id', $this->transformKeys($payable_invoices->pluck('invoice_id')->toArray()))
 | 
			
		||||
            ->withTrashed()
 | 
			
		||||
            ->get()
 | 
			
		||||
            ->filter(function ($invoice){
 | 
			
		||||
 | 
			
		||||
                $invoice = 
 | 
			
		||||
                $invoice->service()
 | 
			
		||||
                        ->markSent()
 | 
			
		||||
                        ->removeUnpaidGatewayFees()
 | 
			
		||||
                        ->save();
 | 
			
		||||
 | 
			
		||||
                return $invoice->isPayable();
 | 
			
		||||
            });
 | 
			
		||||
            ->get();
 | 
			
		||||
 | 
			
		||||
        /* pop non payable invoice from the $payable_invoices array */
 | 
			
		||||
        $payable_invoices = $payable_invoices->filter(function ($payable_invoice) use ($invoices) {
 | 
			
		||||
 | 
			
		||||
@ -1,21 +1,26 @@
 | 
			
		||||
<div x-data="{ payableAmount: '{{ $payableAmount }}', errors: @entangle('errors') }" class="px-4 py-5 bg-white sm:gap-4 sm:px-6">
 | 
			
		||||
<div x-data="{ payableInvoices: @entangle('payableInvoices'), errors: @entangle('errors') }" 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">
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    <template x-for="(invoice, index) in payableInvoices" :key="index">
 | 
			
		||||
            
 | 
			
		||||
        <div class="flex items-center">
 | 
			
		||||
            <label>
 | 
			
		||||
                <span class="mt-2">{{ $currency->code }} ({{ $currency->symbol }})</span>
 | 
			
		||||
                <span x-text="'{{ ctrans('texts.invoice') }} ' + invoice.number" class="mt-2"></span>
 | 
			
		||||
                <span>{{ $currency->code }} ({{ $currency->symbol }})</span>
 | 
			
		||||
                <input
 | 
			
		||||
                    type="text"
 | 
			
		||||
                    class="input mt-0 mr-4 relative"
 | 
			
		||||
                    name="payable_amount"
 | 
			
		||||
                    x-model="payableAmount"
 | 
			
		||||
                    value="{{ $payableAmount }}"/>
 | 
			
		||||
                    name="payable_invoices[]"
 | 
			
		||||
                    x-model="payableInvoices[index].formatted_amount"
 | 
			
		||||
                    />
 | 
			
		||||
            </label>
 | 
			
		||||
        </div>
 | 
			
		||||
    </template>
 | 
			
		||||
        
 | 
			
		||||
    <template x-if="errors.length > 0">
 | 
			
		||||
        <div x-text="errors" class="alert alert-failure mb-4"></div>
 | 
			
		||||
@ -29,7 +34,7 @@
 | 
			
		||||
    <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" 
 | 
			
		||||
            wire:click="checkValue(payableAmount)">
 | 
			
		||||
            wire:click="checkValue(payableInvoices)">
 | 
			
		||||
            <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>
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@
 | 
			
		||||
    @endif
 | 
			
		||||
 | 
			
		||||
    @if($invoice->isPayable())
 | 
			
		||||
        @livewire('invoice-pay', ['invitation_id' => $invitation->id, 'db' => $invoice->company->db])
 | 
			
		||||
        @livewire('invoice-pay', ['invoices' => $invoices, 'invitation_id' => $invitation->id, 'db' => $invoice->company->db, 'variables' => $variables])
 | 
			
		||||
    @endif
 | 
			
		||||
 | 
			
		||||
    @include('portal.ninja2020.components.entity-documents', ['entity' => $invoice])
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user