Fixes for recurring due date days across timezones

This commit is contained in:
David Bomba 2024-11-18 07:28:31 +11:00
parent a089b7809f
commit 290b13f87e
8 changed files with 59 additions and 37 deletions

View File

@ -62,8 +62,7 @@ class SendRecurring implements ShouldQueue
// Generate Standard Invoice // Generate Standard Invoice
$invoice = RecurringInvoiceToInvoiceFactory::create($this->recurring_invoice, $this->recurring_invoice->client); $invoice = RecurringInvoiceToInvoiceFactory::create($this->recurring_invoice, $this->recurring_invoice->client);
$date = now()->addSeconds($this->recurring_invoice->client->timezone_offset())->format('Y-m-d'); $date = date('Y-m-d'); //@todo this will always pull UTC date.
// $date = date('Y-m-d');
$invoice->date = $date; $invoice->date = $date;
nlog("Recurring Invoice Date Set on Invoice = {$invoice->date} - ". now()->format('Y-m-d')); nlog("Recurring Invoice Date Set on Invoice = {$invoice->date} - ". now()->format('Y-m-d'));
@ -85,7 +84,6 @@ class SendRecurring implements ShouldQueue
->save(); ->save();
} }
//12-01-2023 i moved this block after fillDefaults to handle if standard invoice auto bill config has been enabled, recurring invoice should override.
if ($this->recurring_invoice->auto_bill == 'always') { if ($this->recurring_invoice->auto_bill == 'always') {
$invoice->auto_bill_enabled = true; $invoice->auto_bill_enabled = true;
$invoice->saveQuietly(); $invoice->saveQuietly();

View File

@ -679,6 +679,8 @@ class RecurringInvoice extends BaseModel
return Carbon::parse($date)->copy(); return Carbon::parse($date)->copy();
default: default:
$date = now()->addSeconds($this->client->timezone_offset());
return $this->setDayOfMonth($date, $this->due_date_days); return $this->setDayOfMonth($date, $this->due_date_days);
} }
} }

View File

@ -169,16 +169,11 @@ paths:
/api/v1/login: /api/v1/login:
post: post:
x-codeSamples:
tags: tags:
- login - auth
summary: "Attempts authentication" summary: "Login"
description: | description: |
After authenticating with the API, the returned object is a CompanyUser object which is a bridge linking the user to the company.
The company user object itself contains the users permissions (admin/owner or fine grained permissions) You will most likely want to
also include in the response of this object both the company and the user object, this can be done by using the include parameter.
/api/v1/login?include=company,user
operationId: postLogin operationId: postLogin
parameters: parameters:
@ -14651,7 +14646,6 @@ components:
required: true required: true
schema: schema:
type: string type: string
readOnly: true
example: XMLHttpRequest example: XMLHttpRequest
X-API-TOKEN: X-API-TOKEN:
name: X-API-TOKEN name: X-API-TOKEN
@ -14753,7 +14747,11 @@ components:
login_include: login_include:
name: include name: include
in: query in: query
description: Include child relations of the CompanyUser object, format is comma separated. **Note** it is possible to chain multiple includes together, ie. include=account,token description: |
Include child relations of the CompanyUser object, format is comma separated.
> ### **Note**: it is possible to chain multiple includes together, ie. include=account,token
required: false required: false
schema: schema:
type: string type: string
@ -14798,7 +14796,7 @@ components:
name: include_static name: include_static
in: query in: query
description: | description: |
Static variables include: This include will also return the full set of static variables used in the application including:
- Currencies - Currencies
- Countries - Countries
- Languages - Languages
@ -22157,10 +22155,18 @@ components:
readOnly: true readOnly: true
type: object type: object
tags: tags:
- name: login - name: auth
# description: | description: |
# Attempts to authenticate with the API using a email/password combination. Attempts to authenticate with the API using a email/password combination.
After authenticating with the API, the returned object is a CompanyUser object which is a bridge linking the user to the company.
The company user object contains the users permissions (admin/owner or fine grained permissions) You will most likely want to
also include in the response of this object both the company and the user object, this can be done by using the include parameter.
```html
/api/v1/login?include=company,user
```
- name: clients - name: clients
x-tag-expanded: false x-tag-expanded: false
# description: | # description: |

