diff --git a/app/DataMapper/CompanySettings.php b/app/DataMapper/CompanySettings.php index 39662af39b53..aa9bb7064d34 100644 --- a/app/DataMapper/CompanySettings.php +++ b/app/DataMapper/CompanySettings.php @@ -29,7 +29,7 @@ class CompanySettings extends BaseSettings public $besr_id = ''; //@implemented - public $lock_invoices = 'off'; //off,when_sent,when_paid //@implemented + public $lock_invoices = 'off'; //off,when_sent,when_paid,end_of_month //@implemented public $enable_client_portal_tasks = false; //@ben to implement diff --git a/app/Http/Controllers/InvoiceController.php b/app/Http/Controllers/InvoiceController.php index 79e348288788..c307e6302d01 100644 --- a/app/Http/Controllers/InvoiceController.php +++ b/app/Http/Controllers/InvoiceController.php @@ -408,7 +408,7 @@ class InvoiceController extends BaseController } if ($invoice->isLocked()) { - return response()->json(['message' => ctrans('texts.locked_invoice')], 422); + return response()->json(['message' => '', 'errors' => ['number' => ctrans('texts.locked_invoice')]], 422); } $old_invoice = $invoice->line_items; diff --git a/app/Http/Requests/Invoice/UpdateInvoiceRequest.php b/app/Http/Requests/Invoice/UpdateInvoiceRequest.php index 0e75760a6612..961fcb52ca68 100644 --- a/app/Http/Requests/Invoice/UpdateInvoiceRequest.php +++ b/app/Http/Requests/Invoice/UpdateInvoiceRequest.php @@ -67,7 +67,7 @@ class UpdateInvoiceRequest extends Request $rules['client_id'] = ['bail', 'sometimes', Rule::in([$this->invoice->client_id])]; $rules['line_items'] = 'array'; -$rules['discount'] = 'sometimes|numeric|max:99999999999999'; + $rules['discount'] = 'sometimes|numeric|max:99999999999999'; $rules['project_id'] = ['bail', 'sometimes', new ValidProjectForClient($this->all())]; $rules['tax_rate1'] = 'bail|sometimes|numeric'; $rules['tax_rate2'] = 'bail|sometimes|numeric'; @@ -80,7 +80,7 @@ $rules['discount'] = 'sometimes|numeric|max:99999999999999'; $rules['partial'] = 'bail|sometimes|nullable|numeric'; $rules['amount'] = ['sometimes', 'bail', 'numeric', 'max:99999999999999']; -$rules['date'] = 'bail|sometimes|date:Y-m-d'; + $rules['date'] = 'bail|sometimes|date:Y-m-d'; // $rules['partial_due_date'] = ['bail', 'sometimes', 'exclude_if:partial,0', Rule::requiredIf(fn () => $this->partial > 0), 'date', 'before:due_date']; // $rules['due_date'] = ['bail', 'sometimes', 'nullable', 'after:partial_due_date', Rule::requiredIf(fn () => strlen($this->partial_due_date) > 1), 'date']; diff --git a/app/Http/ValidationRules/Invoice/LockedInvoiceRule.php b/app/Http/ValidationRules/Invoice/LockedInvoiceRule.php index e6aa6d445216..6a4d6ac198c2 100644 --- a/app/Http/ValidationRules/Invoice/LockedInvoiceRule.php +++ b/app/Http/ValidationRules/Invoice/LockedInvoiceRule.php @@ -16,6 +16,7 @@ use Illuminate\Contracts\Validation\Rule; /** * Class LockedInvoiceRule. + * @deprecated */ class LockedInvoiceRule implements Rule { @@ -67,6 +68,13 @@ class LockedInvoiceRule implements Rule } return true; + + //if now is greater than the end of month the invoice was dated - do not modify + case 'end_of_month': + if(\Carbon\Carbon::setTimezone($this->invoice->company->timezone()->name)->parse($this->invoice->date)->endOfMonth()->lte(now())) + return false; + + return true; default: return true; } diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index 135f420ed8f5..70dfd979a814 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -563,6 +563,8 @@ class Invoice extends BaseModel return $this->status_id == self::STATUS_SENT; case 'when_paid': return $this->status_id == self::STATUS_PAID || $this->status_id == self::STATUS_PARTIAL; + case 'end_of_month': + return \Carbon\Carbon::parse($this->date)->setTimezone($this->company->timezone()->name)->endOfMonth()->lte(now()); default: return false; } diff --git a/lang/en/texts.php b/lang/en/texts.php index 003509f2c939..375bfbf5ecb3 100644 --- a/lang/en/texts.php +++ b/lang/en/texts.php @@ -5334,6 +5334,7 @@ $lang = array( 'btcpay_refund_body' => 'A refund intended for you has been issued. To claim it via BTCPay, please click on this link:', 'currency_mauritanian_ouguiya' => 'Mauritanian Ouguiya', 'currency_bhutan_ngultrum' => 'Bhutan Ngultrum', + 'end_of_month' => 'End Of Month' ); return $lang; \ No newline at end of file diff --git a/tests/Unit/DatesTest.php b/tests/Unit/DatesTest.php index 3f5ca6e2d4dd..a8cf2ea96345 100644 --- a/tests/Unit/DatesTest.php +++ b/tests/Unit/DatesTest.php @@ -31,6 +31,29 @@ class DatesTest extends TestCase // $this->makeTestData(); } + public function testDateNotGreaterThanMonthsEnd() + { + $this->travelTo(now()->createFromDate(2024, 6, 20)); + $date = '2024-05-20'; + + $this->assertTrue(\Carbon\Carbon::parse($date)->endOfMonth()->lte(now())); + + $this->travelBack(); + + } + + public function testDatLessThanMonthsEnd() + { + $this->travelTo(now()->createFromDate(2024, 5, 30)); + $date = '2024-05-20'; + + $this->assertFalse(\Carbon\Carbon::parse($date)->endOfMonth()->lte(now())); + + $this->travelBack(); + + } + + public function testLastFinancialYear3() { $this->travelTo(now()->createFromDate(2020, 6, 30));