1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-10 05:02:36 +01:00

Add option to lock invoices at the end of the month - accrual accounting

This commit is contained in:
David Bomba 2024-06-06 13:06:07 +10:00
parent 0427f6c317
commit a9c1357689
7 changed files with 38 additions and 4 deletions

View File

@ -29,7 +29,7 @@ class CompanySettings extends BaseSettings
public $besr_id = ''; //@implemented 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 public $enable_client_portal_tasks = false; //@ben to implement

View File

@ -408,7 +408,7 @@ class InvoiceController extends BaseController
} }
if ($invoice->isLocked()) { 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; $old_invoice = $invoice->line_items;

View File

@ -67,7 +67,7 @@ class UpdateInvoiceRequest extends Request
$rules['client_id'] = ['bail', 'sometimes', Rule::in([$this->invoice->client_id])]; $rules['client_id'] = ['bail', 'sometimes', Rule::in([$this->invoice->client_id])];
$rules['line_items'] = 'array'; $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['project_id'] = ['bail', 'sometimes', new ValidProjectForClient($this->all())];
$rules['tax_rate1'] = 'bail|sometimes|numeric'; $rules['tax_rate1'] = 'bail|sometimes|numeric';
$rules['tax_rate2'] = '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['partial'] = 'bail|sometimes|nullable|numeric';
$rules['amount'] = ['sometimes', 'bail', 'numeric', 'max:99999999999999']; $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['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']; // $rules['due_date'] = ['bail', 'sometimes', 'nullable', 'after:partial_due_date', Rule::requiredIf(fn () => strlen($this->partial_due_date) > 1), 'date'];

View File

@ -16,6 +16,7 @@ use Illuminate\Contracts\Validation\Rule;
/** /**
* Class LockedInvoiceRule. * Class LockedInvoiceRule.
* @deprecated
*/ */
class LockedInvoiceRule implements Rule class LockedInvoiceRule implements Rule
{ {
@ -67,6 +68,13 @@ class LockedInvoiceRule implements Rule
} }
return true; 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: default:
return true; return true;
} }

View File

@ -563,6 +563,8 @@ class Invoice extends BaseModel
return $this->status_id == self::STATUS_SENT; return $this->status_id == self::STATUS_SENT;
case 'when_paid': case 'when_paid':
return $this->status_id == self::STATUS_PAID || $this->status_id == self::STATUS_PARTIAL; 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: default:
return false; return false;
} }

View File

@ -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:', '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_mauritanian_ouguiya' => 'Mauritanian Ouguiya',
'currency_bhutan_ngultrum' => 'Bhutan Ngultrum', 'currency_bhutan_ngultrum' => 'Bhutan Ngultrum',
'end_of_month' => 'End Of Month'
); );
return $lang; return $lang;

View File

@ -31,6 +31,29 @@ class DatesTest extends TestCase
// $this->makeTestData(); // $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() public function testLastFinancialYear3()
{ {
$this->travelTo(now()->createFromDate(2020, 6, 30)); $this->travelTo(now()->createFromDate(2020, 6, 30));