View File

@ -14,7 +14,6 @@
required: true required: true
schema: schema:
type: string type: string
readOnly: true
example: XMLHttpRequest example: XMLHttpRequest
X-API-TOKEN: X-API-TOKEN:
name: X-API-TOKEN name: X-API-TOKEN
@ -116,7 +115,11 @@
login_include: login_include:
name: include name: include
in: query in: query
description: Include child relations of the CompanyUser object, format is comma separated. **Note** it is possible to chain multiple includes together, ie. include=account,token description: |
Include child relations of the CompanyUser object, format is comma separated.
> ### **Note**: it is possible to chain multiple includes together, ie. include=account,token
required: false required: false
schema: schema:
type: string type: string
@ -161,7 +164,7 @@
name: include_static name: include_static
in: query in: query
description: | description: |
Static variables include: This include will also return the full set of static variables used in the application including:
- Currencies - Currencies
- Countries - Countries
- Languages - Languages

View File

@ -1,8 +1,16 @@
tags: tags:
- name: login - name: auth
# description: | description: |
# Attempts to authenticate with the API using a email/password combination. Attempts to authenticate with the API using a email/password combination.
After authenticating with the API, the returned object is a CompanyUser object which is a bridge linking the user to the company.
The company user object contains the users permissions (admin/owner or fine grained permissions) You will most likely want to
also include in the response of this object both the company and the user object, this can be done by using the include parameter.
```html
/api/v1/login?include=company,user
```
- name: clients - name: clients
x-tag-expanded: false x-tag-expanded: false
# description: | # description: |

View File

@ -86,16 +86,11 @@ paths:
/api/v1/login: /api/v1/login:
post: post:
x-codeSamples:
tags: tags:
- login - auth
summary: "Attempts authentication" summary: "Login"
description: | description: |
After authenticating with the API, the returned object is a CompanyUser object which is a bridge linking the user to the company.
The company user object itself contains the users permissions (admin/owner or fine grained permissions) You will most likely want to
also include in the response of this object both the company and the user object, this can be done by using the include parameter.
/api/v1/login?include=company,user
operationId: postLogin operationId: postLogin
parameters: parameters:

View File

@ -45,11 +45,25 @@ class RecurringDatesTest extends TestCase
public function testDueDateDaysCalculationsTZ2() public function testDueDateDaysCalculationsTZ2()
{ {
$settings = CompanySettings::defaults();
$settings->timezone_id = '15'; // New York
$company = Company::factory()->create([
'account_id'=>$this->account->id,
'settings' => $settings,
]);
$client = Client::factory()->create([
'company_id' =>$company->id,
'user_id' => $this->user->id,
]);
$this->travelTo(\Carbon\Carbon::create(2024, 12, 1, 17, 0, 0)); $this->travelTo(\Carbon\Carbon::create(2024, 12, 1, 17, 0, 0));
$recurring_invoice = RecurringInvoiceFactory::create($this->company->id, $this->user->id); $recurring_invoice = RecurringInvoiceFactory::create($company->id, $this->user->id);
$recurring_invoice->line_items = $this->buildLineItems(); $recurring_invoice->line_items = $this->buildLineItems();
$recurring_invoice->client_id = $this->client->id; $recurring_invoice->client_id = $client->id;
$recurring_invoice->status_id = RecurringInvoice::STATUS_DRAFT; $recurring_invoice->status_id = RecurringInvoice::STATUS_DRAFT;
$recurring_invoice->frequency_id = RecurringInvoice::FREQUENCY_MONTHLY; $recurring_invoice->frequency_id = RecurringInvoice::FREQUENCY_MONTHLY;
$recurring_invoice->remaining_cycles = 5; $recurring_invoice->remaining_cycles = 5;

View File

@ -15,10 +15,6 @@ use App\Utils\Traits\Recurring\HasRecurrence;
use Illuminate\Support\Carbon; use Illuminate\Support\Carbon;
use Tests\TestCase; use Tests\TestCase;
/**
*
* App\Utils\Traits\Recurring\HasRecurrence
*/
class RecurringDueDatesTest extends TestCase class RecurringDueDatesTest extends TestCase
{ {
use HasRecurrence; use HasRecurrence;