1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-05 18:52:44 +01:00

Working on credit payments

This commit is contained in:
David Bomba 2020-10-13 23:28:30 +11:00
parent 96750d5fdb
commit 080c82770e
5 changed files with 169 additions and 4 deletions

View File

@ -12,6 +12,7 @@
namespace App\Http\Controllers\ClientPortal;
use App\Factory\PaymentFactory;
use App\Http\Controllers\Controller;
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
use App\Jobs\Invoice\InjectSignature;
@ -100,7 +101,6 @@ class PaymentController extends Controller
/*iterate through invoices and add gateway fees and other payment metadata*/
$payable_invoices = $payable_invoices->map(function($payable_invoice) use($invoices, $settings){
$payable_invoice['amount'] = Number::parseFloat($payable_invoice['amount']);
$invoice = $invoices->first(function ($inv) use ($payable_invoice) {
@ -159,8 +159,6 @@ class PaymentController extends Controller
});
if ((bool) request()->signature) {
$invoices->each(function ($invoice) {
InjectSignature::dispatch($invoice, request()->signature);
@ -189,7 +187,7 @@ class PaymentController extends Controller
$payment_hash = new PaymentHash;
$payment_hash->hash = Str::random(128);
$payment_hash->data = $payable_invoices;
$payment_hash->data = $payable_invoices->toArray();
$payment_hash->fee_total = $fee_totals;
$payment_hash->fee_invoice_id = $first_invoice->id;
$payment_hash->save();
@ -230,5 +228,46 @@ class PaymentController extends Controller
public function credit_response(Request $request)
{
$payment_hash = PaymentHash::find($request->input('payment_hash'));
if($payment_hash->payment->exists())
$payment = $payment_hash->payment;
else {
$payment = PaymentFactory::create($payment_hash->fee_invoice->company_id, $payment_hash->fee_invoice->user_id)->save();
$payment_hash->payment_id = $payment->id;
$payment_hash->save();
}
collect($payment_hash->invoices())->each(function ($payable_invoice) use ($payment, $payment_hash){
$invoice = Invoice::find($this->decodePrimaryKey($payable_invoice['invoice_id']));
$amount = $payable_invoice['amount'];
$credits = $payment_hash->fee_invoice
->client
->service()
->getCredits();
foreach($credits as $credit)
{
//starting invoice balance
$invoice_balance = $invoice->balance;
//credit payment applied
$invoice = $credit->service()->applyPayment($invoice, $amount, $payment);
//amount paid from invoice calculated
$remaining_balance = ($invoice_balance - $invoice->balance);
//reduce the amount to be paid on the invoice from the NEXT credit
$amount -= $remaining_balance;
//break if the invoice is no longer PAYABLE OR there is no more amount to be applied
if(!$invoice->isPayable() || (int)$amount == 0)
break;
}
});
}
}

View File

@ -25,4 +25,14 @@ class PaymentHash extends Model
{
return $this->data;
}
public function payment()
{
return $this->belongsTo(Payment::class)->withTrashed();
}
public function fee_invoice()
{
return $this->belongsTo(Invoice::class, 'fee_invoice_id', 'id');
}
}

View File

@ -54,6 +54,17 @@ class ClientService
return Number::roundValue($credits->sum('balance'), $this->client->currency()->precision);
}
public function getCredits() :float
{
return $this->client->credits
->where('is_deleted', false)
->where('balance', '>', 0)
->sortBy('created_at');
}
public function save() :Client
{
$this->client->save();

View File

@ -0,0 +1,97 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Services\Credit;
use App\DataMapper\InvoiceItem;
use App\Models\Credit;
use App\Models\Invoice;
use App\Models\Payment;
class ApplyPayment
{
private $credit;
private $invoice;
private $amount;
private $amount_applied;
private $payment;
public function __construct(Credit $credit, Invoice $invoice, float $amount, Payment $payment)
{
$this->credit = $credit;
$this->invoice = $invoice;
$this->amount = $amount;
$this->amount_applied = 0;
$this->payment = $payment->fresh();
}
public function run() :Invoice
{
//$available_credit_balance = $this->credit->balance;
$applicable_amount = min($this->amount, $this->credit->balance);
//check invoice partial for amount to be cleared first
if($this->invoice->partial > 0){
$partial_payment = min($this->invoice->partial, $applicable_amount);
$this->invoice->partial -= $partial_payment;
$this->invoice->balance -= $partial_payment;
$this->amount -= $partial_payment;
// $this->credit->balance -= $partial_payment;
$applicable_amount -= $partial_payment;
$this->amount_applied += $partial_payment;
}
if($this->amount > 0 && $applicable_amount > 0 && $this->invoice->balance > 0){
$balance_payment = min($this->invoice->balance, $this->amount);
$this->invoice->balance -= $balance_payment;
$this->amount -= $balance_payment;
// $this->credit->balance -= $balance_payment;
$this->amount_applied += $balance_payment;
}
return $this->invoice;
}
private function applyPaymentToCredit()
{
$credit_item = new InvoiceItem;
$credit_item->type_id = '1';
$credit_item->product_key = ctrans('texts.credit');
$credit_item->notes = ctrans('texts.credit_payment', ['invoice_number' => $this->invoice->number]);
$credit_item->quantity = 1;
$credit_item->cost = $this->amount_applied * -1;
$credit_items = $credit->line_items;
$credit_items[] = $credit_item;
$this->credit->line_items = $credit_items;
$this->credit = $this->credit->calc()->getCredit();
$this->credit->save();
}
}

View File

@ -12,6 +12,7 @@
namespace App\Services\Credit;
use App\Models\Credit;
use App\Services\Credit\ApplyPayment;
use App\Services\Credit\CreateInvitations;
use App\Services\Credit\MarkSent;
@ -61,6 +62,13 @@ class CreditService
return $this;
}
public function applyPayment($invoice, $amount, $payment)
{
$this->credit = (new ApplyPayment($this->client, $invoice, $amount, $payment))->run();
return $this;
}
/**
* Saves the credit.
* @return Credit object