diff --git a/app/Console/Commands/SendReminders.php b/app/Console/Commands/SendReminders.php index 437c65875550..5af20726593b 100644 --- a/app/Console/Commands/SendReminders.php +++ b/app/Console/Commands/SendReminders.php @@ -141,8 +141,14 @@ class SendReminders extends Command $account->loadLocalizationSettings($invoice->client); // support trans to add fee line item $number = preg_replace('/[^0-9]/', '', $reminder); - $amount = $account->account_email_settings->{"late_fee{$number}_amount"}; - $percent = $account->account_email_settings->{"late_fee{$number}_percent"}; + if ($invoice->isQuote()) { + $amount = $account->account_email_settings->{"late_fee_quote{$number}_amount"}; + $percent = $account->account_email_settings->{"late_fee_quote{$number}_percent"}; + } else { + $amount = $account->account_email_settings->{"late_fee{$number}_amount"}; + $percent = $account->account_email_settings->{"late_fee{$number}_percent"}; + } + $this->invoiceRepo->setLateFee($invoice, $amount, $percent); } } @@ -184,6 +190,18 @@ class SendReminders extends Command $this->info(date('r') . ' Send email: ' . $invoice->id); dispatch(new SendInvoiceEmail($invoice, $invoice->user_id, 'reminder4')); } + + // endless quote reminders + $invoices = $this->invoiceRepo->findNeedingEndlessReminding($account, true); + $this->info(date('r ') . $account->name . ': ' . $invoices->count() . ' endless quotes found'); + + foreach ($invoices as $invoice) { + if ($invoice->last_sent_date == date('Y-m-d')) { + continue; + } + $this->info(date('r') . ' Send email: ' . $invoice->id); + dispatch(new SendInvoiceEmail($invoice, $invoice->user_id, 'quote_reminder4')); + } } } diff --git a/app/Constants.php b/app/Constants.php index 5e30fffc8a24..6e0fd86c9fdf 100644 --- a/app/Constants.php +++ b/app/Constants.php @@ -513,6 +513,10 @@ if (! defined('APP_NAME')) { define('TEMPLATE_REMINDER2', 'reminder2'); define('TEMPLATE_REMINDER3', 'reminder3'); define('TEMPLATE_REMINDER4', 'reminder4'); + define('TEMPLATE_QUOTE_REMINDER1', 'quote_reminder1'); + define('TEMPLATE_QUOTE_REMINDER2', 'quote_reminder2'); + define('TEMPLATE_QUOTE_REMINDER3', 'quote_reminder3'); + define('TEMPLATE_QUOTE_REMINDER4', 'quote_reminder4'); define('CUSTOM_MESSAGE_DASHBOARD', 'dashboard'); define('CUSTOM_MESSAGE_UNPAID_INVOICE', 'unpaid_invoice'); diff --git a/app/Http/Controllers/AccountController.php b/app/Http/Controllers/AccountController.php index 244a7b26e648..9ec3fea97ef9 100644 --- a/app/Http/Controllers/AccountController.php +++ b/app/Http/Controllers/AccountController.php @@ -940,7 +940,7 @@ class AccountController extends BaseController $account->account_email_settings->$bodyField = ($body == $account->getDefaultEmailTemplate($type) ? null : $body); } - foreach ([TEMPLATE_REMINDER1, TEMPLATE_REMINDER2, TEMPLATE_REMINDER3] as $type) { + foreach ([TEMPLATE_REMINDER1, TEMPLATE_REMINDER2, TEMPLATE_REMINDER3, TEMPLATE_QUOTE_REMINDER1, TEMPLATE_QUOTE_REMINDER2, TEMPLATE_QUOTE_REMINDER3] as $type) { $enableField = "enable_{$type}"; $account->account_email_settings->$enableField = Input::get($enableField) ? true : false; $account->account_email_settings->{"num_days_{$type}"} = Input::get("num_days_{$type}"); @@ -948,13 +948,21 @@ class AccountController extends BaseController $account->account_email_settings->{"direction_{$type}"} = Input::get("field_{$type}") == REMINDER_FIELD_INVOICE_DATE ? REMINDER_DIRECTION_AFTER : Input::get("direction_{$type}"); $number = preg_replace('/[^0-9]/', '', $type); - $account->account_email_settings->{"late_fee{$number}_amount"} = Input::get("late_fee{$number}_amount"); - $account->account_email_settings->{"late_fee{$number}_percent"} = Input::get("late_fee{$number}_percent"); + if (strpos($type, 'quote') !== false) { + $account->account_email_settings->{"late_fee_quote{$number}_amount"} = Input::get("late_fee_quote{$number}_amount"); + $account->account_email_settings->{"late_fee_quote{$number}_percent"} = Input::get("late_fee_quote{$number}_percent"); + } else { + $account->account_email_settings->{"late_fee{$number}_amount"} = Input::get("late_fee{$number}_amount"); + $account->account_email_settings->{"late_fee{$number}_percent"} = Input::get("late_fee{$number}_percent"); + } } $account->account_email_settings->enable_reminder4 = Input::get('enable_reminder4') ? true : false; $account->account_email_settings->frequency_id_reminder4 = Input::get('frequency_id_reminder4'); + $account->account_email_settings->enable_quote_reminder4 = Input::get('enable_quote_reminder4') ? true : false; + $account->account_email_settings->frequency_id_quote_reminder4 = Input::get('frequency_id_quote_reminder4'); + $account->save(); $account->account_email_settings->save(); diff --git a/app/Jobs/RunReport.php b/app/Jobs/RunReport.php index 110a7d267203..e48cffeee662 100644 --- a/app/Jobs/RunReport.php +++ b/app/Jobs/RunReport.php @@ -46,6 +46,14 @@ class RunReport extends Job $startDate = Carbon::now()->subMonth()->firstOfMonth()->toDateString(); $endDate = Carbon::now()->subMonth()->lastOfMonth()->toDateString(); break; + case 'this_quarter': + $startDate = Carbon::now()->firstOfQuarter()->toDateString(); + $endDate = Carbon::now()->lastOfQuarter()->toDateString(); + break; + case 'last_quarter': + $startDate = Carbon::now()->subMonth(3)->firstOfQuarter()->toDateString(); + $endDate = Carbon::now()->subMonth(3)->lastOfQuarter()->toDateString(); + break; case 'this_year': $startDate = Carbon::now()->firstOfYear()->toDateString(); $endDate = Carbon::now()->lastOfYear()->toDateString(); diff --git a/app/Models/AccountEmailSettings.php b/app/Models/AccountEmailSettings.php index 0aa3b8097cda..776a7ecf4822 100644 --- a/app/Models/AccountEmailSettings.php +++ b/app/Models/AccountEmailSettings.php @@ -46,6 +46,31 @@ class AccountEmailSettings extends Eloquent 'field_reminder1', 'field_reminder2', 'field_reminder3', + 'email_subject_quote_reminder1', + 'email_subject_quote_reminder2', + 'email_subject_quote_reminder3', + 'email_template_quote_reminder1', + 'email_template_quote_reminder2', + 'email_template_quote_reminder3', + 'late_fee_quote1_amount', + 'late_fee_quote1_percent', + 'late_fee_quote2_amount', + 'late_fee_quote2_percent', + 'late_fee_quote3_amount', + 'late_fee_quote3_percent', + 'enable_quote_reminder1', + 'enable_quote_reminder2', + 'enable_quote_reminder3', + 'enable_quote_reminder4', + 'num_days_quote_reminder1', + 'num_days_quote_reminder2', + 'num_days_quote_reminder3', + 'direction_quote_reminder1', + 'direction_quote_reminder2', + 'direction_quote_reminder3', + 'field_quote_reminder1', + 'field_quote_reminder2', + 'field_quote_reminder3', 'email_design_id', 'enable_email_markup', 'email_footer', @@ -61,6 +86,10 @@ class AccountEmailSettings extends Eloquent TEMPLATE_REMINDER2, TEMPLATE_REMINDER3, TEMPLATE_REMINDER4, + TEMPLATE_QUOTE_REMINDER1, + TEMPLATE_QUOTE_REMINDER2, + TEMPLATE_QUOTE_REMINDER3, + TEMPLATE_QUOTE_REMINDER4, ]; } diff --git a/app/Models/Traits/SendsEmails.php b/app/Models/Traits/SendsEmails.php index e045f07a5efb..3ef51f43fe0a 100644 --- a/app/Models/Traits/SendsEmails.php +++ b/app/Models/Traits/SendsEmails.php @@ -136,12 +136,12 @@ trait SendsEmails */ public function getReminderDate($reminder, $filterEnabled = true) { - if ($filterEnabled && ! $this->account_email_settings->{"enable_reminder{$reminder}"}) { + if ($filterEnabled && ! $this->account_email_settings->{"enable_{$reminder}"}) { return false; } - $numDays = $this->account_email_settings->{"num_days_reminder{$reminder}"}; - $plusMinus = $this->account_email_settings->{"direction_reminder{$reminder}"} == REMINDER_DIRECTION_AFTER ? '-' : '+'; + $numDays = $this->account_email_settings->{"num_days_{$reminder}"}; + $plusMinus = $this->account_email_settings->{"direction_{$reminder}"} == REMINDER_DIRECTION_AFTER ? '-' : '+'; return date('Y-m-d', strtotime("$plusMinus $numDays days")); } @@ -153,16 +153,18 @@ trait SendsEmails */ public function getInvoiceReminder($invoice, $filterEnabled = true) { + $reminder = $invoice->isQuote() ? 'quote_reminder' : 'reminder'; + for ($i = 1; $i <= 3; $i++) { - if ($date = $this->getReminderDate($i, $filterEnabled)) { - if ($this->account_email_settings->{"field_reminder{$i}"} == REMINDER_FIELD_DUE_DATE) { + if ($date = $this->getReminderDate($reminder.$i, $filterEnabled)) { + if ($this->account_email_settings->{'field_'.$reminder.$i} == REMINDER_FIELD_DUE_DATE) { if (($invoice->partial && $invoice->partial_due_date == $date) || $invoice->due_date == $date) { - return "reminder{$i}"; + return $reminder.$i; } } else { if ($invoice->invoice_date == $date) { - return "reminder{$i}"; + return $reminder.$i; } } } diff --git a/app/Ninja/Presenters/AccountPresenter.php b/app/Ninja/Presenters/AccountPresenter.php index 2f75a3f0569f..d675b8d41663 100644 --- a/app/Ninja/Presenters/AccountPresenter.php +++ b/app/Ninja/Presenters/AccountPresenter.php @@ -169,6 +169,8 @@ class AccountPresenter extends Presenter "' . trans('texts.last_30_days') . '": [moment().subtract(29, "days"), moment()], "' . trans('texts.this_month') . '": [moment().startOf("month"), moment().endOf("month")], "' . trans('texts.last_month') . '": [moment().subtract(1, "month").startOf("month"), moment().subtract(1, "month").endOf("month")], + "' . trans('texts.current_quarter') . '": [moment().quarter(chartQuarter).startOf("quarter"), moment().quarter(chartQuarter).endOf("quarter")], + "' . trans('texts.last_quarter') . '": [moment().subtract(1, "quarter").startOf("quarter"), moment().subtract(1, "quarter").endOf("quarter")], "' . trans('texts.this_year') . '": [moment().date(1).month(' . $month . ').year(' . $year . '), moment()], "' . trans('texts.last_year') . '": [moment().date(1).month(' . $month . ').year(' . $lastYear . '), moment().date(1).month(' . $month . ').year(' . $year . ').subtract(1, "day")], }'; diff --git a/app/Ninja/Repositories/AccountRepository.php b/app/Ninja/Repositories/AccountRepository.php index 8754a4c201a7..3ece09757974 100644 --- a/app/Ninja/Repositories/AccountRepository.php +++ b/app/Ninja/Repositories/AccountRepository.php @@ -767,7 +767,7 @@ class AccountRepository public function findWithReminders() { return Account::whereHas('account_email_settings', function($query) { - $query->whereRaw('enable_reminder1 = 1 OR enable_reminder2 = 1 OR enable_reminder3 = 1 OR enable_reminder4 = 1'); + $query->whereRaw('enable_reminder1 = 1 OR enable_reminder2 = 1 OR enable_reminder3 = 1 OR enable_reminder4 = 1 OR enable_quote_reminder1 = 1 OR enable_quote_reminder2 = 1 OR enable_quote_reminder3 = 1 OR enable_quote_reminder4 = 1'); })->get(); } @@ -779,7 +779,13 @@ class AccountRepository ->orWhere('late_fee2_amount', '>', 0) ->orWhere('late_fee2_percent', '>', 0) ->orWhere('late_fee3_amount', '>', 0) - ->orWhere('late_fee3_percent', '>', 0); + ->orWhere('late_fee3_percent', '>', 0) + ->orWhere('late_fee_quote1_amount', '>', 0) + ->orWhere('late_fee_quote1_percent', '>', 0) + ->orWhere('late_fee_quote2_amount', '>', 0) + ->orWhere('late_fee_quote2_percent', '>', 0) + ->orWhere('late_fee_quote3_amount', '>', 0) + ->orWhere('late_fee_quote3_percent', '>', 0); })->get(); } diff --git a/app/Ninja/Repositories/InvoiceRepository.php b/app/Ninja/Repositories/InvoiceRepository.php index eb31b2ac43fe..6724a453bc99 100644 --- a/app/Ninja/Repositories/InvoiceRepository.php +++ b/app/Ninja/Repositories/InvoiceRepository.php @@ -1198,13 +1198,20 @@ class InvoiceRepository extends BaseRepository $dates = []; for ($i = 1; $i <= 3; $i++) { - if ($date = $account->getReminderDate($i, $filterEnabled)) { + if ($date = $account->getReminderDate('reminder'.$i, $filterEnabled)) { if ($account->account_email_settings->{"field_reminder{$i}"} == REMINDER_FIELD_DUE_DATE) { $dates[] = "(due_date = '$date' OR partial_due_date = '$date')"; } else { $dates[] = "invoice_date = '$date'"; } } + if ($date = $account->getReminderDate('quote_reminder'.$i, $filterEnabled)) { + if ($account->account_email_settings->{"field_quote_reminder{$i}"} == REMINDER_FIELD_DUE_DATE) { + $dates[] = "(due_date = '$date' OR partial_due_date = '$date')"; + } else { + $dates[] = "invoice_date = '$date'"; + } + } } if (! count($dates)) { @@ -1212,8 +1219,7 @@ class InvoiceRepository extends BaseRepository } $sql = implode(' OR ', $dates); - $invoices = Invoice::invoiceType(INVOICE_TYPE_STANDARD) - ->with('client', 'invoice_items') + $invoices = Invoice::with('client', 'invoice_items') ->whereHas('client', function ($query) { $query->whereSendReminders(true); }) @@ -1227,12 +1233,19 @@ class InvoiceRepository extends BaseRepository return $invoices; } - public function findNeedingEndlessReminding(Account $account) + public function findNeedingEndlessReminding(Account $account, $quote = false) { - $settings = $account->account_email_settings; - $frequencyId = $settings->frequency_id_reminder4; + $invoiceType = INVOICE_TYPE_STANDARD; + $reminder = 'reminder'; + if ($quote) { + $reminder = 'quote_reminder'; + $invoiceType = INVOICE_TYPE_QUOTE; + } - if (! $frequencyId || ! $account->account_email_settings->enable_reminder4) { + $settings = $account->account_email_settings; + $frequencyId = $settings->{"frequency_id_{$reminder}4"}; + + if (! $frequencyId || ! $account->account_email_settings->{"enable_{$reminder}4"}) { return collect(); } @@ -1240,7 +1253,7 @@ class InvoiceRepository extends BaseRepository $lastSentDate = date_create(); $lastSentDate->sub(date_interval_create_from_date_string($frequency->date_interval)); - $invoices = Invoice::invoiceType(INVOICE_TYPE_STANDARD) + $invoices = Invoice::invoiceType($invoiceType) ->with('client', 'invoice_items') ->whereHas('client', function ($query) { $query->whereSendReminders(true); @@ -1252,13 +1265,13 @@ class InvoiceRepository extends BaseRepository ->where('last_sent_date', '<', $lastSentDate); for ($i=1; $i<=3; $i++) { - if (!$account->account_email_settings->{"enable_reminder{$i}"}) { + if (!$account->account_email_settings->{"enable_{$reminder}{$i}"}) { continue; } - $field = $account->account_email_settings->{"field_reminder{$i}"} == REMINDER_FIELD_DUE_DATE ? 'due_date' : 'invoice_date'; + $field = $account->account_email_settings->{"field_{$reminder}{$i}"} == REMINDER_FIELD_DUE_DATE ? 'due_date' : 'invoice_date'; $date = date_create(); - if ($account->account_email_settings->{"direction_reminder{$i}"} == REMINDER_DIRECTION_AFTER) { - $date->sub(date_interval_create_from_date_string($account->account_email_settings->{"num_days_reminder{$i}"} . ' days')); + if ($account->account_email_settings->{"direction_{$reminder}{$i}"} == REMINDER_DIRECTION_AFTER) { + $date->sub(date_interval_create_from_date_string($account->account_email_settings->{"num_days_{$reminder}{$i}"} . ' days')); } $invoices->where($field, '<', $date); } diff --git a/database/migrations/2019_04_28_221429_add_quote_reminders.php b/database/migrations/2019_04_28_221429_add_quote_reminders.php new file mode 100644 index 000000000000..91d4445fce4d --- /dev/null +++ b/database/migrations/2019_04_28_221429_add_quote_reminders.php @@ -0,0 +1,100 @@ +string('email_subject_quote_reminder1'); + $table->string('email_subject_quote_reminder2'); + $table->string('email_subject_quote_reminder3'); + $table->string('email_subject_quote_reminder4'); + + $table->text('email_template_quote_reminder1'); + $table->text('email_template_quote_reminder2'); + $table->text('email_template_quote_reminder3'); + $table->text('email_template_quote_reminder4'); + + $table->boolean('enable_quote_reminder1')->default(false); + $table->boolean('enable_quote_reminder2')->default(false); + $table->boolean('enable_quote_reminder3')->default(false); + $table->boolean('enable_quote_reminder4')->default(false); + + $table->smallInteger('num_days_quote_reminder1')->default(7); + $table->smallInteger('num_days_quote_reminder2')->default(14); + $table->smallInteger('num_days_quote_reminder3')->default(30); + + $table->smallInteger('direction_quote_reminder1')->default(1); + $table->smallInteger('direction_quote_reminder2')->default(1); + $table->smallInteger('direction_quote_reminder3')->default(1); + + $table->smallInteger('field_quote_reminder1')->default(1); + $table->smallInteger('field_quote_reminder2')->default(1); + $table->smallInteger('field_quote_reminder3')->default(1); + + $table->unsignedInteger('frequency_id_quote_reminder4')->nullable(); + + $table->decimal('late_fee_quote1_amount', 13, 2)->nullable(); + $table->decimal('late_fee_quote1_percent', 13, 3)->nullable(); + $table->decimal('late_fee_quote2_amount', 13, 2)->nullable(); + $table->decimal('late_fee_quote2_percent', 13, 3)->nullable(); + $table->decimal('late_fee_quote3_amount', 13, 2)->nullable(); + $table->decimal('late_fee_quote3_percent', 13, 3)->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('account_email_settings', function ($table) { + $table->dropColumn('email_subject_quote_reminder1'); + $table->dropColumn('email_subject_quote_reminder2'); + $table->dropColumn('email_subject_quote_reminder3'); + $table->dropColumn('email_subject_quote_reminder4'); + + $table->dropColumn('email_template_quote_reminder1'); + $table->dropColumn('email_template_quote_reminder2'); + $table->dropColumn('email_template_quote_reminder3'); + $table->dropColumn('email_template_quote_reminder4'); + + $table->dropColumn('enable_quote_reminder1'); + $table->dropColumn('enable_quote_reminder2'); + $table->dropColumn('enable_quote_reminder3'); + $table->dropColumn('enable_quote_reminder4'); + + $table->dropColumn('num_days_quote_reminder1'); + $table->dropColumn('num_days_quote_reminder2'); + $table->dropColumn('num_days_quote_reminder3'); + + $table->dropColumn('direction_quote_reminder1'); + $table->dropColumn('direction_quote_reminder2'); + $table->dropColumn('direction_quote_reminder3'); + + $table->dropColumn('field_quote_reminder1'); + $table->dropColumn('field_quote_reminder2'); + $table->dropColumn('field_quote_reminder3'); + + $table->dropColumn('frequency_id_quote_reminder4'); + + $table->dropColumn('late_fee_quote1_amount'); + $table->dropColumn('late_fee_quote1_percent'); + $table->dropColumn('late_fee_quote2_amount'); + $table->dropColumn('late_fee_quote2_percent'); + $table->dropColumn('late_fee_quote3_amount'); + $table->dropColumn('late_fee_quote3_percent'); + }); + } +} diff --git a/resources/lang/cs/texts.php b/resources/lang/cs/texts.php index e04aaf51eeab..b6c0da6b0005 100644 --- a/resources/lang/cs/texts.php +++ b/resources/lang/cs/texts.php @@ -689,6 +689,7 @@ $LANG = array( 'military_time' => '24 hodinový čas', 'last_sent' => 'Poslední odeslány', 'reminder_emails' => 'Připomínky emailem', + 'quote_reminder_emails' => 'Připomínky emailem (nabídky)', 'templates_and_reminders' => 'Šablony & Připomínky', 'subject' => 'Předmět', 'body' => 'Tělo', @@ -2067,6 +2068,8 @@ $LANG = array( 'last_30_days' => 'Poslední měsíc', 'this_month' => 'Tento měsíc', 'last_month' => 'Last Month', + 'current_quarter' => 'Aktuální čtvrtletí', + 'last_quarter' => 'Poslední čtvrtletí', 'last_year' => 'Last Year', 'custom_range' => 'Custom Range', 'url' => 'URL', diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 2ffc21cfc3eb..4842af52adc8 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -135,6 +135,7 @@ $LANG = array( 'status' => 'Status', 'invoice_total' => 'Invoice Total', 'frequency' => 'Frequency', + 'range' => 'Range', 'start_date' => 'Start Date', 'end_date' => 'End Date', 'transaction_reference' => 'Transaction Reference', @@ -688,6 +689,7 @@ $LANG = array( 'military_time' => '24 Hour Time', 'last_sent' => 'Last Sent', 'reminder_emails' => 'Reminder Emails', + 'quote_reminder_emails' => 'Quote Reminder Emails', 'templates_and_reminders' => 'Templates & Reminders', 'subject' => 'Subject', 'body' => 'Body', @@ -2065,6 +2067,8 @@ $LANG = array( 'last_30_days' => 'Last 30 Days', 'this_month' => 'This Month', 'last_month' => 'Last Month', + 'current_quarter' => 'Current Quarter', + 'last_quarter' => 'Last Quarter', 'last_year' => 'Last Year', 'custom_range' => 'Custom Range', 'url' => 'URL', diff --git a/resources/views/accounts/quote_template.blade.php b/resources/views/accounts/quote_template.blade.php new file mode 100644 index 000000000000..82866d86ef59 --- /dev/null +++ b/resources/views/accounts/quote_template.blade.php @@ -0,0 +1,150 @@ +
+ +
+ +
+