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
9b0c860d44
10
CHANGELOG.md
10
CHANGELOG.md
@ -1,11 +1,21 @@
|
||||
# Release notes
|
||||
|
||||
## [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
|
||||
- Improved labelling in the settings (client portal)
|
||||
- Client portal: Multiple accounts access improvements (#5703)
|
||||
- Client portal: "Credits" updates (#5734)
|
||||
- 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)
|
||||
## 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) {
|
||||
$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_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_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])->get()->sum('pivot.refunded');
|
||||
|
||||
$total_invoice_payments += ($total_amount - $total_refund);
|
||||
}
|
||||
|
||||
// 10/02/21
|
||||
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) {
|
||||
@ -347,10 +347,11 @@ class CheckData extends Command
|
||||
$wrong_paid_to_dates = 0;
|
||||
|
||||
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) {
|
||||
$total_amount = $invoice->payments->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment:: STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED])->sum('pivot.amount');
|
||||
$total_refund = $invoice->payments->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment:: STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED])->sum('pivot.refunded');
|
||||
$total_credit = $invoice->credits->sum('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()->get()->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment:: STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED])->sum('pivot.refunded');
|
||||
$total_credit = $invoice->credits()->get()->sum('amount');
|
||||
|
||||
$total_paid = $total_amount - $total_refund;
|
||||
$calculated_paid_amount = $invoice->amount - $invoice->balance - $total_credit;
|
||||
@ -363,6 +364,7 @@ class CheckData extends Command
|
||||
$this->isValid = false;
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
$this->logMessage("{$wrong_balances} clients with incorrect invoice balances");
|
||||
@ -408,8 +410,8 @@ class CheckData extends Command
|
||||
$wrong_paid_to_dates = 0;
|
||||
|
||||
foreach (Client::where('is_deleted', 0)->cursor() as $client) {
|
||||
$invoice_balance = $client->invoices->where('is_deleted', false)->where('status_id', '>', 1)->sum('balance');
|
||||
$credit_balance = $client->credits->where('is_deleted', false)->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)->get()->sum('balance');
|
||||
|
||||
// if($client->balance != $invoice_balance)
|
||||
// $invoice_balance -= $credit_balance;//doesn't make sense to remove the credit amount
|
||||
|
@ -126,9 +126,9 @@ class CheckDb extends Command
|
||||
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_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) {
|
||||
|
||||
$this->LogMessage("V5_DB2");
|
||||
|
||||
$count_db_1 = $entity::on('db-ninja-02')->count();
|
||||
$count_db_2 = $entity::on('db-ninja-01a')->count();
|
||||
|
||||
|
@ -89,7 +89,7 @@ class SendRemindersCron extends Command
|
||||
->cursor();
|
||||
|
||||
$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();
|
||||
|
||||
$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->job(new ReminderJob)->daily()->withoutOverlapping();
|
||||
$schedule->job(new ReminderJob)->hourly()->withoutOverlapping();
|
||||
|
||||
$schedule->job(new CompanySizeCheck)->daily()->withoutOverlapping();
|
||||
|
||||
|
@ -65,6 +65,8 @@ class CompanySettings extends BaseSettings
|
||||
public $auto_convert_quote = true; //@implemented
|
||||
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 $quote_footer = ''; //@implmented
|
||||
|
||||
@ -266,6 +268,7 @@ class CompanySettings extends BaseSettings
|
||||
public $hide_empty_columns_on_pdf = false;
|
||||
|
||||
public static $casts = [
|
||||
'entity_send_time' => 'int',
|
||||
'shared_invoice_credit_counter' => 'bool',
|
||||
'reply_to_name' => 'string',
|
||||
'hide_empty_columns_on_pdf' => 'bool',
|
||||
|
@ -489,38 +489,54 @@ class LoginController extends BaseController
|
||||
|
||||
public function redirectToProvider(string $provider)
|
||||
{
|
||||
//'https://www.googleapis.com/auth/gmail.send','email','profile','openid'
|
||||
|
||||
$scopes = [];
|
||||
|
||||
|
||||
$parameters = [];
|
||||
|
||||
if($provider == 'google'){
|
||||
|
||||
$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')) {
|
||||
return $this->handleProviderCallback($provider);
|
||||
} 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)
|
||||
{
|
||||
$socialite_user = Socialite::driver($provider)
|
||||
->user();
|
||||
$socialite_user = Socialite::driver($provider)->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))
|
||||
{
|
||||
|
||||
nlog('found user and updating their user record');
|
||||
$name = OAuth::splitName($socialite_user->getName());
|
||||
|
||||
$update_user = [
|
||||
'first_name' => $name[0],
|
||||
'last_name' => $name[1],
|
||||
'password' => '',
|
||||
'email' => $socialite_user->getEmail(),
|
||||
'oauth_user_id' => $socialite_user->getId(),
|
||||
'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);
|
||||
|
@ -379,6 +379,15 @@ class ClientController extends BaseController
|
||||
|
||||
$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);
|
||||
|
||||
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);
|
||||
|
||||
$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();
|
||||
|
||||
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\Traits\MakesHash;
|
||||
use App\Utils\Traits\SavesDocuments;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
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)));
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
|
@ -58,6 +58,9 @@ class PasswordProtection
|
||||
$google = new Google();
|
||||
$user = $google->getTokenResponse(request()->header('X-API-OAUTH-PASSWORD'));
|
||||
|
||||
nlog("user");
|
||||
nlog($user);
|
||||
|
||||
if (is_array($user)) {
|
||||
|
||||
$query = [
|
||||
@ -65,14 +68,20 @@ class PasswordProtection
|
||||
'oauth_provider_id'=> 'google'
|
||||
];
|
||||
|
||||
nlog($query);
|
||||
|
||||
//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);
|
||||
|
||||
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);
|
||||
return $next($request);
|
||||
|
@ -14,10 +14,12 @@ namespace App\Http\Requests\User;
|
||||
use App\DataMapper\DefaultSettings;
|
||||
use App\Factory\UserFactory;
|
||||
use App\Http\Requests\Request;
|
||||
use App\Http\ValidationRules\Ninja\CanAddUserRule;
|
||||
use App\Http\ValidationRules\User\AttachableUser;
|
||||
use App\Http\ValidationRules\ValidUserForCompany;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\User;
|
||||
use App\Utils\Ninja;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class StoreUserRequest extends Request
|
||||
@ -45,8 +47,7 @@ class StoreUserRequest extends Request
|
||||
$rules['email'] = ['email', new AttachableUser()];
|
||||
}
|
||||
|
||||
|
||||
if (auth()->user()->company()->account->isFreeHostedClient()) {
|
||||
if (Ninja::isHosted()) {
|
||||
$rules['hosted_users'] = new CanAddUserRule(auth()->user()->company()->account);
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
namespace App\Jobs\Company;
|
||||
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\TaskStatus;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
@ -44,6 +45,9 @@ class CreateCompanyTaskStatuses
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
|
||||
MultiDB::setDb($this->company->db);
|
||||
|
||||
$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.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());
|
||||
|
||||
|
||||
$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->settings = $this->settings;
|
||||
$nmo->to_user = $this->invitation->contact;
|
||||
|
@ -14,7 +14,7 @@ namespace App\Jobs\Ninja;
|
||||
use App\DataMapper\InvoiceItem;
|
||||
use App\Events\Invoice\InvoiceWasEmailed;
|
||||
use App\Jobs\Entity\EmailEntity;
|
||||
use App\Jobs\Util\WebHookHandler;
|
||||
use App\Jobs\Util\WebhookHandler;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\Account;
|
||||
use App\Models\Invoice;
|
||||
@ -84,7 +84,7 @@ class SendReminders implements ShouldQueue
|
||||
|
||||
if (in_array($reminder_template, ['reminder1', 'reminder2', 'reminder3', 'endless_reminder'])) {
|
||||
$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;
|
||||
|
||||
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);
|
||||
|
||||
if (!$invoice->reminder1_sent) {
|
||||
@ -139,20 +139,20 @@ class SendReminders implements ShouldQueue
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (!$invoice->reminder2_sent) {
|
||||
$set_reminder3 = true;
|
||||
$set_reminder2 = true;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (!$invoice->reminder3_sent) {
|
||||
@ -178,15 +178,17 @@ class SendReminders implements ShouldQueue
|
||||
*/
|
||||
private function calculateScheduledDate($invoice, $schedule_reminder, $num_days_reminder) :?Carbon
|
||||
{
|
||||
$offset = $invoice->client->timezone_offset();
|
||||
|
||||
switch ($schedule_reminder) {
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
default:
|
||||
return null;
|
||||
@ -211,7 +213,8 @@ class SendReminders implements ShouldQueue
|
||||
if ($this->checkSendSetting($invoice, $template) && $invoice->company->account->hasFeature(Account::FEATURE_EMAIL_TEMPLATES_REMINDERS)) {
|
||||
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)) {
|
||||
event(new InvoiceWasEmailed($invoice->invitations->first(), $invoice->company, Ninja::eventVars(), $template));
|
||||
}
|
||||
|
||||
|
||||
$invoice->last_sent_date = now();
|
||||
$invoice->next_send_date = $this->calculateNextSendDate($invoice);
|
||||
|
||||
if (in_array($template, ['reminder1', 'reminder2', 'reminder3'])) {
|
||||
$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");
|
||||
/* 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->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*/
|
||||
if ($this->recurring_invoice->remaining_cycles == 0) {
|
||||
@ -96,7 +96,7 @@ class SendRecurring implements ShouldQueue
|
||||
if ($invitation->contact && strlen($invitation->contact->email) >=1) {
|
||||
|
||||
try{
|
||||
EmailEntity::dispatch($invitation, $invoice->company);
|
||||
EmailEntity::dispatch($invitation, $invoice->company)->delay(now()->addSeconds(60));
|
||||
}
|
||||
catch(\Exception $e) {
|
||||
nlog($e->getMessage());
|
||||
|
@ -929,7 +929,7 @@ class Import implements ShouldQueue
|
||||
|
||||
$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['user_id'] = $this->processUserId($resource);
|
||||
|
@ -53,14 +53,14 @@ class ReminderJob implements ShouldQueue
|
||||
|
||||
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()) {
|
||||
$reminder_template = $invoice->calculateTemplate('invoice');
|
||||
$invoice->service()->touchReminder($reminder_template)->save();
|
||||
|
||||
$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}");
|
||||
});
|
||||
|
||||
|
@ -64,7 +64,7 @@ class SendFailedEmails implements ShouldQueue
|
||||
|
||||
if ($invitation->invoice) {
|
||||
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
|
||||
*/
|
||||
|
||||
namespace App\Jobs\Util;
|
||||
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
|
@ -34,11 +34,11 @@ class OAuth
|
||||
* @param Socialite $user
|
||||
* @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 **/
|
||||
$query = [
|
||||
'oauth_user_id' =>$user->getId(),
|
||||
'oauth_user_id' =>$socialite_user->getId(),
|
||||
'oauth_provider_id'=>$provider,
|
||||
];
|
||||
|
||||
|
@ -47,6 +47,9 @@ class CreditEmailEngine extends BaseEmailEngine
|
||||
$t = app('translator');
|
||||
$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) {
|
||||
$body_template = $this->template_data['body'];
|
||||
} else {
|
||||
|
@ -50,6 +50,9 @@ class InvoiceEmailEngine extends BaseEmailEngine
|
||||
$t = app('translator');
|
||||
$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) {
|
||||
$body_template = $this->template_data['body'];
|
||||
} elseif (strlen($this->client->getSetting('email_template_'.$this->reminder_template)) > 0) {
|
||||
|
@ -47,6 +47,9 @@ class QuoteEmailEngine extends BaseEmailEngine
|
||||
App::forgetInstance('translator');
|
||||
$t = app('translator');
|
||||
$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) {
|
||||
$body_template = $this->template_data['body'];
|
||||
|
@ -105,9 +105,6 @@ class Account extends BaseModel
|
||||
return $this->hasOne(Company::class, 'id', 'default_company_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BelongsTo
|
||||
*/
|
||||
public function payment()
|
||||
{
|
||||
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\Models\Presenters\ClientPresenter;
|
||||
use App\Services\Client\ClientService;
|
||||
use App\Utils\Traits\AppSetup;
|
||||
use App\Utils\Traits\GeneratesCounter;
|
||||
use App\Utils\Traits\MakesDates;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
@ -32,6 +33,7 @@ class Client extends BaseModel implements HasLocalePreference
|
||||
use SoftDeletes;
|
||||
use Filterable;
|
||||
use GeneratesCounter;
|
||||
use AppSetup;
|
||||
|
||||
protected $presenter = ClientPresenter::class;
|
||||
|
||||
@ -230,13 +232,16 @@ class Client extends BaseModel implements HasLocalePreference
|
||||
|
||||
public function language()
|
||||
{
|
||||
//return Language::find($this->getSetting('language_id'));
|
||||
|
||||
$languages = Cache::get('languages');
|
||||
|
||||
if(!$languages)
|
||||
$this->buildCache(true);
|
||||
|
||||
return $languages->filter(function ($item) {
|
||||
return $item->id == $this->getSetting('language_id');
|
||||
})->first();
|
||||
|
||||
}
|
||||
|
||||
public function locale()
|
||||
@ -257,6 +262,9 @@ class Client extends BaseModel implements HasLocalePreference
|
||||
{
|
||||
$currencies = Cache::get('currencies');
|
||||
|
||||
if(!$currencies)
|
||||
$this->buildCache(true);
|
||||
|
||||
return $currencies->filter(function ($item) {
|
||||
return $item->id == $this->getSetting('currency_id');
|
||||
})->first();
|
||||
@ -622,6 +630,9 @@ class Client extends BaseModel implements HasLocalePreference
|
||||
{
|
||||
$languages = Cache::get('languages');
|
||||
|
||||
if(!$languages)
|
||||
$this->buildCache(true);
|
||||
|
||||
return $languages->filter(function ($item) {
|
||||
return $item->id == $this->getSetting('language_id');
|
||||
})->first()->locale;
|
||||
@ -684,4 +695,21 @@ class Client extends BaseModel implements HasLocalePreference
|
||||
{
|
||||
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) {
|
||||
return null;
|
||||
// $this->next_send_date = now()->format('Y-m-d');
|
||||
}
|
||||
|
||||
$offset = $this->client->timezone_offset();
|
||||
|
||||
switch ($this->frequency_id) {
|
||||
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:
|
||||
return Carbon::parse($this->next_send_date)->addWeek();
|
||||
return Carbon::parse($this->next_send_date)->startOfDay()->addWeek()->addSeconds($offset);
|
||||
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:
|
||||
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:
|
||||
return Carbon::parse($this->next_send_date)->addMonthNoOverflow();
|
||||
return Carbon::parse($this->next_send_date)->startOfDay()->addMonthNoOverflow()->addSeconds($offset);
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
return Carbon::parse($this->next_send_date)->addYear();
|
||||
return Carbon::parse($this->next_send_date)->startOfDay()->addYear()->addSeconds($offset);
|
||||
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:
|
||||
return Carbon::parse($this->next_send_date)->addYears(3);
|
||||
return Carbon::parse($this->next_send_date)->startOfDay()->addYears(3)->addSeconds($offset);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@ -255,31 +256,33 @@ class RecurringInvoice extends BaseModel
|
||||
|
||||
public function nextDateByFrequency($date)
|
||||
{
|
||||
$offset = $this->client->timezone_offset();
|
||||
|
||||
switch ($this->frequency_id) {
|
||||
case self::FREQUENCY_DAILY:
|
||||
return Carbon::parse($date)->addDay();
|
||||
return Carbon::parse($date)->startOfDay()->addDay()->addSeconds($offset);
|
||||
case self::FREQUENCY_WEEKLY:
|
||||
return Carbon::parse($date)->addWeek();
|
||||
return Carbon::parse($date)->startOfDay()->addWeek()->addSeconds($offset);
|
||||
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:
|
||||
return Carbon::parse($date)->addWeeks(4);
|
||||
return Carbon::parse($date)->startOfDay()->addWeeks(4)->addSeconds($offset);
|
||||
case self::FREQUENCY_MONTHLY:
|
||||
return Carbon::parse($date)->addMonthNoOverflow();
|
||||
return Carbon::parse($date)->startOfDay()->addMonthNoOverflow()->addSeconds($offset);
|
||||
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:
|
||||
return Carbon::parse($date)->addMonthsNoOverflow(3);
|
||||
return Carbon::parse($date)->startOfDay()->addMonthsNoOverflow(3)->addSeconds($offset);
|
||||
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:
|
||||
return Carbon::parse($date)->addMonthsNoOverflow(6);
|
||||
return Carbon::parse($date)->addMonthsNoOverflow(6)->addSeconds($offset);
|
||||
case self::FREQUENCY_ANNUALLY:
|
||||
return Carbon::parse($date)->addYear();
|
||||
return Carbon::parse($date)->startOfDay()->addYear()->addSeconds($offset);
|
||||
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:
|
||||
return Carbon::parse($date)->addYears(3);
|
||||
return Carbon::parse($date)->startOfDay()->addYears(3)->addSeconds($offset);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ class ClientRepository extends BaseRepository
|
||||
if (empty($data['name'])) {
|
||||
$data['name'] = $client->present()->name();
|
||||
}
|
||||
|
||||
|
||||
$client->save();
|
||||
|
||||
$this->contact_repo->save($data, $client);
|
||||
|
@ -376,7 +376,9 @@ class InvoiceService
|
||||
$this->invoice->reminder3_sent = now()->format('Y-m-d');
|
||||
$this->invoice->reminder_last_sent = now()->format('Y-m-d');
|
||||
break;
|
||||
|
||||
case 'endless_reminder':
|
||||
$this->invoice->reminder_last_sent = now()->format('Y-m-d');
|
||||
break;
|
||||
default:
|
||||
// code...
|
||||
break;
|
||||
|
@ -62,7 +62,7 @@ class TriggeredActions extends AbstractService
|
||||
$reminder_template = 'payment';
|
||||
|
||||
$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) {
|
||||
|
@ -41,87 +41,89 @@ class UpdateReminder extends AbstractService
|
||||
return $this->invoice; //exit early
|
||||
}
|
||||
|
||||
$offset = $this->invoice->client->timezone_offset();
|
||||
|
||||
$date_collection = collect();
|
||||
|
||||
if (is_null($this->invoice->reminder1_sent) &&
|
||||
$this->settings->schedule_reminder1 == 'after_invoice_date' &&
|
||||
$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)));
|
||||
$date_collection->push($reminder_date->format('Y-m-d'));
|
||||
$date_collection->push($reminder_date);
|
||||
}
|
||||
|
||||
if (is_null($this->invoice->reminder1_sent) &&
|
||||
$this->settings->schedule_reminder1 == 'before_due_date' &&
|
||||
$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)));
|
||||
$date_collection->push($reminder_date->format('Y-m-d'));
|
||||
$date_collection->push($reminder_date);
|
||||
}
|
||||
|
||||
if (is_null($this->invoice->reminder1_sent) &&
|
||||
$this->settings->schedule_reminder1 == 'after_due_date' &&
|
||||
$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)));
|
||||
$date_collection->push($reminder_date->format('Y-m-d'));
|
||||
$date_collection->push($reminder_date);
|
||||
}
|
||||
|
||||
if (is_null($this->invoice->reminder2_sent) &&
|
||||
$this->settings->schedule_reminder2 == 'after_invoice_date' &&
|
||||
$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)));
|
||||
$date_collection->push($reminder_date->format('Y-m-d'));
|
||||
$date_collection->push($reminder_date);
|
||||
}
|
||||
|
||||
if (is_null($this->invoice->reminder2_sent) &&
|
||||
$this->settings->schedule_reminder2 == 'before_due_date' &&
|
||||
$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)));
|
||||
$date_collection->push($reminder_date->format('Y-m-d'));
|
||||
$date_collection->push($reminder_date);
|
||||
}
|
||||
|
||||
if (is_null($this->invoice->reminder2_sent) &&
|
||||
$this->settings->schedule_reminder2 == 'after_due_date' &&
|
||||
$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)));
|
||||
$date_collection->push($reminder_date->format('Y-m-d'));
|
||||
$date_collection->push($reminder_date);
|
||||
}
|
||||
|
||||
if (is_null($this->invoice->reminder3_sent) &&
|
||||
$this->settings->schedule_reminder3 == 'after_invoice_date' &&
|
||||
$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)));
|
||||
$date_collection->push($reminder_date->format('Y-m-d'));
|
||||
$date_collection->push($reminder_date);
|
||||
}
|
||||
|
||||
if (is_null($this->invoice->reminder3_sent) &&
|
||||
$this->settings->schedule_reminder3 == 'before_due_date' &&
|
||||
$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)));
|
||||
$date_collection->push($reminder_date->format('Y-m-d'));
|
||||
$date_collection->push($reminder_date);
|
||||
}
|
||||
|
||||
if (is_null($this->invoice->reminder3_sent) &&
|
||||
$this->settings->schedule_reminder3 == 'after_due_date' &&
|
||||
$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)));
|
||||
$date_collection->push($reminder_date->format('Y-m-d'));
|
||||
$date_collection->push($reminder_date);
|
||||
}
|
||||
|
||||
$this->invoice->next_send_date = $date_collection->sort()->first();
|
||||
|
@ -51,7 +51,7 @@ class CompanyUserTransformer extends EntityTransformer
|
||||
'archived_at' => (int) $company_user->deleted_at,
|
||||
'created_at' => (int) $company_user->created_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(
|
||||
$client->getSetting('schedule_reminder1'),
|
||||
$client->getSetting('num_days_reminder1')
|
||||
)) {
|
||||
) && !$this->reminder1_sent) {
|
||||
return 'reminder1';
|
||||
} elseif ($this->inReminderWindow(
|
||||
$client->getSetting('schedule_reminder2'),
|
||||
$client->getSetting('num_days_reminder2')
|
||||
)) {
|
||||
) && !$this->reminder2_sent) {
|
||||
return 'reminder2';
|
||||
} elseif ($this->inReminderWindow(
|
||||
$client->getSetting('schedule_reminder3'),
|
||||
$client->getSetting('num_days_reminder3')
|
||||
)) {
|
||||
) && !$this->reminder3_sent) {
|
||||
return 'reminder3';
|
||||
} elseif ($this->checkEndlessReminder(
|
||||
$this->last_sent_date,
|
||||
$this->reminder_last_sent,
|
||||
$client->getSetting('endless_reminder_frequency_id')
|
||||
)) {
|
||||
return 'endless_reminder';
|
||||
@ -76,7 +76,11 @@ trait MakesReminders
|
||||
}
|
||||
|
||||
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))) {
|
||||
return true;
|
||||
}
|
||||
@ -85,12 +89,15 @@ trait MakesReminders
|
||||
}
|
||||
|
||||
private function addTimeInterval($date, $endless_reminder_frequency_id) :?Carbon
|
||||
{
|
||||
{
|
||||
|
||||
if (!$date)
|
||||
return null;
|
||||
|
||||
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();
|
||||
case RecurringInvoice::FREQUENCY_TWO_WEEKS:
|
||||
return Carbon::parse($date)->addWeeks(2)->startOfDay();
|
||||
|
@ -14,8 +14,8 @@ return [
|
||||
'require_https' => env('REQUIRE_HTTPS', true),
|
||||
'app_url' => rtrim(env('APP_URL', ''), '/'),
|
||||
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
|
||||
'app_version' => '5.1.74',
|
||||
'app_tag' => '5.1.74-release',
|
||||
'app_version' => '5.2.0',
|
||||
'app_tag' => '5.2.0-release',
|
||||
'minimum_client_version' => '5.0.16',
|
||||
'terms_version' => '1.0.1',
|
||||
'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 = {
|
||||
"version.json": "9fe5b22a16f39b766c8fdc35a24b3efa",
|
||||
"favicon.ico": "51636d3a390451561744c42188ccd628",
|
||||
"main.dart.js": "9f05b24849e19debf0c8286556e368e6",
|
||||
"main.dart.js": "33f9288e9a8ba68d21b46b8afda06fbb",
|
||||
"/": "23224b5e03519aaa87594403d54412cf",
|
||||
"assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "174c02fc4609e8fc4389f5d21f16a296",
|
||||
"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>
|
||||
|
||||
<pre>
|
||||
@if(\App\Utils\Ninja::isHosted())
|
||||
@if(\App\Utils\Ninja::isSelfHost())
|
||||
{!! $exception->getMessage() !!}
|
||||
{!! $content !!}
|
||||
@else
|
||||
{!! $exception->getMessage() !!}
|
||||
{!! $content !!}
|
||||
<p>Please contact us at contact@invoiceninja.com for more information on this error.</p>
|
||||
@endif
|
||||
</pre>
|
||||
@endcomponent
|
||||
|
@ -77,7 +77,7 @@ class ReminderTest extends TestCase
|
||||
$this->invoice->service()->markSent();
|
||||
$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();
|
||||
}
|
||||
@ -106,7 +106,7 @@ class ReminderTest extends TestCase
|
||||
|
||||
$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->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