mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-16 16:13:20 +01:00
Merge branch 'v5-develop' into v5-stable
This commit is contained in:
commit
f04f16ea93
10
CHANGELOG.md
10
CHANGELOG.md
@ -1,11 +1,21 @@
|
|||||||
# Release notes
|
# Release notes
|
||||||
|
|
||||||
## [Unreleased (daily channel)](https://github.com/invoiceninja/invoiceninja/tree/v5-develop)
|
## [Unreleased (daily channel)](https://github.com/invoiceninja/invoiceninja/tree/v5-develop)
|
||||||
|
|
||||||
|
## [v5.2.0-release](https://github.com/invoiceninja/invoiceninja/releases/tag/v5.2.0-release)
|
||||||
|
## Added:
|
||||||
|
- Timezone Offset: Schedule emails based on timezone and time offsets.
|
||||||
|
- Force client country to system country if none is set.
|
||||||
|
- GMail Oauth via web
|
||||||
|
|
||||||
|
## Fixed:
|
||||||
- Add Cache-control: no-cache to prevent overaggressive caching of assets
|
- Add Cache-control: no-cache to prevent overaggressive caching of assets
|
||||||
- Improved labelling in the settings (client portal)
|
- Improved labelling in the settings (client portal)
|
||||||
- Client portal: Multiple accounts access improvements (#5703)
|
- Client portal: Multiple accounts access improvements (#5703)
|
||||||
- Client portal: "Credits" updates (#5734)
|
- Client portal: "Credits" updates (#5734)
|
||||||
- Client portal: Make sidebar white color, in order to make logo displaying more simple. (#5753)
|
- Client portal: Make sidebar white color, in order to make logo displaying more simple. (#5753)
|
||||||
|
- Inject small delay into emails to allow all resources to be produced (ie PDFs) prior to sending
|
||||||
|
- Fixes for endless reminders not firing
|
||||||
|
|
||||||
## [v5.1.56-release](https://github.com/invoiceninja/invoiceninja/releases/tag/v5.1.56-release)
|
## [v5.1.56-release](https://github.com/invoiceninja/invoiceninja/releases/tag/v5.1.56-release)
|
||||||
## Fixed:
|
## Fixed:
|
||||||
|
@ -1 +1 @@
|
|||||||
5.1.74
|
5.2.0
|
@ -311,17 +311,17 @@ class CheckData extends Command
|
|||||||
Client::withTrashed()->where('is_deleted', 0)->cursor()->each(function ($client) use ($wrong_paid_to_dates, $credit_total_applied) {
|
Client::withTrashed()->where('is_deleted', 0)->cursor()->each(function ($client) use ($wrong_paid_to_dates, $credit_total_applied) {
|
||||||
$total_invoice_payments = 0;
|
$total_invoice_payments = 0;
|
||||||
|
|
||||||
foreach ($client->invoices->where('is_deleted', false)->where('status_id', '>', 1) as $invoice) {
|
foreach ($client->invoices()->where('is_deleted', false)->where('status_id', '>', 1)->get() as $invoice) {
|
||||||
|
|
||||||
$total_amount = $invoice->payments->where('is_deleted', false)->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment:: STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED, Payment::STATUS_REFUNDED])->sum('pivot.amount');
|
$total_amount = $invoice->payments()->where('is_deleted', false)->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment:: STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED, Payment::STATUS_REFUNDED])->get()->sum('pivot.amount');
|
||||||
$total_refund = $invoice->payments->where('is_deleted', false)->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment:: STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED, Payment::STATUS_REFUNDED])->sum('pivot.refunded');
|
$total_refund = $invoice->payments()->where('is_deleted', false)->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment:: STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED, Payment::STATUS_REFUNDED])->get()->sum('pivot.refunded');
|
||||||
|
|
||||||
$total_invoice_payments += ($total_amount - $total_refund);
|
$total_invoice_payments += ($total_amount - $total_refund);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 10/02/21
|
// 10/02/21
|
||||||
foreach ($client->payments as $payment) {
|
foreach ($client->payments as $payment) {
|
||||||
$credit_total_applied += $payment->paymentables->where('paymentable_type', App\Models\Credit::class)->sum(DB::raw('amount'));
|
$credit_total_applied += $payment->paymentables()->where('paymentable_type', App\Models\Credit::class)->get()->sum(DB::raw('amount'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($credit_total_applied < 0) {
|
if ($credit_total_applied < 0) {
|
||||||
@ -347,10 +347,11 @@ class CheckData extends Command
|
|||||||
$wrong_paid_to_dates = 0;
|
$wrong_paid_to_dates = 0;
|
||||||
|
|
||||||
Client::cursor()->where('is_deleted', 0)->each(function ($client) use ($wrong_balances) {
|
Client::cursor()->where('is_deleted', 0)->each(function ($client) use ($wrong_balances) {
|
||||||
|
|
||||||
$client->invoices->where('is_deleted', false)->whereIn('status_id', '!=', Invoice::STATUS_DRAFT)->each(function ($invoice) use ($wrong_balances, $client) {
|
$client->invoices->where('is_deleted', false)->whereIn('status_id', '!=', Invoice::STATUS_DRAFT)->each(function ($invoice) use ($wrong_balances, $client) {
|
||||||
$total_amount = $invoice->payments->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment:: STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED])->sum('pivot.amount');
|
$total_amount = $invoice->payments()->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment:: STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED])->get()->sum('pivot.amount');
|
||||||
$total_refund = $invoice->payments->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment:: STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED])->sum('pivot.refunded');
|
$total_refund = $invoice->payments()->get()->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment:: STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED])->sum('pivot.refunded');
|
||||||
$total_credit = $invoice->credits->sum('amount');
|
$total_credit = $invoice->credits()->get()->sum('amount');
|
||||||
|
|
||||||
$total_paid = $total_amount - $total_refund;
|
$total_paid = $total_amount - $total_refund;
|
||||||
$calculated_paid_amount = $invoice->amount - $invoice->balance - $total_credit;
|
$calculated_paid_amount = $invoice->amount - $invoice->balance - $total_credit;
|
||||||
@ -363,6 +364,7 @@ class CheckData extends Command
|
|||||||
$this->isValid = false;
|
$this->isValid = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$this->logMessage("{$wrong_balances} clients with incorrect invoice balances");
|
$this->logMessage("{$wrong_balances} clients with incorrect invoice balances");
|
||||||
@ -408,8 +410,8 @@ class CheckData extends Command
|
|||||||
$wrong_paid_to_dates = 0;
|
$wrong_paid_to_dates = 0;
|
||||||
|
|
||||||
foreach (Client::where('is_deleted', 0)->cursor() as $client) {
|
foreach (Client::where('is_deleted', 0)->cursor() as $client) {
|
||||||
$invoice_balance = $client->invoices->where('is_deleted', false)->where('status_id', '>', 1)->sum('balance');
|
$invoice_balance = $client->invoices()->where('is_deleted', false)->where('status_id', '>', 1)->get()->sum('balance');
|
||||||
$credit_balance = $client->credits->where('is_deleted', false)->sum('balance');
|
$credit_balance = $client->credits()->where('is_deleted', false)->get()->sum('balance');
|
||||||
|
|
||||||
// if($client->balance != $invoice_balance)
|
// if($client->balance != $invoice_balance)
|
||||||
// $invoice_balance -= $credit_balance;//doesn't make sense to remove the credit amount
|
// $invoice_balance -= $credit_balance;//doesn't make sense to remove the credit amount
|
||||||
|
@ -126,9 +126,9 @@ class CheckDb extends Command
|
|||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
|
|
||||||
foreach($this->entities as $entity) {
|
$this->LogMessage("Checking - V5_DB1");
|
||||||
|
|
||||||
$this->LogMessage("V5_DB1");
|
foreach($this->entities as $entity) {
|
||||||
|
|
||||||
$count_db_1 = $entity::on('db-ninja-01')->count();
|
$count_db_1 = $entity::on('db-ninja-01')->count();
|
||||||
$count_db_2 = $entity::on('db-ninja-02a')->count();
|
$count_db_2 = $entity::on('db-ninja-02a')->count();
|
||||||
@ -140,11 +140,10 @@ class CheckDb extends Command
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->LogMessage("Checking - V5_DB2");
|
||||||
|
|
||||||
foreach($this->entities as $entity) {
|
foreach($this->entities as $entity) {
|
||||||
|
|
||||||
$this->LogMessage("V5_DB2");
|
|
||||||
|
|
||||||
$count_db_1 = $entity::on('db-ninja-02')->count();
|
$count_db_1 = $entity::on('db-ninja-02')->count();
|
||||||
$count_db_2 = $entity::on('db-ninja-01a')->count();
|
$count_db_2 = $entity::on('db-ninja-01a')->count();
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ class SendRemindersCron extends Command
|
|||||||
->cursor();
|
->cursor();
|
||||||
|
|
||||||
$invoices->each(function ($invoice) {
|
$invoices->each(function ($invoice) {
|
||||||
WebHookHandler::dispatch(Webhook::EVENT_LATE_INVOICE, $invoice, $invoice->company);
|
WebhookHandler::dispatch(Webhook::EVENT_LATE_INVOICE, $invoice, $invoice->company);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -99,7 +99,7 @@ class SendRemindersCron extends Command
|
|||||||
->cursor();
|
->cursor();
|
||||||
|
|
||||||
$quotes->each(function ($quote) {
|
$quotes->each(function ($quote) {
|
||||||
WebHookHandler::dispatch(Webhook::EVENT_EXPIRED_QUOTE, $quote, $quote->company);
|
WebhookHandler::dispatch(Webhook::EVENT_EXPIRED_QUOTE, $quote, $quote->company);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ class Kernel extends ConsoleKernel
|
|||||||
|
|
||||||
$schedule->command('ninja:check-data --database=db-ninja-01')->daily()->withoutOverlapping();
|
$schedule->command('ninja:check-data --database=db-ninja-01')->daily()->withoutOverlapping();
|
||||||
|
|
||||||
$schedule->job(new ReminderJob)->daily()->withoutOverlapping();
|
$schedule->job(new ReminderJob)->hourly()->withoutOverlapping();
|
||||||
|
|
||||||
$schedule->job(new CompanySizeCheck)->daily()->withoutOverlapping();
|
$schedule->job(new CompanySizeCheck)->daily()->withoutOverlapping();
|
||||||
|
|
||||||
|
@ -65,6 +65,8 @@ class CompanySettings extends BaseSettings
|
|||||||
public $auto_convert_quote = true; //@implemented
|
public $auto_convert_quote = true; //@implemented
|
||||||
public $auto_email_invoice = true; //@only used for Recurring Invoices, if set to false, we never send?
|
public $auto_email_invoice = true; //@only used for Recurring Invoices, if set to false, we never send?
|
||||||
|
|
||||||
|
public $entity_send_time = 0;
|
||||||
|
|
||||||
public $inclusive_taxes = false; //@implemented
|
public $inclusive_taxes = false; //@implemented
|
||||||
public $quote_footer = ''; //@implmented
|
public $quote_footer = ''; //@implmented
|
||||||
|
|
||||||
@ -266,6 +268,7 @@ class CompanySettings extends BaseSettings
|
|||||||
public $hide_empty_columns_on_pdf = false;
|
public $hide_empty_columns_on_pdf = false;
|
||||||
|
|
||||||
public static $casts = [
|
public static $casts = [
|
||||||
|
'entity_send_time' => 'int',
|
||||||
'shared_invoice_credit_counter' => 'bool',
|
'shared_invoice_credit_counter' => 'bool',
|
||||||
'reply_to_name' => 'string',
|
'reply_to_name' => 'string',
|
||||||
'hide_empty_columns_on_pdf' => 'bool',
|
'hide_empty_columns_on_pdf' => 'bool',
|
||||||
|
@ -489,38 +489,54 @@ class LoginController extends BaseController
|
|||||||
|
|
||||||
public function redirectToProvider(string $provider)
|
public function redirectToProvider(string $provider)
|
||||||
{
|
{
|
||||||
//'https://www.googleapis.com/auth/gmail.send','email','profile','openid'
|
|
||||||
$scopes = [];
|
$scopes = [];
|
||||||
|
|
||||||
|
$parameters = [];
|
||||||
|
|
||||||
if($provider == 'google'){
|
if($provider == 'google'){
|
||||||
|
|
||||||
$scopes = ['https://www.googleapis.com/auth/gmail.send','email','profile','openid'];
|
$scopes = ['https://www.googleapis.com/auth/gmail.send','email','profile','openid'];
|
||||||
|
$parameters = ['access_type' => 'offline', "prompt" => "consent select_account", 'redirect_uri' => config('ninja.app_url')."/auth/google"];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request()->has('code')) {
|
if (request()->has('code')) {
|
||||||
return $this->handleProviderCallback($provider);
|
return $this->handleProviderCallback($provider);
|
||||||
} else {
|
} else {
|
||||||
return Socialite::driver($provider)->with(['redirect_uri' => config('ninja.app_url')."/auth/google"])->scopes($scopes)->redirect();
|
return Socialite::driver($provider)->with($parameters)->scopes($scopes)->redirect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleProviderCallback(string $provider)
|
public function handleProviderCallback(string $provider)
|
||||||
{
|
{
|
||||||
$socialite_user = Socialite::driver($provider)
|
$socialite_user = Socialite::driver($provider)->user();
|
||||||
->user();
|
|
||||||
|
$oauth_user_token = '';
|
||||||
|
|
||||||
|
if($socialite_user->refreshToken){
|
||||||
|
|
||||||
|
$client = new Google_Client();
|
||||||
|
$client->setClientId(config('ninja.auth.google.client_id'));
|
||||||
|
$client->setClientSecret(config('ninja.auth.google.client_secret'));
|
||||||
|
$client->fetchAccessTokenWithRefreshToken($socialite_user->refreshToken);
|
||||||
|
$oauth_user_token = $client->getAccessToken();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if($user = OAuth::handleAuth($socialite_user, $provider))
|
if($user = OAuth::handleAuth($socialite_user, $provider))
|
||||||
{
|
{
|
||||||
|
|
||||||
nlog('found user and updating their user record');
|
nlog('found user and updating their user record');
|
||||||
|
$name = OAuth::splitName($socialite_user->getName());
|
||||||
|
|
||||||
$update_user = [
|
$update_user = [
|
||||||
'first_name' => $name[0],
|
'first_name' => $name[0],
|
||||||
'last_name' => $name[1],
|
'last_name' => $name[1],
|
||||||
'password' => '',
|
|
||||||
'email' => $socialite_user->getEmail(),
|
'email' => $socialite_user->getEmail(),
|
||||||
'oauth_user_id' => $socialite_user->getId(),
|
'oauth_user_id' => $socialite_user->getId(),
|
||||||
'oauth_provider_id' => $provider,
|
'oauth_provider_id' => $provider,
|
||||||
'oauth_user_token' => $socialite_user->refreshToken,
|
'oauth_user_token' => $oauth_user_token,
|
||||||
|
'oauth_user_refresh_token' => $socialite_user->refreshToken
|
||||||
];
|
];
|
||||||
|
|
||||||
$user->update($update_user);
|
$user->update($update_user);
|
||||||
|
@ -379,6 +379,15 @@ class ClientController extends BaseController
|
|||||||
|
|
||||||
$client->load('contacts', 'primary_contact');
|
$client->load('contacts', 'primary_contact');
|
||||||
|
|
||||||
|
/* Set the client country to the company if none is set */
|
||||||
|
if(!$client->country_id && strlen($client->company->settings->country_id) > 1){
|
||||||
|
|
||||||
|
$client->country_id = $client->company->settings->country_id;
|
||||||
|
|
||||||
|
$client->save();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
$this->uploadLogo($request->file('company_logo'), $client->company, $client);
|
$this->uploadLogo($request->file('company_logo'), $client->company, $client);
|
||||||
|
|
||||||
event(new ClientWasCreated($client, $client->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
event(new ClientWasCreated($client, $client->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
||||||
|
@ -564,7 +564,7 @@ class CreditController extends BaseController
|
|||||||
// EmailCredit::dispatch($credit, $credit->company);
|
// EmailCredit::dispatch($credit, $credit->company);
|
||||||
|
|
||||||
$credit->invitations->load('contact.client.country', 'credit.client.country', 'credit.company')->each(function ($invitation) use ($credit) {
|
$credit->invitations->load('contact.client.country', 'credit.client.country', 'credit.company')->each(function ($invitation) use ($credit) {
|
||||||
EmailEntity::dispatch($invitation, $credit->company, 'credit');
|
EmailEntity::dispatch($invitation, $credit->company, 'credit')->delay(now()->addSeconds(60));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ class EmailController extends BaseController
|
|||||||
$entity_obj->service()->markSent()->save();
|
$entity_obj->service()->markSent()->save();
|
||||||
|
|
||||||
EmailEntity::dispatch($invitation->fresh(), $invitation->company, $template, $data)
|
EmailEntity::dispatch($invitation->fresh(), $invitation->company, $template, $data)
|
||||||
->delay(now()->addSeconds(5));
|
->delay(now()->addSeconds(60));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ use App\Transformers\RecurringInvoiceTransformer;
|
|||||||
use App\Utils\Ninja;
|
use App\Utils\Ninja;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
use App\Utils\Traits\SavesDocuments;
|
use App\Utils\Traits\SavesDocuments;
|
||||||
|
use Carbon\Carbon;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
|
|
||||||
@ -205,6 +206,10 @@ class RecurringInvoiceController extends BaseController
|
|||||||
|
|
||||||
event(new RecurringInvoiceWasCreated($recurring_invoice, $recurring_invoice->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
event(new RecurringInvoiceWasCreated($recurring_invoice, $recurring_invoice->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
||||||
|
|
||||||
|
$offset = $recurring_invoice->client->timezone_offset();
|
||||||
|
$recurring_invoice->next_send_date = Carbon::parse($recurring_invoice->next_send_date)->startOfDay()->addSeconds($offset);
|
||||||
|
$recurring_invoice->save();
|
||||||
|
|
||||||
return $this->itemResponse($recurring_invoice);
|
return $this->itemResponse($recurring_invoice);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,6 +58,9 @@ class PasswordProtection
|
|||||||
$google = new Google();
|
$google = new Google();
|
||||||
$user = $google->getTokenResponse(request()->header('X-API-OAUTH-PASSWORD'));
|
$user = $google->getTokenResponse(request()->header('X-API-OAUTH-PASSWORD'));
|
||||||
|
|
||||||
|
nlog("user");
|
||||||
|
nlog($user);
|
||||||
|
|
||||||
if (is_array($user)) {
|
if (is_array($user)) {
|
||||||
|
|
||||||
$query = [
|
$query = [
|
||||||
@ -65,14 +68,20 @@ class PasswordProtection
|
|||||||
'oauth_provider_id'=> 'google'
|
'oauth_provider_id'=> 'google'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
nlog($query);
|
||||||
|
|
||||||
//If OAuth and user also has a password set - check both
|
//If OAuth and user also has a password set - check both
|
||||||
if ($existing_user = MultiDB::hasUser($query) && auth()->user()->has_password && Hash::check(auth()->user()->password, $request->header('X-API-PASSWORD'))) {
|
if ($existing_user = MultiDB::hasUser($query) && auth()->user()->company()->oauth_password_required && auth()->user()->has_password && Hash::check(auth()->user()->password, $request->header('X-API-PASSWORD'))) {
|
||||||
|
|
||||||
|
nlog("existing user with password");
|
||||||
|
|
||||||
Cache::put(auth()->user()->hashed_id.'_'.auth()->user()->account_id.'_logged_in', Str::random(64), $timeout);
|
Cache::put(auth()->user()->hashed_id.'_'.auth()->user()->account_id.'_logged_in', Str::random(64), $timeout);
|
||||||
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
elseif($existing_user = MultiDB::hasUser($query) && !auth()->user()->has_password){
|
elseif($existing_user = MultiDB::hasUser($query) && !auth()->user()->company()->oauth_password_required){
|
||||||
|
|
||||||
|
nlog("existing user without password");
|
||||||
|
|
||||||
Cache::put(auth()->user()->hashed_id.'_'.auth()->user()->account_id.'_logged_in', Str::random(64), $timeout);
|
Cache::put(auth()->user()->hashed_id.'_'.auth()->user()->account_id.'_logged_in', Str::random(64), $timeout);
|
||||||
return $next($request);
|
return $next($request);
|
||||||
|
@ -14,10 +14,12 @@ namespace App\Http\Requests\User;
|
|||||||
use App\DataMapper\DefaultSettings;
|
use App\DataMapper\DefaultSettings;
|
||||||
use App\Factory\UserFactory;
|
use App\Factory\UserFactory;
|
||||||
use App\Http\Requests\Request;
|
use App\Http\Requests\Request;
|
||||||
|
use App\Http\ValidationRules\Ninja\CanAddUserRule;
|
||||||
use App\Http\ValidationRules\User\AttachableUser;
|
use App\Http\ValidationRules\User\AttachableUser;
|
||||||
use App\Http\ValidationRules\ValidUserForCompany;
|
use App\Http\ValidationRules\ValidUserForCompany;
|
||||||
use App\Libraries\MultiDB;
|
use App\Libraries\MultiDB;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use App\Utils\Ninja;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
class StoreUserRequest extends Request
|
class StoreUserRequest extends Request
|
||||||
@ -45,8 +47,7 @@ class StoreUserRequest extends Request
|
|||||||
$rules['email'] = ['email', new AttachableUser()];
|
$rules['email'] = ['email', new AttachableUser()];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Ninja::isHosted()) {
|
||||||
if (auth()->user()->company()->account->isFreeHostedClient()) {
|
|
||||||
$rules['hosted_users'] = new CanAddUserRule(auth()->user()->company()->account);
|
$rules['hosted_users'] = new CanAddUserRule(auth()->user()->company()->account);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace App\Jobs\Company;
|
namespace App\Jobs\Company;
|
||||||
|
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
use App\Models\TaskStatus;
|
use App\Models\TaskStatus;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
@ -44,6 +45,9 @@ class CreateCompanyTaskStatuses
|
|||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
MultiDB::setDb($this->company->db);
|
||||||
|
|
||||||
$task_statuses = [
|
$task_statuses = [
|
||||||
['name' => ctrans('texts.backlog'), 'company_id' => $this->company->id, 'user_id' => $this->user->id, 'created_at' => now(), 'updated_at' => now(), 'status_order' => 1],
|
['name' => ctrans('texts.backlog'), 'company_id' => $this->company->id, 'user_id' => $this->user->id, 'created_at' => now(), 'updated_at' => now(), 'status_order' => 1],
|
||||||
['name' => ctrans('texts.ready_to_do'), 'company_id' => $this->company->id, 'user_id' => $this->user->id, 'created_at' => now(), 'updated_at' => now(), 'status_order' => 2],
|
['name' => ctrans('texts.ready_to_do'), 'company_id' => $this->company->id, 'user_id' => $this->user->id, 'created_at' => now(), 'updated_at' => now(), 'status_order' => 2],
|
||||||
|
@ -109,9 +109,8 @@ class EmailEntity implements ShouldQueue
|
|||||||
|
|
||||||
App::setLocale($this->invitation->contact->preferredLocale());
|
App::setLocale($this->invitation->contact->preferredLocale());
|
||||||
|
|
||||||
|
|
||||||
$nmo = new NinjaMailerObject;
|
$nmo = new NinjaMailerObject;
|
||||||
$nmo->mailable = new TemplateEmail($this->email_entity_builder,$this->invitation->contact, $this->invitation);
|
$nmo->mailable = new TemplateEmail($this->email_entity_builder, $this->invitation->contact, $this->invitation);
|
||||||
$nmo->company = $this->company;
|
$nmo->company = $this->company;
|
||||||
$nmo->settings = $this->settings;
|
$nmo->settings = $this->settings;
|
||||||
$nmo->to_user = $this->invitation->contact;
|
$nmo->to_user = $this->invitation->contact;
|
||||||
|
@ -14,7 +14,7 @@ namespace App\Jobs\Ninja;
|
|||||||
use App\DataMapper\InvoiceItem;
|
use App\DataMapper\InvoiceItem;
|
||||||
use App\Events\Invoice\InvoiceWasEmailed;
|
use App\Events\Invoice\InvoiceWasEmailed;
|
||||||
use App\Jobs\Entity\EmailEntity;
|
use App\Jobs\Entity\EmailEntity;
|
||||||
use App\Jobs\Util\WebHookHandler;
|
use App\Jobs\Util\WebhookHandler;
|
||||||
use App\Libraries\MultiDB;
|
use App\Libraries\MultiDB;
|
||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
@ -84,7 +84,7 @@ class SendReminders implements ShouldQueue
|
|||||||
|
|
||||||
if (in_array($reminder_template, ['reminder1', 'reminder2', 'reminder3', 'endless_reminder'])) {
|
if (in_array($reminder_template, ['reminder1', 'reminder2', 'reminder3', 'endless_reminder'])) {
|
||||||
$this->sendReminder($invoice, $reminder_template);
|
$this->sendReminder($invoice, $reminder_template);
|
||||||
WebHookHandler::dispatch(Webhook::EVENT_REMIND_INVOICE, $invoice, $invoice->company);
|
WebhookHandler::dispatch(Webhook::EVENT_REMIND_INVOICE, $invoice, $invoice->company);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -128,9 +128,9 @@ class SendReminders implements ShouldQueue
|
|||||||
$set_reminder3 = false;
|
$set_reminder3 = false;
|
||||||
|
|
||||||
if ((int)$settings->schedule_reminder1 > 0) {
|
if ((int)$settings->schedule_reminder1 > 0) {
|
||||||
$next_reminder_date = $this->calculateScheduledDate($invoice, (int)$settings->schedule_reminder1, (int)$settings->num_days_reminder1);
|
$next_reminder_date = $this->calculateScheduledDate($invoice, $settings->schedule_reminder1, (int)$settings->num_days_reminder1);
|
||||||
|
|
||||||
if ($next_reminder_date->gt(Carbon::parse($invoice->last_sent_date)));
|
if ($next_reminder_date && $next_reminder_date->gt(Carbon::parse($invoice->last_sent_date)));
|
||||||
$dates->push($next_reminder_date);
|
$dates->push($next_reminder_date);
|
||||||
|
|
||||||
if (!$invoice->reminder1_sent) {
|
if (!$invoice->reminder1_sent) {
|
||||||
@ -139,20 +139,20 @@ class SendReminders implements ShouldQueue
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((int)$settings->num_days_reminder2 > 0) {
|
if ((int)$settings->num_days_reminder2 > 0) {
|
||||||
$next_reminder_date = $this->calculateScheduledDate($invoice, (int)$settings->schedule_reminder2, (int)$settings->num_days_reminder2);
|
$next_reminder_date = $this->calculateScheduledDate($invoice, $settings->schedule_reminder2, (int)$settings->num_days_reminder2);
|
||||||
|
|
||||||
if ($next_reminder_date->gt(Carbon::parse($invoice->last_sent_date)));
|
if ($next_reminder_date && $next_reminder_date->gt(Carbon::parse($invoice->last_sent_date)));
|
||||||
$dates->push($next_reminder_date);
|
$dates->push($next_reminder_date);
|
||||||
|
|
||||||
if (!$invoice->reminder2_sent) {
|
if (!$invoice->reminder2_sent) {
|
||||||
$set_reminder3 = true;
|
$set_reminder2 = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((int)$settings->num_days_reminder3 > 0) {
|
if ((int)$settings->num_days_reminder3 > 0) {
|
||||||
$next_reminder_date = $this->calculateScheduledDate($invoice, (int)$settings->schedule_reminder3, (int)$settings->num_days_reminder3);
|
$next_reminder_date = $this->calculateScheduledDate($invoice, $settings->schedule_reminder3, (int)$settings->num_days_reminder3);
|
||||||
|
|
||||||
if ($next_reminder_date->gt(Carbon::parse($invoice->last_sent_date)));
|
if ($next_reminder_date && $next_reminder_date->gt(Carbon::parse($invoice->last_sent_date)));
|
||||||
$dates->push($next_reminder_date);
|
$dates->push($next_reminder_date);
|
||||||
|
|
||||||
if (!$invoice->reminder3_sent) {
|
if (!$invoice->reminder3_sent) {
|
||||||
@ -178,15 +178,17 @@ class SendReminders implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
private function calculateScheduledDate($invoice, $schedule_reminder, $num_days_reminder) :?Carbon
|
private function calculateScheduledDate($invoice, $schedule_reminder, $num_days_reminder) :?Carbon
|
||||||
{
|
{
|
||||||
|
$offset = $invoice->client->timezone_offset();
|
||||||
|
|
||||||
switch ($schedule_reminder) {
|
switch ($schedule_reminder) {
|
||||||
case 'after_invoice_date':
|
case 'after_invoice_date':
|
||||||
return Carbon::parse($invoice->date)->addDays($num_days_reminder)->startOfDay();
|
return Carbon::parse($invoice->date)->addDays($num_days_reminder)->startOfDay()->addSeconds($offset);
|
||||||
break;
|
break;
|
||||||
case 'before_due_date':
|
case 'before_due_date':
|
||||||
return Carbon::parse($invoice->due_date)->subDays($num_days_reminder)->startOfDay();
|
return Carbon::parse($invoice->due_date)->subDays($num_days_reminder)->startOfDay()->addSeconds($offset);
|
||||||
break;
|
break;
|
||||||
case 'after_due_date':
|
case 'after_due_date':
|
||||||
return Carbon::parse($invoice->due_date)->addDays($num_days_reminder)->startOfDay();
|
return Carbon::parse($invoice->due_date)->addDays($num_days_reminder)->startOfDay()->addSeconds($offset);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
@ -211,7 +213,8 @@ class SendReminders implements ShouldQueue
|
|||||||
if ($this->checkSendSetting($invoice, $template) && $invoice->company->account->hasFeature(Account::FEATURE_EMAIL_TEMPLATES_REMINDERS)) {
|
if ($this->checkSendSetting($invoice, $template) && $invoice->company->account->hasFeature(Account::FEATURE_EMAIL_TEMPLATES_REMINDERS)) {
|
||||||
nlog("firing email");
|
nlog("firing email");
|
||||||
|
|
||||||
EmailEntity::dispatchNow($invitation, $invitation->company, $template);
|
EmailEntity::dispatchNow($invitation, $invitation->company, $template)->delay(now()->addSeconds(60));
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -219,15 +222,16 @@ class SendReminders implements ShouldQueue
|
|||||||
if ($this->checkSendSetting($invoice, $template)) {
|
if ($this->checkSendSetting($invoice, $template)) {
|
||||||
event(new InvoiceWasEmailed($invoice->invitations->first(), $invoice->company, Ninja::eventVars(), $template));
|
event(new InvoiceWasEmailed($invoice->invitations->first(), $invoice->company, Ninja::eventVars(), $template));
|
||||||
}
|
}
|
||||||
|
|
||||||
$invoice->last_sent_date = now();
|
$invoice->last_sent_date = now();
|
||||||
$invoice->next_send_date = $this->calculateNextSendDate($invoice);
|
$invoice->next_send_date = $this->calculateNextSendDate($invoice);
|
||||||
|
|
||||||
if (in_array($template, ['reminder1', 'reminder2', 'reminder3'])) {
|
if (in_array($template, ['reminder1', 'reminder2', 'reminder3'])) {
|
||||||
$invoice->{$template."_sent"} = now();
|
$invoice->{$template."_sent"} = now();
|
||||||
}
|
}
|
||||||
|
$invoice->service()->touchReminder($template)->save();
|
||||||
|
|
||||||
$invoice->save();
|
// $invoice->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -70,9 +70,9 @@ class SendRecurring implements ShouldQueue
|
|||||||
|
|
||||||
nlog("updating recurring invoice dates");
|
nlog("updating recurring invoice dates");
|
||||||
/* Set next date here to prevent a recurring loop forming */
|
/* Set next date here to prevent a recurring loop forming */
|
||||||
$this->recurring_invoice->next_send_date = $this->recurring_invoice->nextSendDate()->format('Y-m-d');
|
$this->recurring_invoice->next_send_date = $this->recurring_invoice->nextSendDate();
|
||||||
$this->recurring_invoice->remaining_cycles = $this->recurring_invoice->remainingCycles();
|
$this->recurring_invoice->remaining_cycles = $this->recurring_invoice->remainingCycles();
|
||||||
$this->recurring_invoice->last_sent_date = date('Y-m-d');
|
$this->recurring_invoice->last_sent_date = now();
|
||||||
|
|
||||||
/* Set completed if we don't have any more cycles remaining*/
|
/* Set completed if we don't have any more cycles remaining*/
|
||||||
if ($this->recurring_invoice->remaining_cycles == 0) {
|
if ($this->recurring_invoice->remaining_cycles == 0) {
|
||||||
@ -96,7 +96,7 @@ class SendRecurring implements ShouldQueue
|
|||||||
if ($invitation->contact && strlen($invitation->contact->email) >=1) {
|
if ($invitation->contact && strlen($invitation->contact->email) >=1) {
|
||||||
|
|
||||||
try{
|
try{
|
||||||
EmailEntity::dispatch($invitation, $invoice->company);
|
EmailEntity::dispatch($invitation, $invoice->company)->delay(now()->addSeconds(60));
|
||||||
}
|
}
|
||||||
catch(\Exception $e) {
|
catch(\Exception $e) {
|
||||||
nlog($e->getMessage());
|
nlog($e->getMessage());
|
||||||
|
@ -929,7 +929,7 @@ class Import implements ShouldQueue
|
|||||||
|
|
||||||
$modified['client_id'] = $this->transformId('clients', $resource['client_id']);
|
$modified['client_id'] = $this->transformId('clients', $resource['client_id']);
|
||||||
|
|
||||||
if(array_key_exists('invoice_id', $resource) && $this->tryTransformingId('invoices', $resource['invoice_id']))
|
if(array_key_exists('invoice_id', $resource) && isset($resource['invoice_id']) && $this->tryTransformingId('invoices', $resource['invoice_id']))
|
||||||
$modified['invoice_id'] = $this->transformId('invoices', $resource['invoice_id']);
|
$modified['invoice_id'] = $this->transformId('invoices', $resource['invoice_id']);
|
||||||
|
|
||||||
$modified['user_id'] = $this->processUserId($resource);
|
$modified['user_id'] = $this->processUserId($resource);
|
||||||
|
@ -53,14 +53,14 @@ class ReminderJob implements ShouldQueue
|
|||||||
|
|
||||||
private function processReminders()
|
private function processReminders()
|
||||||
{
|
{
|
||||||
Invoice::where('next_send_date', Carbon::today()->format('Y-m-d'))->with('invitations')->cursor()->each(function ($invoice) {
|
Invoice::whereDate('next_send_date', '<=', now())->with('invitations')->cursor()->each(function ($invoice) {
|
||||||
|
|
||||||
if ($invoice->isPayable()) {
|
if ($invoice->isPayable()) {
|
||||||
$reminder_template = $invoice->calculateTemplate('invoice');
|
$reminder_template = $invoice->calculateTemplate('invoice');
|
||||||
$invoice->service()->touchReminder($reminder_template)->save();
|
$invoice->service()->touchReminder($reminder_template)->save();
|
||||||
|
|
||||||
$invoice->invitations->each(function ($invitation) use ($invoice, $reminder_template) {
|
$invoice->invitations->each(function ($invitation) use ($invoice, $reminder_template) {
|
||||||
EmailEntity::dispatch($invitation, $invitation->company, $reminder_template);
|
EmailEntity::dispatch($invitation, $invitation->company, $reminder_template)->delay(now()->addSeconds(60));
|
||||||
nlog("Firing reminder email for invoice {$invoice->number}");
|
nlog("Firing reminder email for invoice {$invoice->number}");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ class SendFailedEmails implements ShouldQueue
|
|||||||
|
|
||||||
if ($invitation->invoice) {
|
if ($invitation->invoice) {
|
||||||
if ($invitation->contact->send_email && $invitation->contact->email) {
|
if ($invitation->contact->send_email && $invitation->contact->email) {
|
||||||
EmailEntity::dispatch($invitation, $invitation->company, $job_meta_array['reminder_template']);
|
EmailEntity::dispatch($invitation, $invitation->company, $job_meta_array['reminder_template'])->delay(now()->addSeconds(60));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
*
|
*
|
||||||
* @license https://opensource.org/licenses/AAL
|
* @license https://opensource.org/licenses/AAL
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace App\Jobs\Util;
|
namespace App\Jobs\Util;
|
||||||
|
|
||||||
use App\Jobs\Util\SystemLogger;
|
use App\Jobs\Util\SystemLogger;
|
||||||
|
@ -34,11 +34,11 @@ class OAuth
|
|||||||
* @param Socialite $user
|
* @param Socialite $user
|
||||||
* @return bool|\App\Models\User|\App\Libraries\App\Models\User|null
|
* @return bool|\App\Models\User|\App\Libraries\App\Models\User|null
|
||||||
*/
|
*/
|
||||||
public static function handleAuth(Socialite $user)
|
public static function handleAuth($socialite_user, $provider)
|
||||||
{
|
{
|
||||||
/** 1. Ensure user arrives on the correct provider **/
|
/** 1. Ensure user arrives on the correct provider **/
|
||||||
$query = [
|
$query = [
|
||||||
'oauth_user_id' =>$user->getId(),
|
'oauth_user_id' =>$socialite_user->getId(),
|
||||||
'oauth_provider_id'=>$provider,
|
'oauth_provider_id'=>$provider,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -47,6 +47,9 @@ class CreditEmailEngine extends BaseEmailEngine
|
|||||||
$t = app('translator');
|
$t = app('translator');
|
||||||
$t->replace(Ninja::transformTranslations($this->client->getMergedSettings()));
|
$t->replace(Ninja::transformTranslations($this->client->getMergedSettings()));
|
||||||
|
|
||||||
|
if($this->reminder_template == 'endless_reminder')
|
||||||
|
$this->reminder_template = 'reminder_endless';
|
||||||
|
|
||||||
if (is_array($this->template_data) && array_key_exists('body', $this->template_data) && strlen($this->template_data['body']) > 0) {
|
if (is_array($this->template_data) && array_key_exists('body', $this->template_data) && strlen($this->template_data['body']) > 0) {
|
||||||
$body_template = $this->template_data['body'];
|
$body_template = $this->template_data['body'];
|
||||||
} else {
|
} else {
|
||||||
|
@ -50,6 +50,9 @@ class InvoiceEmailEngine extends BaseEmailEngine
|
|||||||
$t = app('translator');
|
$t = app('translator');
|
||||||
$t->replace(Ninja::transformTranslations($this->client->getMergedSettings()));
|
$t->replace(Ninja::transformTranslations($this->client->getMergedSettings()));
|
||||||
|
|
||||||
|
if($this->reminder_template == 'endless_reminder')
|
||||||
|
$this->reminder_template = 'reminder_endless';
|
||||||
|
|
||||||
if (is_array($this->template_data) && array_key_exists('body', $this->template_data) && strlen($this->template_data['body']) > 0) {
|
if (is_array($this->template_data) && array_key_exists('body', $this->template_data) && strlen($this->template_data['body']) > 0) {
|
||||||
$body_template = $this->template_data['body'];
|
$body_template = $this->template_data['body'];
|
||||||
} elseif (strlen($this->client->getSetting('email_template_'.$this->reminder_template)) > 0) {
|
} elseif (strlen($this->client->getSetting('email_template_'.$this->reminder_template)) > 0) {
|
||||||
|
@ -47,6 +47,9 @@ class QuoteEmailEngine extends BaseEmailEngine
|
|||||||
App::forgetInstance('translator');
|
App::forgetInstance('translator');
|
||||||
$t = app('translator');
|
$t = app('translator');
|
||||||
$t->replace(Ninja::transformTranslations($this->client->getMergedSettings()));
|
$t->replace(Ninja::transformTranslations($this->client->getMergedSettings()));
|
||||||
|
|
||||||
|
if($this->reminder_template == 'endless_reminder')
|
||||||
|
$this->reminder_template = 'reminder_endless';
|
||||||
|
|
||||||
if (is_array($this->template_data) && array_key_exists('body', $this->template_data) && strlen($this->template_data['body']) > 0) {
|
if (is_array($this->template_data) && array_key_exists('body', $this->template_data) && strlen($this->template_data['body']) > 0) {
|
||||||
$body_template = $this->template_data['body'];
|
$body_template = $this->template_data['body'];
|
||||||
|
@ -105,9 +105,6 @@ class Account extends BaseModel
|
|||||||
return $this->hasOne(Company::class, 'id', 'default_company_id');
|
return $this->hasOne(Company::class, 'id', 'default_company_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return BelongsTo
|
|
||||||
*/
|
|
||||||
public function payment()
|
public function payment()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Payment::class)->withTrashed();
|
return $this->belongsTo(Payment::class)->withTrashed();
|
||||||
@ -323,4 +320,5 @@ class Account extends BaseModel
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ use App\DataMapper\ClientSettings;
|
|||||||
use App\DataMapper\CompanySettings;
|
use App\DataMapper\CompanySettings;
|
||||||
use App\Models\Presenters\ClientPresenter;
|
use App\Models\Presenters\ClientPresenter;
|
||||||
use App\Services\Client\ClientService;
|
use App\Services\Client\ClientService;
|
||||||
|
use App\Utils\Traits\AppSetup;
|
||||||
use App\Utils\Traits\GeneratesCounter;
|
use App\Utils\Traits\GeneratesCounter;
|
||||||
use App\Utils\Traits\MakesDates;
|
use App\Utils\Traits\MakesDates;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
@ -32,6 +33,7 @@ class Client extends BaseModel implements HasLocalePreference
|
|||||||
use SoftDeletes;
|
use SoftDeletes;
|
||||||
use Filterable;
|
use Filterable;
|
||||||
use GeneratesCounter;
|
use GeneratesCounter;
|
||||||
|
use AppSetup;
|
||||||
|
|
||||||
protected $presenter = ClientPresenter::class;
|
protected $presenter = ClientPresenter::class;
|
||||||
|
|
||||||
@ -230,13 +232,16 @@ class Client extends BaseModel implements HasLocalePreference
|
|||||||
|
|
||||||
public function language()
|
public function language()
|
||||||
{
|
{
|
||||||
//return Language::find($this->getSetting('language_id'));
|
|
||||||
|
|
||||||
$languages = Cache::get('languages');
|
$languages = Cache::get('languages');
|
||||||
|
|
||||||
|
if(!$languages)
|
||||||
|
$this->buildCache(true);
|
||||||
|
|
||||||
return $languages->filter(function ($item) {
|
return $languages->filter(function ($item) {
|
||||||
return $item->id == $this->getSetting('language_id');
|
return $item->id == $this->getSetting('language_id');
|
||||||
})->first();
|
})->first();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function locale()
|
public function locale()
|
||||||
@ -257,6 +262,9 @@ class Client extends BaseModel implements HasLocalePreference
|
|||||||
{
|
{
|
||||||
$currencies = Cache::get('currencies');
|
$currencies = Cache::get('currencies');
|
||||||
|
|
||||||
|
if(!$currencies)
|
||||||
|
$this->buildCache(true);
|
||||||
|
|
||||||
return $currencies->filter(function ($item) {
|
return $currencies->filter(function ($item) {
|
||||||
return $item->id == $this->getSetting('currency_id');
|
return $item->id == $this->getSetting('currency_id');
|
||||||
})->first();
|
})->first();
|
||||||
@ -622,6 +630,9 @@ class Client extends BaseModel implements HasLocalePreference
|
|||||||
{
|
{
|
||||||
$languages = Cache::get('languages');
|
$languages = Cache::get('languages');
|
||||||
|
|
||||||
|
if(!$languages)
|
||||||
|
$this->buildCache(true);
|
||||||
|
|
||||||
return $languages->filter(function ($item) {
|
return $languages->filter(function ($item) {
|
||||||
return $item->id == $this->getSetting('language_id');
|
return $item->id == $this->getSetting('language_id');
|
||||||
})->first()->locale;
|
})->first()->locale;
|
||||||
@ -684,4 +695,21 @@ class Client extends BaseModel implements HasLocalePreference
|
|||||||
{
|
{
|
||||||
return $this->hasMany(Payment::class);
|
return $this->hasMany(Payment::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function timezone_offset()
|
||||||
|
{
|
||||||
|
$offset = 0;
|
||||||
|
|
||||||
|
$entity_send_time = $this->getSetting('entity_send_time');
|
||||||
|
|
||||||
|
if($entity_send_time == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
$timezone = $this->company->timezone();
|
||||||
|
|
||||||
|
$offset -= $timezone->utc_offset;
|
||||||
|
$offset += ($entity_send_time * 3600);
|
||||||
|
|
||||||
|
return $offset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,34 +220,35 @@ class RecurringInvoice extends BaseModel
|
|||||||
{
|
{
|
||||||
if (!$this->next_send_date) {
|
if (!$this->next_send_date) {
|
||||||
return null;
|
return null;
|
||||||
// $this->next_send_date = now()->format('Y-m-d');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$offset = $this->client->timezone_offset();
|
||||||
|
|
||||||
switch ($this->frequency_id) {
|
switch ($this->frequency_id) {
|
||||||
case self::FREQUENCY_DAILY:
|
case self::FREQUENCY_DAILY:
|
||||||
return Carbon::parse($this->next_send_date)->addDay();
|
return Carbon::parse($this->next_send_date)->startOfDay()->addDay()->addSeconds($offset);
|
||||||
case self::FREQUENCY_WEEKLY:
|
case self::FREQUENCY_WEEKLY:
|
||||||
return Carbon::parse($this->next_send_date)->addWeek();
|
return Carbon::parse($this->next_send_date)->startOfDay()->addWeek()->addSeconds($offset);
|
||||||
case self::FREQUENCY_TWO_WEEKS:
|
case self::FREQUENCY_TWO_WEEKS:
|
||||||
return Carbon::parse($this->next_send_date)->addWeeks(2);
|
return Carbon::parse($this->next_send_date)->startOfDay()->addWeeks(2)->addSeconds($offset);
|
||||||
case self::FREQUENCY_FOUR_WEEKS:
|
case self::FREQUENCY_FOUR_WEEKS:
|
||||||
return Carbon::parse($this->next_send_date)->addWeeks(4);
|
return Carbon::parse($this->next_send_date)->startOfDay()->addWeeks(4)->addSeconds($offset);
|
||||||
case self::FREQUENCY_MONTHLY:
|
case self::FREQUENCY_MONTHLY:
|
||||||
return Carbon::parse($this->next_send_date)->addMonthNoOverflow();
|
return Carbon::parse($this->next_send_date)->startOfDay()->addMonthNoOverflow()->addSeconds($offset);
|
||||||
case self::FREQUENCY_TWO_MONTHS:
|
case self::FREQUENCY_TWO_MONTHS:
|
||||||
return Carbon::parse($this->next_send_date)->addMonthsNoOverflow(2);
|
return Carbon::parse($this->next_send_date)->startOfDay()->addMonthsNoOverflow(2)->addSeconds($offset);
|
||||||
case self::FREQUENCY_THREE_MONTHS:
|
case self::FREQUENCY_THREE_MONTHS:
|
||||||
return Carbon::parse($this->next_send_date)->addMonthsNoOverflow(3);
|
return Carbon::parse($this->next_send_date)->startOfDay()->addMonthsNoOverflow(3)->addSeconds($offset);
|
||||||
case self::FREQUENCY_FOUR_MONTHS:
|
case self::FREQUENCY_FOUR_MONTHS:
|
||||||
return Carbon::parse($this->next_send_date)->addMonthsNoOverflow(4);
|
return Carbon::parse($this->next_send_date)->startOfDay()->addMonthsNoOverflow(4)->addSeconds($offset);
|
||||||
case self::FREQUENCY_SIX_MONTHS:
|
case self::FREQUENCY_SIX_MONTHS:
|
||||||
return Carbon::parse($this->next_send_date)->addMonthsNoOverflow(6);
|
return Carbon::parse($this->next_send_date)->startOfDay()->addMonthsNoOverflow(6)->addSeconds($offset);
|
||||||
case self::FREQUENCY_ANNUALLY:
|
case self::FREQUENCY_ANNUALLY:
|
||||||
return Carbon::parse($this->next_send_date)->addYear();
|
return Carbon::parse($this->next_send_date)->startOfDay()->addYear()->addSeconds($offset);
|
||||||
case self::FREQUENCY_TWO_YEARS:
|
case self::FREQUENCY_TWO_YEARS:
|
||||||
return Carbon::parse($this->next_send_date)->addYears(2);
|
return Carbon::parse($this->next_send_date)->startOfDay()->addYears(2)->addSeconds($offset);
|
||||||
case self::FREQUENCY_THREE_YEARS:
|
case self::FREQUENCY_THREE_YEARS:
|
||||||
return Carbon::parse($this->next_send_date)->addYears(3);
|
return Carbon::parse($this->next_send_date)->startOfDay()->addYears(3)->addSeconds($offset);
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -255,31 +256,33 @@ class RecurringInvoice extends BaseModel
|
|||||||
|
|
||||||
public function nextDateByFrequency($date)
|
public function nextDateByFrequency($date)
|
||||||
{
|
{
|
||||||
|
$offset = $this->client->timezone_offset();
|
||||||
|
|
||||||
switch ($this->frequency_id) {
|
switch ($this->frequency_id) {
|
||||||
case self::FREQUENCY_DAILY:
|
case self::FREQUENCY_DAILY:
|
||||||
return Carbon::parse($date)->addDay();
|
return Carbon::parse($date)->startOfDay()->addDay()->addSeconds($offset);
|
||||||
case self::FREQUENCY_WEEKLY:
|
case self::FREQUENCY_WEEKLY:
|
||||||
return Carbon::parse($date)->addWeek();
|
return Carbon::parse($date)->startOfDay()->addWeek()->addSeconds($offset);
|
||||||
case self::FREQUENCY_TWO_WEEKS:
|
case self::FREQUENCY_TWO_WEEKS:
|
||||||
return Carbon::parse($date)->addWeeks(2);
|
return Carbon::parse($date)->startOfDay()->addWeeks(2)->addSeconds($offset);
|
||||||
case self::FREQUENCY_FOUR_WEEKS:
|
case self::FREQUENCY_FOUR_WEEKS:
|
||||||
return Carbon::parse($date)->addWeeks(4);
|
return Carbon::parse($date)->startOfDay()->addWeeks(4)->addSeconds($offset);
|
||||||
case self::FREQUENCY_MONTHLY:
|
case self::FREQUENCY_MONTHLY:
|
||||||
return Carbon::parse($date)->addMonthNoOverflow();
|
return Carbon::parse($date)->startOfDay()->addMonthNoOverflow()->addSeconds($offset);
|
||||||
case self::FREQUENCY_TWO_MONTHS:
|
case self::FREQUENCY_TWO_MONTHS:
|
||||||
return Carbon::parse($date)->addMonthsNoOverflow(2);
|
return Carbon::parse($date)->startOfDay()->addMonthsNoOverflow(2)->addSeconds($offset);
|
||||||
case self::FREQUENCY_THREE_MONTHS:
|
case self::FREQUENCY_THREE_MONTHS:
|
||||||
return Carbon::parse($date)->addMonthsNoOverflow(3);
|
return Carbon::parse($date)->startOfDay()->addMonthsNoOverflow(3)->addSeconds($offset);
|
||||||
case self::FREQUENCY_FOUR_MONTHS:
|
case self::FREQUENCY_FOUR_MONTHS:
|
||||||
return Carbon::parse($date)->addMonthsNoOverflow(4);
|
return Carbon::parse($date)->startOfDay()->addMonthsNoOverflow(4)->addSeconds($offset);
|
||||||
case self::FREQUENCY_SIX_MONTHS:
|
case self::FREQUENCY_SIX_MONTHS:
|
||||||
return Carbon::parse($date)->addMonthsNoOverflow(6);
|
return Carbon::parse($date)->addMonthsNoOverflow(6)->addSeconds($offset);
|
||||||
case self::FREQUENCY_ANNUALLY:
|
case self::FREQUENCY_ANNUALLY:
|
||||||
return Carbon::parse($date)->addYear();
|
return Carbon::parse($date)->startOfDay()->addYear()->addSeconds($offset);
|
||||||
case self::FREQUENCY_TWO_YEARS:
|
case self::FREQUENCY_TWO_YEARS:
|
||||||
return Carbon::parse($date)->addYears(2);
|
return Carbon::parse($date)->startOfDay()->addYears(2)->addSeconds($offset);
|
||||||
case self::FREQUENCY_THREE_YEARS:
|
case self::FREQUENCY_THREE_YEARS:
|
||||||
return Carbon::parse($date)->addYears(3);
|
return Carbon::parse($date)->startOfDay()->addYears(3)->addSeconds($offset);
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ class ClientRepository extends BaseRepository
|
|||||||
if (empty($data['name'])) {
|
if (empty($data['name'])) {
|
||||||
$data['name'] = $client->present()->name();
|
$data['name'] = $client->present()->name();
|
||||||
}
|
}
|
||||||
|
|
||||||
$client->save();
|
$client->save();
|
||||||
|
|
||||||
$this->contact_repo->save($data, $client);
|
$this->contact_repo->save($data, $client);
|
||||||
|
@ -376,7 +376,9 @@ class InvoiceService
|
|||||||
$this->invoice->reminder3_sent = now()->format('Y-m-d');
|
$this->invoice->reminder3_sent = now()->format('Y-m-d');
|
||||||
$this->invoice->reminder_last_sent = now()->format('Y-m-d');
|
$this->invoice->reminder_last_sent = now()->format('Y-m-d');
|
||||||
break;
|
break;
|
||||||
|
case 'endless_reminder':
|
||||||
|
$this->invoice->reminder_last_sent = now()->format('Y-m-d');
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
// code...
|
// code...
|
||||||
break;
|
break;
|
||||||
|
@ -62,7 +62,7 @@ class TriggeredActions extends AbstractService
|
|||||||
$reminder_template = 'payment';
|
$reminder_template = 'payment';
|
||||||
|
|
||||||
$this->invoice->invitations->load('contact.client.country', 'invoice.client.country', 'invoice.company')->each(function ($invitation) use ($reminder_template) {
|
$this->invoice->invitations->load('contact.client.country', 'invoice.client.country', 'invoice.company')->each(function ($invitation) use ($reminder_template) {
|
||||||
EmailEntity::dispatch($invitation, $this->invoice->company, $reminder_template);
|
EmailEntity::dispatch($invitation, $this->invoice->company, $reminder_template)->delay(now()->addSeconds(60));
|
||||||
});
|
});
|
||||||
|
|
||||||
if ($this->invoice->invitations->count() > 0) {
|
if ($this->invoice->invitations->count() > 0) {
|
||||||
|
@ -41,87 +41,89 @@ class UpdateReminder extends AbstractService
|
|||||||
return $this->invoice; //exit early
|
return $this->invoice; //exit early
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$offset = $this->invoice->client->timezone_offset();
|
||||||
|
|
||||||
$date_collection = collect();
|
$date_collection = collect();
|
||||||
|
|
||||||
if (is_null($this->invoice->reminder1_sent) &&
|
if (is_null($this->invoice->reminder1_sent) &&
|
||||||
$this->settings->schedule_reminder1 == 'after_invoice_date' &&
|
$this->settings->schedule_reminder1 == 'after_invoice_date' &&
|
||||||
$this->settings->num_days_reminder1 > 0) {
|
$this->settings->num_days_reminder1 > 0) {
|
||||||
$reminder_date = Carbon::parse($this->invoice->date)->addDays($this->settings->num_days_reminder1);
|
$reminder_date = Carbon::parse($this->invoice->date)->startOfDay()->addDays($this->settings->num_days_reminder1)->addSeconds($offset);
|
||||||
|
|
||||||
if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date)));
|
if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date)));
|
||||||
$date_collection->push($reminder_date->format('Y-m-d'));
|
$date_collection->push($reminder_date);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_null($this->invoice->reminder1_sent) &&
|
if (is_null($this->invoice->reminder1_sent) &&
|
||||||
$this->settings->schedule_reminder1 == 'before_due_date' &&
|
$this->settings->schedule_reminder1 == 'before_due_date' &&
|
||||||
$this->settings->num_days_reminder1 > 0) {
|
$this->settings->num_days_reminder1 > 0) {
|
||||||
$reminder_date = Carbon::parse($this->invoice->due_date)->subDays($this->settings->num_days_reminder1);
|
$reminder_date = Carbon::parse($this->invoice->due_date)->startOfDay()->subDays($this->settings->num_days_reminder1)->addSeconds($offset);
|
||||||
|
|
||||||
if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date)));
|
if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date)));
|
||||||
$date_collection->push($reminder_date->format('Y-m-d'));
|
$date_collection->push($reminder_date);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_null($this->invoice->reminder1_sent) &&
|
if (is_null($this->invoice->reminder1_sent) &&
|
||||||
$this->settings->schedule_reminder1 == 'after_due_date' &&
|
$this->settings->schedule_reminder1 == 'after_due_date' &&
|
||||||
$this->settings->num_days_reminder1 > 0) {
|
$this->settings->num_days_reminder1 > 0) {
|
||||||
$reminder_date = Carbon::parse($this->invoice->due_date)->addDays($this->settings->num_days_reminder1);
|
$reminder_date = Carbon::parse($this->invoice->due_date)->startOfDay()->addDays($this->settings->num_days_reminder1)->addSeconds($offset);
|
||||||
|
|
||||||
if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date)));
|
if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date)));
|
||||||
$date_collection->push($reminder_date->format('Y-m-d'));
|
$date_collection->push($reminder_date);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_null($this->invoice->reminder2_sent) &&
|
if (is_null($this->invoice->reminder2_sent) &&
|
||||||
$this->settings->schedule_reminder2 == 'after_invoice_date' &&
|
$this->settings->schedule_reminder2 == 'after_invoice_date' &&
|
||||||
$this->settings->num_days_reminder2 > 0) {
|
$this->settings->num_days_reminder2 > 0) {
|
||||||
$reminder_date = Carbon::parse($this->invoice->date)->addDays($this->settings->num_days_reminder2);
|
$reminder_date = Carbon::parse($this->invoice->date)->startOfDay()->addDays($this->settings->num_days_reminder2)->addSeconds($offset);
|
||||||
|
|
||||||
if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date)));
|
if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date)));
|
||||||
$date_collection->push($reminder_date->format('Y-m-d'));
|
$date_collection->push($reminder_date);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_null($this->invoice->reminder2_sent) &&
|
if (is_null($this->invoice->reminder2_sent) &&
|
||||||
$this->settings->schedule_reminder2 == 'before_due_date' &&
|
$this->settings->schedule_reminder2 == 'before_due_date' &&
|
||||||
$this->settings->num_days_reminder2 > 0) {
|
$this->settings->num_days_reminder2 > 0) {
|
||||||
$reminder_date = Carbon::parse($this->invoice->due_date)->subDays($this->settings->num_days_reminder2);
|
$reminder_date = Carbon::parse($this->invoice->due_date)->startOfDay()->subDays($this->settings->num_days_reminder2)->addSeconds($offset);
|
||||||
|
|
||||||
if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date)));
|
if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date)));
|
||||||
$date_collection->push($reminder_date->format('Y-m-d'));
|
$date_collection->push($reminder_date);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_null($this->invoice->reminder2_sent) &&
|
if (is_null($this->invoice->reminder2_sent) &&
|
||||||
$this->settings->schedule_reminder2 == 'after_due_date' &&
|
$this->settings->schedule_reminder2 == 'after_due_date' &&
|
||||||
$this->settings->num_days_reminder2 > 0) {
|
$this->settings->num_days_reminder2 > 0) {
|
||||||
$reminder_date = Carbon::parse($this->invoice->due_date)->addDays($this->settings->num_days_reminder2);
|
$reminder_date = Carbon::parse($this->invoice->due_date)->startOfDay()->addDays($this->settings->num_days_reminder2)->addSeconds($offset);
|
||||||
|
|
||||||
if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date)));
|
if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date)));
|
||||||
$date_collection->push($reminder_date->format('Y-m-d'));
|
$date_collection->push($reminder_date);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_null($this->invoice->reminder3_sent) &&
|
if (is_null($this->invoice->reminder3_sent) &&
|
||||||
$this->settings->schedule_reminder3 == 'after_invoice_date' &&
|
$this->settings->schedule_reminder3 == 'after_invoice_date' &&
|
||||||
$this->settings->num_days_reminder3 > 0) {
|
$this->settings->num_days_reminder3 > 0) {
|
||||||
$reminder_date = Carbon::parse($this->invoice->date)->addDays($this->settings->num_days_reminder3);
|
$reminder_date = Carbon::parse($this->invoice->date)->startOfDay()->addDays($this->settings->num_days_reminder3)->addSeconds($offset);
|
||||||
|
|
||||||
if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date)));
|
if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date)));
|
||||||
$date_collection->push($reminder_date->format('Y-m-d'));
|
$date_collection->push($reminder_date);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_null($this->invoice->reminder3_sent) &&
|
if (is_null($this->invoice->reminder3_sent) &&
|
||||||
$this->settings->schedule_reminder3 == 'before_due_date' &&
|
$this->settings->schedule_reminder3 == 'before_due_date' &&
|
||||||
$this->settings->num_days_reminder3 > 0) {
|
$this->settings->num_days_reminder3 > 0) {
|
||||||
$reminder_date = Carbon::parse($this->invoice->due_date)->subDays($this->settings->num_days_reminder3);
|
$reminder_date = Carbon::parse($this->invoice->due_date)->startOfDay()->subDays($this->settings->num_days_reminder3)->addSeconds($offset);
|
||||||
|
|
||||||
if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date)));
|
if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date)));
|
||||||
$date_collection->push($reminder_date->format('Y-m-d'));
|
$date_collection->push($reminder_date);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_null($this->invoice->reminder3_sent) &&
|
if (is_null($this->invoice->reminder3_sent) &&
|
||||||
$this->settings->schedule_reminder3 == 'after_due_date' &&
|
$this->settings->schedule_reminder3 == 'after_due_date' &&
|
||||||
$this->settings->num_days_reminder3 > 0) {
|
$this->settings->num_days_reminder3 > 0) {
|
||||||
$reminder_date = Carbon::parse($this->invoice->due_date)->addDays($this->settings->num_days_reminder3);
|
$reminder_date = Carbon::parse($this->invoice->due_date)->startOfDay()->addDays($this->settings->num_days_reminder3)->addSeconds($offset);
|
||||||
|
|
||||||
if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date)));
|
if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date)));
|
||||||
$date_collection->push($reminder_date->format('Y-m-d'));
|
$date_collection->push($reminder_date);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->invoice->next_send_date = $date_collection->sort()->first();
|
$this->invoice->next_send_date = $date_collection->sort()->first();
|
||||||
|
@ -51,7 +51,7 @@ class CompanyUserTransformer extends EntityTransformer
|
|||||||
'archived_at' => (int) $company_user->deleted_at,
|
'archived_at' => (int) $company_user->deleted_at,
|
||||||
'created_at' => (int) $company_user->created_at,
|
'created_at' => (int) $company_user->created_at,
|
||||||
'permissions_updated_at' => (int) $company_user->permissions_updated_at,
|
'permissions_updated_at' => (int) $company_user->permissions_updated_at,
|
||||||
//'number_years_active' => (int) $company_user->number_years_active,
|
'ninja_portal_url' => (string) $company_user->ninja_portal_url,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,20 +51,20 @@ trait MakesReminders
|
|||||||
if ($this->inReminderWindow(
|
if ($this->inReminderWindow(
|
||||||
$client->getSetting('schedule_reminder1'),
|
$client->getSetting('schedule_reminder1'),
|
||||||
$client->getSetting('num_days_reminder1')
|
$client->getSetting('num_days_reminder1')
|
||||||
)) {
|
) && !$this->reminder1_sent) {
|
||||||
return 'reminder1';
|
return 'reminder1';
|
||||||
} elseif ($this->inReminderWindow(
|
} elseif ($this->inReminderWindow(
|
||||||
$client->getSetting('schedule_reminder2'),
|
$client->getSetting('schedule_reminder2'),
|
||||||
$client->getSetting('num_days_reminder2')
|
$client->getSetting('num_days_reminder2')
|
||||||
)) {
|
) && !$this->reminder2_sent) {
|
||||||
return 'reminder2';
|
return 'reminder2';
|
||||||
} elseif ($this->inReminderWindow(
|
} elseif ($this->inReminderWindow(
|
||||||
$client->getSetting('schedule_reminder3'),
|
$client->getSetting('schedule_reminder3'),
|
||||||
$client->getSetting('num_days_reminder3')
|
$client->getSetting('num_days_reminder3')
|
||||||
)) {
|
) && !$this->reminder3_sent) {
|
||||||
return 'reminder3';
|
return 'reminder3';
|
||||||
} elseif ($this->checkEndlessReminder(
|
} elseif ($this->checkEndlessReminder(
|
||||||
$this->last_sent_date,
|
$this->reminder_last_sent,
|
||||||
$client->getSetting('endless_reminder_frequency_id')
|
$client->getSetting('endless_reminder_frequency_id')
|
||||||
)) {
|
)) {
|
||||||
return 'endless_reminder';
|
return 'endless_reminder';
|
||||||
@ -76,7 +76,11 @@ trait MakesReminders
|
|||||||
}
|
}
|
||||||
|
|
||||||
private function checkEndlessReminder($last_sent_date, $endless_reminder_frequency_id) :bool
|
private function checkEndlessReminder($last_sent_date, $endless_reminder_frequency_id) :bool
|
||||||
{
|
{
|
||||||
|
nlog("endless date match = ".$this->addTimeInterval($last_sent_date, $endless_reminder_frequency_id));
|
||||||
|
nlog("Endless reminder bool = ");
|
||||||
|
nlog(Carbon::now()->startOfDay()->eq($this->addTimeInterval($last_sent_date, $endless_reminder_frequency_id)));
|
||||||
|
|
||||||
if (Carbon::now()->startOfDay()->eq($this->addTimeInterval($last_sent_date, $endless_reminder_frequency_id))) {
|
if (Carbon::now()->startOfDay()->eq($this->addTimeInterval($last_sent_date, $endless_reminder_frequency_id))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -85,12 +89,15 @@ trait MakesReminders
|
|||||||
}
|
}
|
||||||
|
|
||||||
private function addTimeInterval($date, $endless_reminder_frequency_id) :?Carbon
|
private function addTimeInterval($date, $endless_reminder_frequency_id) :?Carbon
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!$date)
|
if (!$date)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
switch ($endless_reminder_frequency_id) {
|
switch ($endless_reminder_frequency_id) {
|
||||||
case RecurringInvoice::FREQUENCY_WEEKLY:
|
case RecurringInvoice::FREQUENCY_DAILY:
|
||||||
|
return Carbon::parse($date)->addDay()->startOfDay();
|
||||||
|
case RecurringInvoice::FREQUENCY_WEEKLY:
|
||||||
return Carbon::parse($date)->addWeek()->startOfDay();
|
return Carbon::parse($date)->addWeek()->startOfDay();
|
||||||
case RecurringInvoice::FREQUENCY_TWO_WEEKS:
|
case RecurringInvoice::FREQUENCY_TWO_WEEKS:
|
||||||
return Carbon::parse($date)->addWeeks(2)->startOfDay();
|
return Carbon::parse($date)->addWeeks(2)->startOfDay();
|
||||||
|
@ -14,8 +14,8 @@ return [
|
|||||||
'require_https' => env('REQUIRE_HTTPS', true),
|
'require_https' => env('REQUIRE_HTTPS', true),
|
||||||
'app_url' => rtrim(env('APP_URL', ''), '/'),
|
'app_url' => rtrim(env('APP_URL', ''), '/'),
|
||||||
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
|
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
|
||||||
'app_version' => '5.1.74',
|
'app_version' => '5.2.0',
|
||||||
'app_tag' => '5.1.74-release',
|
'app_tag' => '5.2.0-release',
|
||||||
'minimum_client_version' => '5.0.16',
|
'minimum_client_version' => '5.0.16',
|
||||||
'terms_version' => '1.0.1',
|
'terms_version' => '1.0.1',
|
||||||
'api_secret' => env('API_SECRET', ''),
|
'api_secret' => env('API_SECRET', ''),
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class AddNinjaPortalColumnToAccountsTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('company_user', function (Blueprint $table) {
|
||||||
|
$table->text('ninja_portal_url')->default('');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
2
public/flutter_service_worker.js
vendored
2
public/flutter_service_worker.js
vendored
@ -5,7 +5,7 @@ const CACHE_NAME = 'flutter-app-cache';
|
|||||||
const RESOURCES = {
|
const RESOURCES = {
|
||||||
"version.json": "9fe5b22a16f39b766c8fdc35a24b3efa",
|
"version.json": "9fe5b22a16f39b766c8fdc35a24b3efa",
|
||||||
"favicon.ico": "51636d3a390451561744c42188ccd628",
|
"favicon.ico": "51636d3a390451561744c42188ccd628",
|
||||||
"main.dart.js": "9f05b24849e19debf0c8286556e368e6",
|
"main.dart.js": "33f9288e9a8ba68d21b46b8afda06fbb",
|
||||||
"/": "23224b5e03519aaa87594403d54412cf",
|
"/": "23224b5e03519aaa87594403d54412cf",
|
||||||
"assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "174c02fc4609e8fc4389f5d21f16a296",
|
"assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "174c02fc4609e8fc4389f5d21f16a296",
|
||||||
"assets/AssetManifest.json": "659dcf9d1baf3aed3ab1b9c42112bf8f",
|
"assets/AssetManifest.json": "659dcf9d1baf3aed3ab1b9c42112bf8f",
|
||||||
|
169188
public/main.dart.js
vendored
169188
public/main.dart.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
168238
public/main.foss.dart.js
vendored
168238
public/main.foss.dart.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -7,12 +7,11 @@
|
|||||||
<p>Looks like your migration failed. Here's the error message:</p>
|
<p>Looks like your migration failed. Here's the error message:</p>
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
@if(\App\Utils\Ninja::isHosted())
|
@if(\App\Utils\Ninja::isSelfHost())
|
||||||
{!! $exception->getMessage() !!}
|
{!! $exception->getMessage() !!}
|
||||||
{!! $content !!}
|
{!! $content !!}
|
||||||
@else
|
@else
|
||||||
{!! $exception->getMessage() !!}
|
<p>Please contact us at contact@invoiceninja.com for more information on this error.</p>
|
||||||
{!! $content !!}
|
|
||||||
@endif
|
@endif
|
||||||
</pre>
|
</pre>
|
||||||
@endcomponent
|
@endcomponent
|
||||||
|
@ -77,7 +77,7 @@ class ReminderTest extends TestCase
|
|||||||
$this->invoice->service()->markSent();
|
$this->invoice->service()->markSent();
|
||||||
$this->invoice->service()->setReminder($settings)->save();
|
$this->invoice->service()->setReminder($settings)->save();
|
||||||
|
|
||||||
$this->assertEquals($this->invoice->next_send_date, Carbon::now()->addDays(7)->format('Y-m-d'));
|
$this->assertEquals(Carbon::parse($this->invoice->next_send_date)->format('Y-m-d'), Carbon::now()->addDays(7)->format('Y-m-d'));
|
||||||
|
|
||||||
// ReminderJob::dispatchNow();
|
// ReminderJob::dispatchNow();
|
||||||
}
|
}
|
||||||
@ -106,7 +106,7 @@ class ReminderTest extends TestCase
|
|||||||
|
|
||||||
$this->invoice->fresh();
|
$this->invoice->fresh();
|
||||||
|
|
||||||
$this->assertEquals($this->invoice->next_send_date, now()->format('Y-m-d'));
|
$this->assertEquals(Carbon::parse($this->invoice->next_send_date)->format('Y-m-d'), now()->format('Y-m-d'));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,7 +136,7 @@ class ReminderTest extends TestCase
|
|||||||
|
|
||||||
$this->invoice->fresh();
|
$this->invoice->fresh();
|
||||||
|
|
||||||
$this->assertEquals($this->invoice->next_send_date, now()->format('Y-m-d'));
|
$this->assertEquals(Carbon::parse($this->invoice->next_send_date)->format('Y-m-d'), now()->format('Y-m-d'));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user