diff --git a/app/Repositories/InvoiceRepository.php b/app/Repositories/InvoiceRepository.php index 83b6980f1567..c7347da552b0 100644 --- a/app/Repositories/InvoiceRepository.php +++ b/app/Repositories/InvoiceRepository.php @@ -97,6 +97,10 @@ class InvoiceRepository extends BaseRepository // reversed delete invoice actions $invoice = $invoice->service()->handleRestore()->save(); + /* If the reverse did not succeed due to rules, then do not restore / unarchive */ + if($invoice->is_deleted) + return $invoice; + parent::restore($invoice); return $invoice; diff --git a/app/Services/Invoice/HandleRestore.php b/app/Services/Invoice/HandleRestore.php index c3e2947e8732..d5bf6c8275ba 100644 --- a/app/Services/Invoice/HandleRestore.php +++ b/app/Services/Invoice/HandleRestore.php @@ -44,6 +44,7 @@ class HandleRestore extends AbstractService //cannot restore an invoice with a deleted payment foreach ($this->invoice->payments as $payment) { if (($this->invoice->paid_to_date == 0) && $payment->is_deleted) { + $this->invoice->delete(); return $this->invoice; } } diff --git a/tests/Feature/PaymentV2Test.php b/tests/Feature/PaymentV2Test.php index 761c00b03361..11f448b3b481 100644 --- a/tests/Feature/PaymentV2Test.php +++ b/tests/Feature/PaymentV2Test.php @@ -11,20 +11,21 @@ namespace Tests\Feature; +use Tests\TestCase; use App\Models\Client; -use App\Models\ClientContact; use App\Models\Credit; use App\Models\Invoice; use App\Models\Payment; +use Tests\MockAccountData; +use App\Models\ClientContact; use App\Utils\Traits\MakesHash; +use App\Factory\InvoiceItemFactory; use Illuminate\Database\Eloquent\Model; -use Illuminate\Foundation\Testing\DatabaseTransactions; -use Illuminate\Foundation\Testing\WithoutEvents; -use Illuminate\Routing\Middleware\ThrottleRequests; use Illuminate\Support\Facades\Session; use Illuminate\Validation\ValidationException; -use Tests\MockAccountData; -use Tests\TestCase; +use Illuminate\Foundation\Testing\WithoutEvents; +use Illuminate\Routing\Middleware\ThrottleRequests; +use Illuminate\Foundation\Testing\DatabaseTransactions; /** * @test @@ -189,4 +190,186 @@ class PaymentV2Test extends TestCase $this->assertEquals(20, $client->fresh()->paid_to_date); } + +public function testStorePaymentWithCreditsThenDeletingInvoicesAndThenPayments() + { + $client = Client::factory()->create(['company_id' =>$this->company->id, 'user_id' => $this->user->id, 'balance' => 100, 'paid_to_date' => 0]); + ClientContact::factory()->create([ + 'user_id' => $this->user->id, + 'client_id' => $client->id, + 'company_id' => $this->company->id, + 'is_primary' => 1, + ]); + + $line_items = []; + + $item = InvoiceItemFactory::create(); + $item->quantity = 1; + $item->cost = 100; + + $line_items[] = $item; + + + $invoice = Invoice::factory()->create([ + 'company_id' => $this->company->id, + 'user_id' => $this->user->id, + 'client_id' => $client->id, + 'status_id' => Invoice::STATUS_SENT, + 'uses_inclusive_taxes' => false, + 'amount' => 100, + 'balance' => 100, + 'discount' => 0, + 'number' => uniqid("st", true), + 'line_items' => $line_items + ]); + + $this->assertEquals(100, $client->balance); + $this->assertEquals(0, $client->paid_to_date); + $this->assertEquals(100, $invoice->amount); + $this->assertEquals(100, $invoice->balance); + + $credit = Credit::factory()->create([ + 'company_id' => $this->company->id, + 'user_id' => $this->user->id, + 'client_id' => $client->id, + 'status_id' => Invoice::STATUS_SENT, + 'uses_inclusive_taxes' => false, + 'amount' => 20, + 'balance' => 20, + 'discount' => 0, + 'number' => uniqid("st", true), + 'line_items' => [] + ]); + + $this->assertEquals(20, $credit->amount); + $this->assertEquals(20, $credit->balance); + + $data = [ + 'client_id' => $client->hashed_id, + 'invoices' => [ + [ + 'invoice_id' => $invoice->hashed_id, + 'amount' => 100, + ], + ], + 'credits' => [ + [ + 'credit_id' => $credit->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?include=invoices', $data); + } catch (ValidationException $e) { + $message = json_decode($e->validator->getMessageBag(), 1); + nlog($message); + $this->assertNotNull($message); + } + + $arr = $response->json(); + $response->assertStatus(200); + + $payment_id = $arr['data']['id']; + + $payment = Payment::find($this->decodePrimaryKey($payment_id)); + + $this->assertNotNull($payment); + $this->assertNotNull($payment->invoices()); + $this->assertEquals(1, $payment->invoices()->count()); + $this->assertEquals(80, $payment->amount); + $this->assertEquals(0, $client->fresh()->balance); + $this->assertEquals(100, $client->fresh()->paid_to_date); + + $invoice = $invoice->fresh(); + + //delete the invoice + + $data = [ + 'action' => 'delete', + 'ids' => [ + $invoice->hashed_id, + ], + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/invoices/bulk', $data); + + $response->assertStatus(200); + + $payment = $payment->fresh(); + $invoice = $invoice->fresh(); + + $this->assertTrue($invoice->is_deleted); + $this->assertFalse($payment->is_deleted); + + $data = [ + 'action' => 'delete', + 'ids' => [ + $payment->hashed_id, + ], + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/payments/bulk', $data); + + $payment = $payment->fresh(); + $this->assertTrue($payment->is_deleted); + + $data = [ + 'action' => 'restore', + 'ids' => [ + $invoice->hashed_id, + ], + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/invoices/bulk', $data); + + $response->assertStatus(200); + $invoice = $invoice->fresh(); + + $this->assertTrue($invoice->is_deleted); + $this->assertTrue($invoice->trashed()); + + // $this->assertEquals(0, $payment->amount); + // $this->assertEquals(0, $client->fresh()->balance); + // $this->assertEquals(0, $client->fresh()->paid_to_date); + + // $data = [ + // 'action' => 'restore', + // 'ids' => [ + // $invoice->hashed_id, + // ], + // ]; + + // $response = $this->withHeaders([ + // 'X-API-SECRET' => config('ninja.api_secret'), + // 'X-API-TOKEN' => $this->token, + // ])->post('/api/v1/invoices/bulk', $data); + + // $invoice = $invoice->fresh(); + // $this->assertEquals(false, $invoice->is_deleted); + + // $payment = $payment->fresh(); + + // $this->assertEquals(0, $payment->amount); + // $this->assertEquals(20, $client->fresh()->paid_to_date); + + } + } \ No newline at end of file