diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 68361b199a6f..5076e834fb30 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -30,7 +30,9 @@ jobs: php artisan optimize php artisan storage:link sudo php artisan cache:clear - + sudo find ./ -type f -exec chmod 644 {} \; + sudo find ./ -type d -exec chmod 755 {} \; + - name: Prepare JS/CSS assets run: | npm i diff --git a/app/Http/Controllers/InvoiceController.php b/app/Http/Controllers/InvoiceController.php index 558e3525a07f..f23589f2a5c9 100644 --- a/app/Http/Controllers/InvoiceController.php +++ b/app/Http/Controllers/InvoiceController.php @@ -677,6 +677,11 @@ class InvoiceController extends BaseController } break; case 'cancel': + $invoice = $invoice->service()->handleCancellation()->save(); + + if(!$bulk){ + $this->itemResponse($invoice); + } break; case 'reverse': $invoice = $invoice->service()->handleReversal()->save(); diff --git a/app/Services/Invoice/HandleCancellation.php b/app/Services/Invoice/HandleCancellation.php new file mode 100644 index 000000000000..54be067f9085 --- /dev/null +++ b/app/Services/Invoice/HandleCancellation.php @@ -0,0 +1,59 @@ +invoice = $invoice; + } + + public function run() + { + /* Check again!! */ + if(!$this->invoice->invoiceCancellable($this->invoice)) + return $this->invoice; + + $adjustment = $this->invoice->balance*-1; + //set invoice balance to 0 + $this->invoice->ledger()->updateInvoiceBalance($adjustment, "Invoice cancellation"); + + $this->invoice->balance = 0; + $this->invoice = $this->invoice->service()->setStatus(Invoice::STATUS_CANCELLED)->save(); + + //adjust client balance + $this->invoice->client->service()->updateBalance($adjustment)->save(); + + return $this->invoice; + } + +} + diff --git a/app/Services/Invoice/HandleReversal.php b/app/Services/Invoice/HandleReversal.php index 8a45c13b4269..facf974fa41f 100644 --- a/app/Services/Invoice/HandleReversal.php +++ b/app/Services/Invoice/HandleReversal.php @@ -90,7 +90,7 @@ class HandleReversal extends AbstractService $credit->service()->markSent()->save(); } /* Set invoice balance to 0 */ - $this->invoice->ledger()->updateInvoiceBalance($balance_remaining, $notes)->save(); + $this->invoice->ledger()->updateInvoiceBalance($balance_remaining*-1, $notes)->save(); $this->invoice->balance= 0; diff --git a/app/Services/Invoice/InvoiceService.php b/app/Services/Invoice/InvoiceService.php index 4730ae379000..9a5037d0ba37 100644 --- a/app/Services/Invoice/InvoiceService.php +++ b/app/Services/Invoice/InvoiceService.php @@ -18,6 +18,7 @@ use App\Services\Invoice\ApplyNumber; use App\Services\Invoice\ApplyPayment; use App\Services\Invoice\CreateInvitations; use App\Services\Invoice\GetInvoicePdf; +use App\Services\Invoice\HandleCancellation; use App\Services\Invoice\HandleReversal; use App\Services\Invoice\MarkInvoicePaid; use App\Services\Invoice\MarkSent; @@ -123,6 +124,14 @@ class InvoiceService return $this; } + public function handleCancellation() + { + $this->invoice = (new HandleCancellation($this->invoice))->run(); + + return $this; + } + + public function markViewed() { $this->invoice->last_viewed = Carbon::now()->format('Y-m-d H:i'); diff --git a/app/Utils/Traits/Invoice/ActionsInvoice.php b/app/Utils/Traits/Invoice/ActionsInvoice.php index e9d3efaec6a9..fa6b61417c02 100644 --- a/app/Utils/Traits/Invoice/ActionsInvoice.php +++ b/app/Utils/Traits/Invoice/ActionsInvoice.php @@ -28,7 +28,7 @@ trait ActionsInvoice public function invoiceCancellable($invoice) :bool { - if($invoice->status_id == Invoice::STATUS_PARTIAL && $invoice->is_deleted == false && $invoice->deleted_at == NULL) + if(($invoice->status_id == Invoice::STATUS_SENT || $invoice->status_id == Invoice::STATUS_PARTIAL) && $invoice->is_deleted == false && $invoice->deleted_at == NULL) return true; return false; diff --git a/tests/Feature/CancelInvoiceTest.php b/tests/Feature/CancelInvoiceTest.php new file mode 100644 index 000000000000..da9202ccd243 --- /dev/null +++ b/tests/Feature/CancelInvoiceTest.php @@ -0,0 +1,72 @@ +withoutMiddleware( + ThrottleRequests::class + ); + + $this->faker = \Faker\Factory::create(); + + Model::reguard(); + + $this->makeTestData(); + + $this->withoutExceptionHandling(); + } + + public function testCancelInvoice() + { + $this->assertTrue($this->invoice->invoiceCancellable($this->invoice)); + + $client_balance = $this->client->balance; + $invoice_balance = $this->invoice->balance; + + $this->assertEquals(Invoice::STATUS_SENT, $this->invoice->status_id); + + $this->invoice->service()->handleCancellation()->save(); + + $this->assertEquals(0, $this->invoice->balance); + $this->assertEquals($this->client->balance, ($client_balance - $invoice_balance)); + $this->assertNotEquals($client_balance, $this->client->balance); + $this->assertEquals(Invoice::STATUS_CANCELLED, $this->invoice->status_id); + + } +} + + diff --git a/tests/Unit/InvoiceActionsTest.php b/tests/Unit/InvoiceActionsTest.php index 3969a3286f5f..e503bab5a210 100644 --- a/tests/Unit/InvoiceActionsTest.php +++ b/tests/Unit/InvoiceActionsTest.php @@ -29,7 +29,7 @@ class InvoiceActionsTest extends TestCase { $this->assertTrue($this->invoiceDeletable($this->invoice)); $this->assertTrue($this->invoiceReversable($this->invoice)); - $this->assertFalse($this->invoiceCancellable($this->invoice)); + $this->assertTrue($this->invoiceCancellable($this->invoice)); } public function testInvoiceIsReversable()