diff --git a/app/Http/Controllers/ClientPortal/PaymentController.php b/app/Http/Controllers/ClientPortal/PaymentController.php index a2ade63eeeac..d558c28fab85 100644 --- a/app/Http/Controllers/ClientPortal/PaymentController.php +++ b/app/Http/Controllers/ClientPortal/PaymentController.php @@ -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; @@ -99,7 +100,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']); @@ -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; + } + + }); + + } } diff --git a/app/Models/PaymentHash.php b/app/Models/PaymentHash.php index 6c23c88a239f..2e16a8fc2631 100644 --- a/app/Models/PaymentHash.php +++ b/app/Models/PaymentHash.php @@ -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'); + } } diff --git a/app/Services/Client/ClientService.php b/app/Services/Client/ClientService.php index 3cd30b4ea13c..aa77f1d751fb 100644 --- a/app/Services/Client/ClientService.php +++ b/app/Services/Client/ClientService.php @@ -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(); diff --git a/app/Services/Credit/ApplyPayment.php b/app/Services/Credit/ApplyPayment.php new file mode 100644 index 000000000000..52df3db55489 --- /dev/null +++ b/app/Services/Credit/ApplyPayment.php @@ -0,0 +1,97 @@ +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(); + + } + + +} diff --git a/app/Services/Credit/CreditService.php b/app/Services/Credit/CreditService.php index e161ff6c2764..754d74e86288 100644 --- a/app/Services/Credit/CreditService.php +++ b/app/Services/Credit/CreditService.php @@ -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