diff --git a/app/Services/Invoice/HandleRestore.php b/app/Services/Invoice/HandleRestore.php index d647767355bc..00ab017611cc 100644 --- a/app/Services/Invoice/HandleRestore.php +++ b/app/Services/Invoice/HandleRestore.php @@ -20,8 +20,6 @@ class HandleRestore extends AbstractService private $invoice; - private $payment_total = 0; - public function __construct(Invoice $invoice) { $this->invoice = $invoice; @@ -37,17 +35,23 @@ class HandleRestore extends AbstractService foreach($this->invoice->payments as $payment) { - + //restore the payment record $payment->restore(); + //determine the paymentable amount before paymentable restoration + $pre_restore_amount = $payment->paymentables() + ->where('paymentable_type', '=', 'invoices') + ->sum(\DB::raw('amount')); + + //restore the paymentables $payment->paymentables() ->where('paymentable_type', '=', 'invoices') ->where('paymentable_id', $this->invoice->id) ->restore(); + //determine the post restore paymentable amount (we need to increment the payment amount by the difference between pre and post) $payment_amount = $payment->paymentables() ->where('paymentable_type', '=', 'invoices') - ->where('paymentable_id', $this->invoice->id) ->sum(\DB::raw('amount')); info($payment->amount . " == " . $payment_amount); @@ -61,27 +65,22 @@ class HandleRestore extends AbstractService else { $payment->is_deleted = false; - $payment->amount += $this->payment_total; - $payment->applied += $this->payment_total; + $payment->amount += ($payment_amount - $pre_restore_amount); + $payment->applied += ($payment_amount - $pre_restore_amount); $payment->save(); } - $this->payment_total += $payment_amount; - } - - - //adjust ledger balance $this->invoice->ledger()->updateInvoiceBalance($this->invoice->balance, 'Restored invoice {$this->invoice->number}')->save(); //adjust paid to dates - $this->invoice->client->service()->updatePaidToDate($this->payment_total)->save(); + $this->invoice->client->service()->updatePaidToDate($payment_amount - $pre_restore_amount)->save(); $this->invoice->client->service()->updateBalance($this->invoice->balance)->save(); - $this->invoice->ledger()->updatePaymentBalance($this->payment_total, 'Restored payment for invoice {$this->invoice->number}')->save(); + $this->invoice->ledger()->updatePaymentBalance(($payment_amount - $pre_restore_amount), 'Restored payment for invoice {$this->invoice->number}')->save(); $this->windBackInvoiceNumber(); diff --git a/tests/Feature/DeleteInvoiceTest.php b/tests/Feature/DeleteInvoiceTest.php index a15850df4b6f..2170c4f7bded 100644 --- a/tests/Feature/DeleteInvoiceTest.php +++ b/tests/Feature/DeleteInvoiceTest.php @@ -40,7 +40,121 @@ class DeleteInvoiceTest extends TestCase ); } + /** + * @covers App\Services\Invoice\MarkInvoiceDeleted + */ public function testInvoiceDeletion() + { + + $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); + + //delete invoice + $data = [ + 'ids' => [$invoice_one_hashed_id], + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/invoices/bulk?action=delete', $data)->assertStatus(200); + + + $invoice = $invoice->fresh(); + + $this->assertEquals(20, $invoice->balance); + $this->assertEquals(0, $invoice->client->balance); + $this->assertTrue((bool)$invoice->is_deleted); + $this->assertNotNull($invoice->deleted_at); + + //delete invoice + $data = [ + 'ids' => [$invoice_one_hashed_id], + ]; + + //restore invoice + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/invoices/bulk?action=restore', $data)->assertStatus(200); + + $invoice = $invoice->fresh(); + + $this->assertEquals(20, $invoice->balance); + $this->assertFalse((bool)$invoice->is_deleted); + $this->assertNull($invoice->deleted_at); + $this->assertEquals(20, $invoice->client->fresh()->balance); + + } + + /** + * @covers App\Services\Invoice\HandleRestore + */ + public function testInvoiceDeletionAndRestoration() { //create new client @@ -151,6 +265,8 @@ class DeleteInvoiceTest extends TestCase $invoice_one = Invoice::find($this->decodePrimaryKey($invoice_one_hashed_id)); $invoice_two = Invoice::find($this->decodePrimaryKey($invoice_two_hashed_id)); $payment = Payment::find($this->decodePrimaryKey($payment_hashed_id)); + + $this->assertEquals(20, $invoice_one->company_ledger->sortByDesc('id')->first()->balance); //test balance $this->assertEquals($invoice_one->amount, 20); @@ -179,17 +295,34 @@ class DeleteInvoiceTest extends TestCase $this->assertTrue($arr['data'][0]['is_deleted']); - $this->assertEquals($client->fresh()->paid_to_date, 20); + $this->assertEquals(20, $client->fresh()->paid_to_date); + $this->assertEquals(0, $client->fresh()->balance); + $this->assertEquals(20, $payment->fresh()->applied); + $this->assertEquals(20, $payment->fresh()->amount); - $this->assertEquals($payment->fresh()->applied, 20); - $this->assertEquals($payment->fresh()->amount, 20); - //test ledger balance + $invoice_one = $invoice_one->fresh(); - //test client balance + $this->assertTrue((bool)$invoice_one->is_deleted); + $this->assertNotNull($invoice_one->deleted_at); - //test client paid to date + //restore invoice + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/invoices/bulk?action=restore', $data); - - + $arr = $response->json(); + + $this->assertFalse($arr['data'][0]['is_deleted']); + + $invoice_one = $invoice_one->fresh(); + $this->assertFalse((bool)$invoice_one->is_deleted); + $this->assertNull($invoice_one->deleted_at); + + $payment = $payment->fresh(); + + $this->assertEquals(40, $payment->fresh()->applied); + $this->assertEquals(40, $payment->fresh()->amount); + $this->assertEquals(40, $client->fresh()->paid_to_date); } }