From 50b24c55d954ad51aa826caf99052f743b8f6bb4 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 7 Oct 2020 22:03:53 +1100 Subject: [PATCH] Working on applying credits to payments prior to billing via gateway --- app/Models/Client.php | 5 + app/Services/Invoice/AutoBillInvoice.php | 127 +++++++++++++++++++---- database/seeders/RandomDataSeeder.php | 2 +- resources/lang/en/texts.php | 3 + 4 files changed, 118 insertions(+), 19 deletions(-) diff --git a/app/Models/Client.php b/app/Models/Client.php index fcf885357b5f..f651ca1f7725 100644 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -156,6 +156,11 @@ class Client extends BaseModel implements HasLocalePreference ->first(); } + public function credits() + { + return $this->hasMany(Credit::class)->withTrashed(); + } + public function activities() { return $this->hasMany(Activity::class)->orderBy('id', 'desc'); diff --git a/app/Services/Invoice/AutoBillInvoice.php b/app/Services/Invoice/AutoBillInvoice.php index 3dad55c4e8f6..5a927c3daf3b 100644 --- a/app/Services/Invoice/AutoBillInvoice.php +++ b/app/Services/Invoice/AutoBillInvoice.php @@ -30,6 +30,8 @@ class AutoBillInvoice extends AbstractService private $client; + private $payment; + public function __construct(Invoice $invoice) { $this->invoice = $invoice; @@ -39,32 +41,37 @@ class AutoBillInvoice extends AbstractService public function run() { - if (! $this->invoice->isPayable()) { + /* Is the invoice payable? */ + if (! $this->invoice->isPayable()) return $this->invoice; - } - + + /* Mark the invoice as sent */ $this->invoice = $this->invoice->service()->markSent()->save(); - if ($this->invoice->balance > 0) { - $gateway_token = $this->getGateway($this->invoice->balance); //todo what if it is only a partial amount? - } else { + /* Mark the invoice as paid if there is no balance */ + if ((int)$this->invoice->balance == 0) return $this->invoice->service()->markPaid()->save(); - } - if (! $gateway_token || ! $gateway_token->gateway->driver($this->client)->token_billing) { - return $this->invoice; - } + $this->applyCreditPayment(); - if ($this->invoice->partial > 0) { - $fee = $gateway_token->gateway->calcGatewayFee($this->invoice->partial); - // $amount = $this->invoice->partial + $fee; + /* Determine $amount */ + if ($this->invoice->partial > 0) $amount = $this->invoice->partial; - } else { - $fee = $gateway_token->gateway->calcGatewayFee($this->invoice->balance); - // $amount = $this->invoice->balance + $fee; + elseif($this->invoice->balance >0) $amount = $this->invoice->balance; - } + else + return $this->invoice; + $gateway_token = $this->getGateway($amount); + + /* Bail out if no payment methods available */ + if (! $gateway_token || ! $gateway_token->gateway->driver($this->client)->token_billing) + return $this->invoice; + + /* $gateway fee */ + $fee = $gateway_token->gateway->calcGatewayFee($this->invoice->partial); + + /* Build payment hash */ $payment_hash = PaymentHash::create([ 'hash' => Str::random(128), 'data' => ['invoice_id' => $this->invoice->hashed_id, 'amount' => $amount], @@ -72,11 +79,95 @@ class AutoBillInvoice extends AbstractService 'fee_invoice_id' => $this->invoice->id, ]); - $payment = $gateway_token->gateway->driver($this->client)->tokenBilling($gateway_token, $payment_hash); + $payment = $gateway_token->gateway + ->driver($this->client) + ->tokenBilling($gateway_token, $payment_hash); return $this->invoice; } + /** + * Applies credits to a payment prior to push + * to the payment gateway + * + * @return $this + */ + private function applyCreditPayment() + { + + $available_credits = $this->client + ->credits + ->where('is_deleted', false) + ->where('balance', '>', 0) + ->sortBy('created_at'); + + $available_credit_balance = $available_credits->sum('balance'); + + if((int)$available_credit_balance == 0) + return; + + $is_partial_amount = false; + + if ($this->invoice->partial > 0) { + $is_partial_amount = true; + } + + $this->payment = PaymentFactory::create($this->client->company_id, $this->client->user_id); + $this->payment->save(); + + $available_credits->each(function($credit) use($is_partial_amount){ + + + // if($credit->balance >= $amount){ + // //current credit covers the total amount + + // } + //return false to exit each loop + }); + + return $this; + } + + private function buildPayment($credit, $is_partial_amount) + { + if($is_partial_amount) { + + if($this->invoice->partial >= $credit->balance) { + + $amount = $this->invoice->partial - $credit->balance; + $this->invoice->partial -= $amount; + + $this->payment->credits()->attach([ + $credit->id => ['amount' => $amount] + ]); + + $this->applyPaymentToCredit($credit, $amount); + } + } + + } + + + private function applyPaymentToCredit($credit, $amount) + { + + $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 = $amount * -1; + + $credit_items = $credit->line_items; + $credit_items[] = $credit_item; + + $credit->line_items = $credit_items; + + $credit = $credit->calc()->getCredit(); + + + } + /** * Harvests a client gateway token which passes the * necessary filters for an $amount. diff --git a/database/seeders/RandomDataSeeder.php b/database/seeders/RandomDataSeeder.php index e8b98bf6e6c1..109a3832a77f 100644 --- a/database/seeders/RandomDataSeeder.php +++ b/database/seeders/RandomDataSeeder.php @@ -214,7 +214,7 @@ class RandomDataSeeder extends Seeder $invoice->ledger()->updateInvoiceBalance($invoice->balance); if (rand(0, 1)) { - $payment = App\Models\Payment::create([ + $payment = Payment::create([ 'date' => now(), 'user_id' => $user->id, 'company_id' => $company->id, diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 4d5e8e7e77eb..57881f1c32b5 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -3281,4 +3281,7 @@ return [ 'paused' => 'Paused', 'saved_at' => 'Saved at :time', + 'credit_payment' => 'Credit applied to Invoice :invoice_number', + + ];