From 05fafb2f0ecd248e47ece4c752f178a33aff9b64 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 13 Aug 2021 11:30:48 +1000 Subject: [PATCH] Apply payment amount --- app/Services/Invoice/ApplyPaymentAmount.php | 128 ++++++++++++++++++++ app/Services/Invoice/InvoiceService.php | 8 ++ app/Services/Invoice/TriggeredActions.php | 5 + tests/Feature/InvoiceAmountPaymentTest.php | 114 +++++++++++++++++ 4 files changed, 255 insertions(+) create mode 100644 app/Services/Invoice/ApplyPaymentAmount.php create mode 100644 tests/Feature/InvoiceAmountPaymentTest.php diff --git a/app/Services/Invoice/ApplyPaymentAmount.php b/app/Services/Invoice/ApplyPaymentAmount.php new file mode 100644 index 000000000000..2671b6209977 --- /dev/null +++ b/app/Services/Invoice/ApplyPaymentAmount.php @@ -0,0 +1,128 @@ +invoice = $invoice; + $this->amount = $amount; + } + + public function run() + { + if ($this->invoice->status_id == Invoice::STATUS_DRAFT) { + $this->invoice->service()->markSent(); + } + + /*Don't double pay*/ + if ($this->invoice->statud_id == Invoice::STATUS_PAID) { + return $this->invoice; + } + + if($this->amount == 0) + return $this->invoice; + + /* Create Payment */ + $payment = PaymentFactory::create($this->invoice->company_id, $this->invoice->user_id); + + $payment->amount = $this->amount; + $payment->applied = min($this->amount, $this->invoice->balance); + $payment->number = $this->getNextPaymentNumber($this->invoice->client); + $payment->status_id = Payment::STATUS_COMPLETED; + $payment->client_id = $this->invoice->client_id; + $payment->transaction_reference = ctrans('texts.manual_entry'); + $payment->currency_id = $this->invoice->client->getSetting('currency_id'); + $payment->is_manual = true; + /* Create a payment relationship to the invoice entity */ + $payment->save(); + + $this->setExchangeRate($payment); + + $payment->invoices()->attach($this->invoice->id, [ + 'amount' => $payment->amount, + ]); + + $this->invoice->next_send_date = null; + + $this->invoice->service() + ->setExchangeRate() + ->updateBalance($payment->amount * -1) + ->updatePaidToDate($payment->amount) + ->setCalculatedStatus() + ->applyNumber() + ->deletePdf() + ->save(); + + if ($this->invoice->client->getSetting('client_manual_payment_notification')) + $payment->service()->sendEmail(); + + /* Update Invoice balance */ + event(new PaymentWasCreated($payment, $payment->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null))); + event(new InvoiceWasPaid($this->invoice, $payment, $payment->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null))); + + $payment->ledger() + ->updatePaymentBalance($payment->amount * -1); + + $this->invoice + ->client + ->service() + ->updateBalance($payment->amount * -1) + ->updatePaidToDate($payment->amount) + ->save(); + + $this->invoice->service()->workFlow()->save(); + + return $this->invoice; + } + + private function setExchangeRate(Payment $payment) + { + + $client_currency = $payment->client->getSetting('currency_id'); + $company_currency = $payment->client->company->settings->currency_id; + + if ($company_currency != $client_currency) { + + $exchange_rate = new CurrencyApi(); + + $payment->exchange_rate = $exchange_rate->exchangeRate($client_currency, $company_currency, Carbon::parse($payment->date)); + //$payment->exchange_currency_id = $client_currency; // 23/06/2021 + $payment->exchange_currency_id = $company_currency; + + $payment->save(); + + } + + } +} diff --git a/app/Services/Invoice/InvoiceService.php b/app/Services/Invoice/InvoiceService.php index 9f7f7bdf6b74..f6df31475ca2 100644 --- a/app/Services/Invoice/InvoiceService.php +++ b/app/Services/Invoice/InvoiceService.php @@ -22,6 +22,7 @@ use App\Models\Payment; use App\Models\Task; use App\Repositories\BaseRepository; use App\Services\Client\ClientService; +use App\Services\Invoice\ApplyPaymentAmount; use App\Services\Invoice\UpdateReminder; use App\Utils\Ninja; use App\Utils\Traits\MakesHash; @@ -51,6 +52,13 @@ class InvoiceService return $this; } + public function applyPaymentAmount($amount) + { + $this->invoice = (new ApplyPaymentAmount($this->invoice, $amount))->run(); + + return $this; + } + /** * Applies the invoice number. * @return $this InvoiceService object diff --git a/app/Services/Invoice/TriggeredActions.php b/app/Services/Invoice/TriggeredActions.php index 02b13eecfad0..9dca9a50f733 100644 --- a/app/Services/Invoice/TriggeredActions.php +++ b/app/Services/Invoice/TriggeredActions.php @@ -44,6 +44,10 @@ class TriggeredActions extends AbstractService $this->invoice = $this->invoice->service()->markPaid()->save(); } + if ($this->request->has('amount_paid') && is_numeric($this->request->input('amount_paid')) ) { + $this->invoice = $this->invoice->service()->applyPaymentAmount($this->request->input('amount_paid'))->save(); + } + if ($this->request->has('send_email') && $this->request->input('send_email') == 'true') { $this->sendEmail(); } @@ -52,6 +56,7 @@ class TriggeredActions extends AbstractService $this->invoice = $this->invoice->service()->markSent()->save(); } + return $this->invoice; } diff --git a/tests/Feature/InvoiceAmountPaymentTest.php b/tests/Feature/InvoiceAmountPaymentTest.php new file mode 100644 index 000000000000..0d1e429f4ed7 --- /dev/null +++ b/tests/Feature/InvoiceAmountPaymentTest.php @@ -0,0 +1,114 @@ +makeTestData(); + + $this->withoutMiddleware( + ThrottleRequests::class + ); + } + + public function testPaymentAmountForInvoice() + { + + $data = [ + 'name' => 'A Nice Client', + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/clients', $data); + + $response->assertStatus(200); + + $arr = $response->json(); + + $client_hash_id = $arr['data']['id']; + $client = Client::find($this->decodePrimaryKey($client_hash_id)); + + $this->assertEquals($client->balance, 0); + $this->assertEquals($client->paid_to_date, 0); + //create new invoice. + + $line_items = []; + + $item = InvoiceItemFactory::create(); + $item->quantity = 1; + $item->cost = 10; + + $line_items[] = (array)$item; + + $item = InvoiceItemFactory::create(); + $item->quantity = 1; + $item->cost = 10; + + $line_items[] = (array)$item; + + $invoice = [ + 'status_id' => 1, + 'number' => '', + 'discount' => 0, + 'is_amount_discount' => 1, + 'po_number' => '3434343', + 'public_notes' => 'notes', + 'is_deleted' => 0, + 'custom_value1' => 0, + 'custom_value2' => 0, + 'custom_value3' => 0, + 'custom_value4' => 0, + 'client_id' => $client_hash_id, + 'line_items' => (array)$line_items, + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/invoices?amount_paid=10', $invoice) + ->assertStatus(200); + + $arr = $response->json(); + + $invoice_one_hashed_id = $arr['data']['id']; + + $invoice = Invoice::find($this->decodePrimaryKey($invoice_one_hashed_id)); + + $this->assertEquals(10, $invoice->balance); + $this->assertTrue($invoice->payments()->exists()); + + $payment = $invoice->payments()->first(); + + $this->assertEquals(10, $payment->applied); + $this->assertEquals(10, $payment->amount); + + } +} \ No newline at end of file