From e2d1a59224b232b679413c9cca90de2d7fb69a10 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 4 Jan 2022 21:33:37 +1100 Subject: [PATCH] Fixes for Partially deleted payments --- app/Models/Payment.php | 1 + app/Services/Payment/DeletePayment.php | 8 +- .../Payments/UnappliedPaymentDeleteTest.php | 255 ++++++++++++++++++ 3 files changed, 260 insertions(+), 4 deletions(-) diff --git a/app/Models/Payment.php b/app/Models/Payment.php index 4443cc8ebf..183a6d0a91 100644 --- a/app/Models/Payment.php +++ b/app/Models/Payment.php @@ -11,6 +11,7 @@ namespace App\Models; +use App\Events\Payment\PaymentWasRefunded; use App\Events\Payment\PaymentWasVoided; use App\Services\Ledger\LedgerService; use App\Services\Payment\PaymentService; diff --git a/app/Services/Payment/DeletePayment.php b/app/Services/Payment/DeletePayment.php index 58222c6e75..60ea86d86e 100644 --- a/app/Services/Payment/DeletePayment.php +++ b/app/Services/Payment/DeletePayment.php @@ -98,7 +98,7 @@ class DeletePayment $paymentable_invoice->client ->service() ->updateBalance($net_deletable) - ->updatePaidToDate($net_deletable * -1) + // ->updatePaidToDate($net_deletable * -1) ->save(); if ($paymentable_invoice->balance == $paymentable_invoice->amount) { @@ -120,17 +120,17 @@ class DeletePayment }); } - else { + // else { /* If there are no invoices - then we need to still adjust the total client->paid_to_date amount*/ $this->payment ->client ->service() - ->updatePaidToDate(($this->payment->amount - $this->payment->applied)*-1) + ->updatePaidToDate(($this->payment->amount - $this->payment->refunded)*-1) ->save(); - } + // } return $this; } diff --git a/tests/Feature/Payments/UnappliedPaymentDeleteTest.php b/tests/Feature/Payments/UnappliedPaymentDeleteTest.php index bc93dcfa51..06bcbed463 100644 --- a/tests/Feature/Payments/UnappliedPaymentDeleteTest.php +++ b/tests/Feature/Payments/UnappliedPaymentDeleteTest.php @@ -11,6 +11,9 @@ namespace Tests\Feature\Payments; +use App\Factory\InvoiceItemFactory; +use App\Models\Client; +use App\Models\Invoice; use App\Models\Payment; use App\Utils\Traits\MakesHash; use Illuminate\Foundation\Testing\DatabaseTransactions; @@ -96,7 +99,259 @@ class UnappliedPaymentDeleteTest extends TestCase } + } + public function testUnappliedPaymentWithPaidInvoice() + { + + $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/', $invoice) + ->assertStatus(200); + + $arr = $response->json(); + + $invoice_one_hashed_id = $arr['data']['id']; + + $invoice = Invoice::find($this->decodePrimaryKey($invoice_one_hashed_id)); + + $invoice = $invoice->service()->markSent()->save(); + + $this->assertEquals(20, $invoice->balance); + $this->assertEquals(20, $invoice->client->balance); + + + $data = [ + 'amount' => 30, + 'client_id' => $client->hashed_id, + 'invoices' => [ + [ + 'invoice_id' => $invoice->hashed_id, + 'amount' => 20 + ] + ], + 'date' => '2020/12/12', + + ]; + + $response = null; + + try { + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/payments', $data); + } catch (ValidationException $e) { + $message = json_decode($e->validator->getMessageBag(), 1); + $this->assertNotNull($message); + nlog($message); + } + + $arr = $response->json(); + + $payment_hashed_id = $arr['data']['id']; + $payment = Payment::find($this->decodePrimaryKey($payment_hashed_id)); + + $this->assertEquals(30, $payment->amount); + $this->assertEquals(20, $payment->applied); + + $payment->service()->deletePayment(); + + $payment->fresh(); + $invoice->fresh(); + + $this->assertEquals(0, $client->fresh()->paid_to_date); + $this->assertEquals(20, $client->fresh()->balance); + + } + + public function testRefundPartialPaymentDeletion() + { + + $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/', $invoice) + ->assertStatus(200); + + $arr = $response->json(); + + $invoice_one_hashed_id = $arr['data']['id']; + + $invoice = Invoice::find($this->decodePrimaryKey($invoice_one_hashed_id)); + + $invoice = $invoice->service()->markSent()->save(); + + $this->assertEquals(20, $invoice->balance); + $this->assertEquals(20, $invoice->client->balance); + + $data = [ + 'amount' => 50, + 'client_id' => $client->hashed_id, + 'date' => '2020/12/12', + 'invoices' => [ + [ + 'invoice_id' => $invoice->hashed_id, + 'amount' => 20 + ] + ], + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/payments', $data); + + $arr = $response->json(); + $response->assertStatus(200); + + $payment_id = $arr['data']['id']; + + $this->assertEquals(50, $arr['data']['amount']); + + $payment = Payment::whereId($this->decodePrimaryKey($payment_id))->first(); + + $this->assertNotNull($payment); + + $data = [ + 'id' => $this->encodePrimaryKey($payment->id), + 'amount' => 20, + 'date' => '2020/12/12', + 'invoices' => [ + [ + 'invoice_id' => $invoice->hashed_id, + 'amount' => 20 + ] + ], + ]; + + $response = false; + + try { + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/payments/refund', $data); + } catch (ValidationException $e) { + $message = json_decode($e->validator->getMessageBag(), 1); + } + + $arr = $response->json(); + + $response->assertStatus(200); + + $this->assertEquals(20, $arr['data']['refunded']); + $this->assertEquals(Payment::STATUS_PARTIALLY_REFUNDED, $arr['data']['status_id']); + $this->assertEquals(20, $payment->fresh()->refunded); + + $this->assertEquals(30, $client->fresh()->paid_to_date); + $this->assertEquals(20, $client->fresh()->balance); + + $payment->fresh()->service()->deletePayment(); + + $this->assertEquals(0, $client->fresh()->paid_to_date); + $this->assertEquals(20, $client->fresh()->balance); }