mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-06-01 01:04:43 -04:00
Updates for subscription cron logic to utilize company timezone
This commit is contained in:
parent
dd28cb0372
commit
d353bfc52a
@ -39,62 +39,25 @@ class SubscriptionCron
|
|||||||
*/
|
*/
|
||||||
public function handle(): void
|
public function handle(): void
|
||||||
{
|
{
|
||||||
nlog('Subscription Cron');
|
|
||||||
|
|
||||||
Auth::logout();
|
Auth::logout();
|
||||||
|
|
||||||
if (! config('ninja.db.multi_db_enabled')) {
|
if (! config('ninja.db.multi_db_enabled')) {
|
||||||
$invoices = Invoice::where('is_deleted', 0)
|
|
||||||
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
|
||||||
->where('balance', '>', 0)
|
|
||||||
->where('is_proforma', 0)
|
|
||||||
->whereDate('due_date', '<=', now()->addDay()->startOfDay())
|
|
||||||
->whereNull('deleted_at')
|
|
||||||
->whereNotNull('subscription_id')
|
|
||||||
->cursor();
|
|
||||||
|
|
||||||
$invoices->each(function (Invoice $invoice) {
|
nlog('Subscription Cron '. now()->toDateTimeString());
|
||||||
$subscription = $invoice->subscription;
|
|
||||||
|
|
||||||
$body = [
|
$this->timezoneAware();
|
||||||
'context' => 'plan_expired',
|
|
||||||
'client' => $invoice->client->hashed_id,
|
|
||||||
'invoice' => $invoice->hashed_id,
|
|
||||||
'subscription' => $subscription->hashed_id,
|
|
||||||
];
|
|
||||||
|
|
||||||
$this->sendLoad($subscription, $body);
|
|
||||||
//This will send the notification daily.
|
|
||||||
//We'll need to handle this by performing some action on the invoice to either archive it or delete it?
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
//multiDB environment, need to
|
//multiDB environment, need to
|
||||||
foreach (MultiDB::$dbs as $db) {
|
foreach (MultiDB::$dbs as $db) {
|
||||||
MultiDB::setDB($db);
|
MultiDB::setDB($db);
|
||||||
|
|
||||||
$invoices = Invoice::where('is_deleted', 0)
|
nlog('Subscription Cron for ' . $db . ' ' . now()->toDateTimeString());
|
||||||
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
|
||||||
->where('balance', '>', 0)
|
|
||||||
->where('is_proforma', 0)
|
|
||||||
->whereDate('due_date', '<=', now()->addDay()->startOfDay())
|
|
||||||
->whereNull('deleted_at')
|
|
||||||
->whereNotNull('subscription_id')
|
|
||||||
->cursor();
|
|
||||||
|
|
||||||
$invoices->each(function (Invoice $invoice) {
|
$this->timezoneAware();
|
||||||
$subscription = $invoice->subscription;
|
|
||||||
|
|
||||||
$body = [
|
|
||||||
'context' => 'plan_expired',
|
|
||||||
'client' => $invoice->client->hashed_id,
|
|
||||||
'invoice' => $invoice->hashed_id,
|
|
||||||
'subscription' => $subscription->hashed_id,
|
|
||||||
];
|
|
||||||
|
|
||||||
$this->sendLoad($subscription, $body);
|
|
||||||
//This will send the notification daily.
|
|
||||||
//We'll need to handle this by performing some action on the invoice to either archive it or delete it?
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -131,7 +94,7 @@ class SubscriptionCron
|
|||||||
->where('is_proforma', 0)
|
->where('is_proforma', 0)
|
||||||
->whereNotNull('subscription_id')
|
->whereNotNull('subscription_id')
|
||||||
->where('balance', '>', 0)
|
->where('balance', '>', 0)
|
||||||
->whereDate('due_date', '<=', now()->setTimezone($company->timezone()->name)->addDay()->startOfDay())
|
->whereDate('due_date', '<=', now()->addDay()->startOfDay())
|
||||||
->cursor()
|
->cursor()
|
||||||
->each(function (Invoice $invoice) {
|
->each(function (Invoice $invoice) {
|
||||||
|
|
||||||
|
@ -12,13 +12,19 @@
|
|||||||
namespace Tests\Feature;
|
namespace Tests\Feature;
|
||||||
|
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Models\Client;
|
||||||
|
use App\Models\Company;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use App\Models\Product;
|
use App\Models\Product;
|
||||||
use App\Models\RecurringInvoice;
|
|
||||||
use Tests\MockAccountData;
|
use Tests\MockAccountData;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
use App\Models\CompanyToken;
|
||||||
use App\Models\Subscription;
|
use App\Models\Subscription;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use App\Models\RecurringInvoice;
|
||||||
|
use App\DataMapper\CompanySettings;
|
||||||
|
use App\Factory\CompanyUserFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Support\Facades\Session;
|
use Illuminate\Support\Facades\Session;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
@ -51,6 +57,250 @@ class SubscriptionApiTest extends TestCase
|
|||||||
Model::reguard();
|
Model::reguard();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testSubscriptionCronLocalization()
|
||||||
|
{
|
||||||
|
|
||||||
|
$settings = CompanySettings::defaults();
|
||||||
|
$settings->timezone_id = '50'; //europe/vienna
|
||||||
|
|
||||||
|
$c2 = Company::factory()->create([
|
||||||
|
'account_id' => $this->company->account_id,
|
||||||
|
'settings' => $settings
|
||||||
|
]);
|
||||||
|
|
||||||
|
$cu = CompanyUserFactory::create($this->user->id, $c2->id, $this->account->id);
|
||||||
|
$cu->is_owner = true;
|
||||||
|
$cu->is_admin = true;
|
||||||
|
$cu->is_locked = true;
|
||||||
|
$cu->permissions = '["view_client"]';
|
||||||
|
$cu->save();
|
||||||
|
|
||||||
|
$different_company_token = \Illuminate\Support\Str::random(64);
|
||||||
|
|
||||||
|
$company_token = new CompanyToken();
|
||||||
|
$company_token->user_id = $this->user->id;
|
||||||
|
$company_token->company_id = $c2->id;
|
||||||
|
$company_token->account_id = $c2->account_id;
|
||||||
|
$company_token->name = 'test token';
|
||||||
|
$company_token->token = $different_company_token;
|
||||||
|
$company_token->is_system = true;
|
||||||
|
$company_token->save();
|
||||||
|
|
||||||
|
|
||||||
|
$s = Subscription::factory()->create([
|
||||||
|
'company_id' => $c2->id,
|
||||||
|
'user_id' => $this->user->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$client2 = Client::factory()->create([
|
||||||
|
'company_id' => $c2->id,
|
||||||
|
'user_id' => $this->user->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$i = Invoice::factory()->create([
|
||||||
|
'company_id' => $c2->id,
|
||||||
|
'user_id' => $this->user->id,
|
||||||
|
'subscription_id' => $s->id,
|
||||||
|
'due_date' => now()->startOfDay(),
|
||||||
|
'client_id' => $client2->id,
|
||||||
|
'status_id' => Invoice::STATUS_SENT
|
||||||
|
]);
|
||||||
|
|
||||||
|
$settings = CompanySettings::defaults();
|
||||||
|
$settings->timezone_id = '110'; //sydney/australia
|
||||||
|
|
||||||
|
$c = Company::factory()->create([
|
||||||
|
'account_id' => $this->company->account_id,
|
||||||
|
'settings' => $settings,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$cu = CompanyUserFactory::create($this->user->id, $c->id, $this->account->id);
|
||||||
|
$cu->is_owner = true;
|
||||||
|
$cu->is_admin = true;
|
||||||
|
$cu->is_locked = true;
|
||||||
|
$cu->permissions = '["view_client"]';
|
||||||
|
$cu->save();
|
||||||
|
|
||||||
|
$different_company_token = \Illuminate\Support\Str::random(64);
|
||||||
|
|
||||||
|
$company_token = new CompanyToken();
|
||||||
|
$company_token->user_id = $this->user->id;
|
||||||
|
$company_token->company_id = $c->id;
|
||||||
|
$company_token->account_id = $c->account_id;
|
||||||
|
$company_token->name = 'test token';
|
||||||
|
$company_token->token = $different_company_token;
|
||||||
|
$company_token->is_system = true;
|
||||||
|
$company_token->save();
|
||||||
|
|
||||||
|
$s1 = Subscription::factory()->create([
|
||||||
|
'company_id' => $c->id,
|
||||||
|
'user_id' => $this->user->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
$client = Client::factory()->create([
|
||||||
|
'company_id' => $c2->id,
|
||||||
|
'user_id' => $this->user->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$i = Invoice::factory()->create([
|
||||||
|
'company_id' => $c->id,
|
||||||
|
'user_id' => $this->user->id,
|
||||||
|
'subscription_id' => $s1->id,
|
||||||
|
'due_date' => now()->startOfDay(),
|
||||||
|
'client_id' => $client->id,
|
||||||
|
'status_id' => Invoice::STATUS_SENT
|
||||||
|
]);
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
$company = Company::find($c->id); //sydney
|
||||||
|
|
||||||
|
$timezone_now = now()->setTimezone($company->timezone()->name);
|
||||||
|
|
||||||
|
$this->assertEquals('Australia/Sydney', $timezone_now->timezoneName);
|
||||||
|
|
||||||
|
$this->travelTo($timezone_now->copy()->startOfDay()->subHour());
|
||||||
|
|
||||||
|
$i = false;
|
||||||
|
|
||||||
|
//Capture companies within the window of 00:00 and 00:30
|
||||||
|
if($timezone_now->gte($timezone_now->copy()->startOfDay()) && $timezone_now->lt($timezone_now->copy()->startOfDay()->addMinutes(30))) {
|
||||||
|
|
||||||
|
$i = Invoice::query()
|
||||||
|
->where('company_id', $company->id)
|
||||||
|
->whereNull('deleted_at')
|
||||||
|
->where('is_deleted', 0)
|
||||||
|
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
||||||
|
->where('is_proforma', 0)
|
||||||
|
->whereNotNull('subscription_id')
|
||||||
|
->where('balance', '>', 0)
|
||||||
|
->whereDate('due_date', '<=', now()->setTimezone($company->timezone()->name)->addDay()->startOfDay())
|
||||||
|
->get();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertFalse($i);
|
||||||
|
|
||||||
|
$this->travelTo($timezone_now->copy()->startOfDay());
|
||||||
|
|
||||||
|
if(now()->gte($timezone_now->copy()->startOfDay()) && now()->lt($timezone_now->copy()->startOfDay()->addMinutes(30))) {
|
||||||
|
|
||||||
|
$i = Invoice::query()
|
||||||
|
->where('company_id', $company->id)
|
||||||
|
->whereNull('deleted_at')
|
||||||
|
->where('is_deleted', 0)
|
||||||
|
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
||||||
|
->where('is_proforma', 0)
|
||||||
|
->whereNotNull('subscription_id')
|
||||||
|
->whereDate('due_date', '<=', now()->setTimezone($company->timezone()->name)->addDay()->startOfDay())
|
||||||
|
->get();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertEquals(1, $i->count());
|
||||||
|
|
||||||
|
$i = false;
|
||||||
|
|
||||||
|
$this->travelTo($timezone_now->copy()->startOfDay()->addHours(2));
|
||||||
|
|
||||||
|
if($timezone_now->gte($timezone_now->copy()->startOfDay()) && $timezone_now->lt($timezone_now->copy()->startOfDay()->addMinutes(30))) {
|
||||||
|
|
||||||
|
$i = Invoice::query()
|
||||||
|
->where('company_id', $company->id)
|
||||||
|
->whereNull('deleted_at')
|
||||||
|
->where('is_deleted', 0)
|
||||||
|
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
||||||
|
->where('is_proforma', 0)
|
||||||
|
->whereNotNull('subscription_id')
|
||||||
|
->where('balance', '>', 0)
|
||||||
|
->whereDate('due_date', '<=', now()->setTimezone($company->timezone()->name)->addDay()->startOfDay())
|
||||||
|
->get();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertFalse($i);
|
||||||
|
|
||||||
|
$count = Invoice::whereNotNull('subscription_id')->count();
|
||||||
|
|
||||||
|
$this->assertEquals(2, $count);
|
||||||
|
|
||||||
|
$this->travelBack();
|
||||||
|
//////////////////////////////////////////// vienna //////////////////////////////////////////////////
|
||||||
|
|
||||||
|
$company = Company::find($c2->id); //vienna
|
||||||
|
|
||||||
|
$timezone_now = now()->setTimezone($company->timezone()->name);
|
||||||
|
|
||||||
|
$this->assertEquals('Europe/Vienna', $timezone_now->timezoneName);
|
||||||
|
|
||||||
|
$this->travelTo($timezone_now->copy()->startOfDay()->subHour());
|
||||||
|
|
||||||
|
$this->travelTo($timezone_now->copy()->startOfDay()->subHour());
|
||||||
|
|
||||||
|
$i = false;
|
||||||
|
|
||||||
|
//Capture companies within the window of 00:00 and 00:30
|
||||||
|
if($timezone_now->gte($timezone_now->copy()->startOfDay()) && $timezone_now->lt($timezone_now->copy()->startOfDay()->addMinutes(30))) {
|
||||||
|
|
||||||
|
$i = Invoice::query()
|
||||||
|
->where('company_id', $company->id)
|
||||||
|
->whereNull('deleted_at')
|
||||||
|
->where('is_deleted', 0)
|
||||||
|
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
||||||
|
->where('is_proforma', 0)
|
||||||
|
->whereNotNull('subscription_id')
|
||||||
|
->where('balance', '>', 0)
|
||||||
|
->whereDate('due_date', '<=', now()->setTimezone($company->timezone()->name)->addDay()->startOfDay())
|
||||||
|
->get();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertFalse($i);
|
||||||
|
|
||||||
|
$this->travelTo($timezone_now->copy()->startOfDay());
|
||||||
|
|
||||||
|
if(now()->gte($timezone_now->copy()->startOfDay()) && now()->lt($timezone_now->copy()->startOfDay()->addMinutes(30))) {
|
||||||
|
|
||||||
|
$i = Invoice::query()
|
||||||
|
->where('company_id', $company->id)
|
||||||
|
->whereNull('deleted_at')
|
||||||
|
->where('is_deleted', 0)
|
||||||
|
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
||||||
|
->where('is_proforma', 0)
|
||||||
|
->whereNotNull('subscription_id')
|
||||||
|
->whereDate('due_date', '<=', now()->setTimezone($company->timezone()->name)->addDay()->startOfDay())
|
||||||
|
->get();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertEquals(1, $i->count());
|
||||||
|
|
||||||
|
$i = false;
|
||||||
|
|
||||||
|
$this->travelTo($timezone_now->copy()->startOfDay()->addHours(2));
|
||||||
|
|
||||||
|
if($timezone_now->gte($timezone_now->copy()->startOfDay()) && $timezone_now->lt($timezone_now->copy()->startOfDay()->addMinutes(30))) {
|
||||||
|
|
||||||
|
$i = Invoice::query()
|
||||||
|
->where('company_id', $company->id)
|
||||||
|
->whereNull('deleted_at')
|
||||||
|
->where('is_deleted', 0)
|
||||||
|
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
||||||
|
->where('is_proforma', 0)
|
||||||
|
->whereNotNull('subscription_id')
|
||||||
|
->where('balance', '>', 0)
|
||||||
|
->whereDate('due_date', '<=', now()->setTimezone($company->timezone()->name)->addDay()->startOfDay())
|
||||||
|
->get();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertFalse($i);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public function testAssignInvoice()
|
public function testAssignInvoice()
|
||||||
{
|
{
|
||||||
$i = Invoice::factory()
|
$i = Invoice::factory()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user