From 0611004e7787f5c684984b9f2874fbadc1fdb335 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Tue, 10 Dec 2013 19:18:35 +0200 Subject: [PATCH] Working on recurring invoices --- .gitignore | 1 + app/commands/SendRecurringInvoices.php | 79 +++++++++++-------- app/config/database.php | 8 +- app/controllers/InvoiceController.php | 39 ++++----- ...11_05_180133_confide_setup_users_table.php | 30 +++++-- app/libraries/utils.php | 73 +++++++++++++++++ app/mailers/ContactMailer.php | 31 ++++++++ app/mailers/Mailer.php | 19 +++++ app/mailers/UserMailer.php | 0 app/models/Account.php | 4 +- app/models/Activity.php | 25 ++++-- app/models/EntityModel.php | 26 ++++-- app/models/Invoice.php | 48 ++++++++--- app/models/Theme.php | 2 +- app/routes.php | 3 +- app/start/artisan.php | 3 +- app/views/invoices/edit.blade.php | 2 +- bootstrap/start.php | 3 +- composer.json | 3 +- public/js/script.js | 77 +++++++++++++++++- scheduler.yml | 8 ++ 21 files changed, 381 insertions(+), 103 deletions(-) create mode 100755 app/mailers/ContactMailer.php create mode 100755 app/mailers/Mailer.php create mode 100755 app/mailers/UserMailer.php create mode 100755 scheduler.yml diff --git a/.gitignore b/.gitignore index 517c11cf5b8e..0ff666ab56fc 100755 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /app/config/staging +/app/config/development /public/logo /bootstrap/compiled.php /vendor diff --git a/app/commands/SendRecurringInvoices.php b/app/commands/SendRecurringInvoices.php index 96657aa7e606..9f4d482d117e 100755 --- a/app/commands/SendRecurringInvoices.php +++ b/app/commands/SendRecurringInvoices.php @@ -3,50 +3,68 @@ use Illuminate\Console\Command; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputArgument; +use Ninja\Mailers\ContactMailer as Mailer; class SendRecurringInvoices extends Command { - /** - * The console command name. - * - * @var string - */ protected $name = 'ninja:send-invoices'; - - /** - * The console command description. - * - * @var string - */ protected $description = 'Send recurring invoices'; + protected $mailer; - /** - * Create a new command instance. - * - * @return void - */ - public function __construct() + public function __construct(Mailer $mailer) { parent::__construct(); + + $this->mailer = $mailer; } - /** - * Execute the console command. - * - * @return void - */ public function fire() { - $this->info('Running SendRecurringInvoices...'); + $this->info(date('Y-m-d') . ' Running SendRecurringInvoices...'); + + $today = date('Y-m-d'); + + $invoices = Invoice::with('account', 'invoice_items')->whereRaw('start_date <= ? AND (end_date IS NULL OR end_date >= ?)', array($today, $today))->get(); + $this->info(count($invoices) . ' recurring invoice(s) found'); + + foreach ($invoices as $recurInvoice) + { + $this->info('Processing Invoice ' . $recurInvoice->id . ' - Should send ' . ($recurInvoice->shouldSendToday() ? 'YES' : 'NO')); + + if (!$recurInvoice->shouldSendToday()) + { + continue; + } + + $invoice = Invoice::createNew($recurInvoice); + $invoice->client_id = $recurInvoice->client_id; + $invoice->parent_id = $recurInvoice->id; + $invoice->invoice_number = $recurInvoice->account->getNextInvoiceNumber(); + $invoice->total = $recurInvoice->total; + $invoice->invoice_date = new DateTime(); + $invoice->due_date = new DateTime(); + $invoice->save(); + + foreach ($recurInvoice->invoice_items as $recurItem) + { + $item = InvoiceItem::createNew($recurItem); + $item->product_id = $recurItem->product_id; + $item->qty = $recurItem->qty; + $item->cost = $recurItem->cost; + $item->notes = Utils::processVariables($recurItem->notes); + $item->product_key = Utils::processVariables($recurItem->product_key); + $invoice->invoice_items()->save($item); + } + + $recurInvoice->last_sent_date = new DateTime(); + $recurInvoice->save(); + + $this->mailer->sendInvoice($invoice, $invoice->client->contacts()->first()); + } $this->info('Done'); } - /** - * Get the console command arguments. - * - * @return array - */ protected function getArguments() { return array( @@ -54,11 +72,6 @@ class SendRecurringInvoices extends Command { ); } - /** - * Get the console command options. - * - * @return array - */ protected function getOptions() { return array( diff --git a/app/config/database.php b/app/config/database.php index a1c091cf888b..da0f8104185b 100755 --- a/app/config/database.php +++ b/app/config/database.php @@ -54,10 +54,10 @@ return array( 'mysql' => array( 'driver' => 'mysql', - 'host' => 'localhost', - 'database' => '', - 'username' => '', - 'password' => '', + 'host' => getenv('DB_HOST'), + 'database' => getenv('DB_NAME'), + 'username' => getenv('DB_USER'), + 'password' => getenv('DB_PASS'), 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', 'prefix' => '', diff --git a/app/controllers/InvoiceController.php b/app/controllers/InvoiceController.php index 5b828fdd8b24..7c7fd18cf185 100755 --- a/app/controllers/InvoiceController.php +++ b/app/controllers/InvoiceController.php @@ -1,12 +1,18 @@ mailer = $mailer; + } + public function index() { return View::make('list', array( @@ -41,7 +47,7 @@ class InvoiceController extends \BaseController { $table->addColumn('client', function($model) { return link_to('clients/' . $model->client_public_id, $model->client_name); }); } - return $table->addColumn('total', function($model){ return '$' . money_format('%i', $model->total); }) + return $table->addColumn('total', function($model) { return '$' . money_format('%i', $model->total); }) ->addColumn('balance', function($model) { return '$' . money_format('%i', $model->balance); }) ->addColumn('invoice_date', function($model) { return Utils::fromSqlDate($model->invoice_date); }) ->addColumn('due_date', function($model) { return Utils::fromSqlDate($model->due_date); }) @@ -364,6 +370,7 @@ class InvoiceController extends \BaseController { $invoice = Invoice::createNew(); } + $invoice->client_id = $client->id; $invoice->invoice_number = trim(Input::get('invoice_number')); $invoice->discount = 0; $invoice->invoice_date = Utils::toSqlDate(Input::get('invoice_date')); @@ -442,23 +449,9 @@ class InvoiceController extends \BaseController { */ if ($action == 'email') - { - $data = array('link' => URL::to('view') . '/' . $invoice->invoice_key); - /* - Mail::send(array('html'=>'emails.invoice_html','text'=>'emails.invoice_text'), $data, function($message) use ($contact) - { - $message->from('hillelcoren@gmail.com', 'Hillel Coren'); - $message->to($contact->email); - }); - */ - - $invitation = Invitation::createNew(); - $invitation->invoice_id = $invoice->id; - $invitation->user_id = Auth::user()->id; - $invitation->contact_id = $contact->id; - $invitation->invitation_key = str_random(20); - $invitation->save(); - + { + $this->mailer->sendInvoice($invoice, $contact); + Session::flash('message', 'Successfully emailed invoice'); } else { Session::flash('message', 'Successfully saved invoice'); diff --git a/app/database/migrations/2013_11_05_180133_confide_setup_users_table.php b/app/database/migrations/2013_11_05_180133_confide_setup_users_table.php index 817ceb5d013a..dff39acf18a7 100755 --- a/app/database/migrations/2013_11_05_180133_confide_setup_users_table.php +++ b/app/database/migrations/2013_11_05_180133_confide_setup_users_table.php @@ -21,14 +21,13 @@ class ConfideSetupUsersTable extends Migration { Schema::dropIfExists('products'); Schema::dropIfExists('contacts'); Schema::dropIfExists('invoices'); - Schema::dropIfExists('users'); Schema::dropIfExists('password_reminders'); Schema::dropIfExists('clients'); + Schema::dropIfExists('users'); Schema::dropIfExists('accounts'); Schema::dropIfExists('invoice_statuses'); Schema::dropIfExists('countries'); - Schema::dropIfExists('timezones'); - + Schema::dropIfExists('timezones'); Schema::create('countries', function($table) { @@ -147,8 +146,8 @@ class ConfideSetupUsersTable extends Migration { Schema::create('clients', function($t) { $t->increments('id'); - $t->unsignedInteger('account_id'); - $t->unsignedInteger('country_id')->nullable(); + $t->unsignedInteger('user_id'); + $t->unsignedInteger('account_id'); $t->timestamps(); $t->softDeletes(); @@ -158,12 +157,14 @@ class ConfideSetupUsersTable extends Migration { $t->string('city'); $t->string('state'); $t->string('postal_code'); + $t->unsignedInteger('country_id')->nullable(); $t->string('work_phone'); $t->text('notes'); $t->decimal('balance', 10, 2); $t->timestamp('last_login'); $t->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + $t->foreign('user_id')->references('id')->on('users'); $t->foreign('country_id')->references('id')->on('countries'); $t->unsignedInteger('public_id'); @@ -174,6 +175,7 @@ class ConfideSetupUsersTable extends Migration { { $t->increments('id'); $t->unsignedInteger('account_id'); + $t->unsignedInteger('user_id'); $t->unsignedInteger('client_id'); $t->timestamps(); $t->softDeletes(); @@ -186,6 +188,7 @@ class ConfideSetupUsersTable extends Migration { $t->timestamp('last_login'); $t->foreign('client_id')->references('id')->on('clients')->onDelete('cascade'); + $t->foreign('user_id')->references('id')->on('users'); $t->unsignedInteger('public_id'); $t->unique( array('account_id','public_id') ); @@ -202,6 +205,7 @@ class ConfideSetupUsersTable extends Migration { { $t->increments('id'); $t->unsignedInteger('client_id'); + $t->unsignedInteger('user_id'); $t->unsignedInteger('account_id'); $t->unsignedInteger('invoice_status_id')->default(1); $t->timestamps(); @@ -219,11 +223,15 @@ class ConfideSetupUsersTable extends Migration { $t->integer('how_often'); $t->date('start_date')->nullable(); $t->date('end_date')->nullable(); + $t->date('last_sent_date')->nullable(); + $t->unsignedInteger('parent_id')->nullable(); $t->foreign('client_id')->references('id')->on('clients')->onDelete('cascade'); $t->foreign('account_id')->references('id')->on('accounts'); + $t->foreign('user_id')->references('id')->on('users'); $t->foreign('invoice_status_id')->references('id')->on('invoice_statuses'); - + $t->foreign('parent_id')->references('id')->on('invoices'); + $t->unsignedInteger('public_id'); $t->unique( array('account_id','public_id') ); }); @@ -254,6 +262,7 @@ class ConfideSetupUsersTable extends Migration { { $t->increments('id'); $t->unsignedInteger('account_id'); + $t->unsignedInteger('user_id'); $t->timestamps(); $t->softDeletes(); @@ -263,7 +272,8 @@ class ConfideSetupUsersTable extends Migration { $t->decimal('qty', 10, 2); $t->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); - + $t->foreign('user_id')->references('id')->on('users'); + $t->unsignedInteger('public_id'); $t->unique( array('account_id','public_id') ); }); @@ -273,6 +283,7 @@ class ConfideSetupUsersTable extends Migration { { $t->increments('id'); $t->unsignedInteger('account_id'); + $t->unsignedInteger('user_id'); $t->unsignedInteger('invoice_id'); $t->unsignedInteger('product_id')->nullable(); $t->timestamps(); @@ -285,6 +296,7 @@ class ConfideSetupUsersTable extends Migration { $t->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade'); $t->foreign('product_id')->references('id')->on('products'); + $t->foreign('user_id')->references('id')->on('users'); $t->unsignedInteger('public_id'); $t->unique( array('account_id','public_id') ); @@ -321,6 +333,7 @@ class ConfideSetupUsersTable extends Migration { { $t->increments('id'); $t->unsignedInteger('account_id'); + $t->unsignedInteger('user_id'); $t->unsignedInteger('client_id')->nullable(); $t->unsignedInteger('contact_id')->nullable(); $t->timestamps(); @@ -333,6 +346,7 @@ class ConfideSetupUsersTable extends Migration { $t->foreign('account_id')->references('id')->on('accounts'); $t->foreign('client_id')->references('id')->on('clients')->onDelete('cascade'); $t->foreign('contact_id')->references('id')->on('contacts'); + $t->foreign('user_id')->references('id')->on('users'); $t->unsignedInteger('public_id'); $t->unique( array('account_id','public_id') ); @@ -380,9 +394,9 @@ class ConfideSetupUsersTable extends Migration { Schema::dropIfExists('products'); Schema::dropIfExists('contacts'); Schema::dropIfExists('invoices'); - Schema::dropIfExists('users'); Schema::dropIfExists('password_reminders'); Schema::dropIfExists('clients'); + Schema::dropIfExists('users'); Schema::dropIfExists('accounts'); Schema::dropIfExists('invoice_statuses'); Schema::dropIfExists('countries'); diff --git a/app/libraries/utils.php b/app/libraries/utils.php index e525d704de73..22b50c810ae0 100755 --- a/app/libraries/utils.php +++ b/app/libraries/utils.php @@ -133,5 +133,78 @@ class Utils Session::put(RECENTLY_VIEWED, $viewed); } + public static function processVariables($str) + { + if (!$str) { + return ''; + } + $variables = ['MONTH', 'QUARTER', 'YEAR']; + for ($i=0; $i 1) { + $offset = intval($addArray[1]); + } else if (count($minArray) > 1) { + $offset = intval($minArray[1]) * -1; + } + + $val = Utils::getDatePart($variable, $offset); + $str = str_replace($match, $val, $str); + } + } + + return $str; + } + + private static function getDatePart($part, $offset) + { + $offset = intval($offset); + if ($part == 'MONTH') { + return Utils::getMonth($offset); + } else if ($part == 'QUARTER') { + return Utils::getQuarter($offset); + } else if ($part == 'YEAR') { + return Utils::getYear($offset); + } + } + + private static function getMonth($offset) + { + $months = [ "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" ]; + + $month = intval(date('n')) - 1; + $month += $offset; + $month = $month % 12; + return $months[$month]; + } + + private static function getQuarter($offset) + { + $month = intval(date('n')) - 1; + $quarter = floor(($month + 3) / 3); + $quarter += $offset; + $quarter = $quarter % 4; + if ($quarter == 0) { + $quarter = 4; + } + return 'Q' . $quarter; + } + + private static function getYear($offset) + { + $year = intval(date('Y')); + return $year + $offset; + } } \ No newline at end of file diff --git a/app/mailers/ContactMailer.php b/app/mailers/ContactMailer.php new file mode 100755 index 000000000000..fa70d6883cd7 --- /dev/null +++ b/app/mailers/ContactMailer.php @@ -0,0 +1,31 @@ + URL::to('view') . '/' . $invoice->invoice_key); + $subject = ''; + + if (Auth::check()) { + $invitation = Invitation::createNew(); + } else { + $invitation = Invitation::createNew($invoice); + } + + $invitation->invoice_id = $invoice->id; + $invitation->user_id = Auth::check() ? Auth::user()->id : $invoice->user_id; + $invitation->contact_id = $contact->id; + $invitation->invitation_key = str_random(20); + $invitation->save(); + + return $this->sendTo($contact->email, $subject, $view, $data); + } +} \ No newline at end of file diff --git a/app/mailers/Mailer.php b/app/mailers/Mailer.php new file mode 100755 index 000000000000..0ec95884710e --- /dev/null +++ b/app/mailers/Mailer.php @@ -0,0 +1,19 @@ + 'emails.'.$view.'_html', + 'text' => 'emails.'.$view.'_text' + ]; + + Mail::queue($views, $data, function($message) use($email, $subject) + { + $message->to($email)->subject($subject); + }); + } +} \ No newline at end of file diff --git a/app/mailers/UserMailer.php b/app/mailers/UserMailer.php new file mode 100755 index 000000000000..e69de29bb2d1 diff --git a/app/models/Account.php b/app/models/Account.php index adae333536d6..5278d32555a0 100755 --- a/app/models/Account.php +++ b/app/models/Account.php @@ -78,8 +78,8 @@ class Account extends Eloquent } public function getNextInvoiceNumber() - { - $order = Invoice::withTrashed()->scope()->orderBy('invoice_number', 'DESC')->first(); + { + $order = Invoice::withTrashed()->scope(false, $this->id)->orderBy('invoice_number', 'DESC')->first(); if ($order) { diff --git a/app/models/Activity.php b/app/models/Activity.php index 745583d86b93..71d033c8d2ff 100755 --- a/app/models/Activity.php +++ b/app/models/Activity.php @@ -25,12 +25,19 @@ class Activity extends Eloquent return $query->whereAccountId(Auth::user()->account_id); } - private static function getBlank() + private static function getBlank($entity = false) { - $user = Auth::user(); $activity = new Activity; - $activity->user_id = $user->id; - $activity->account_id = $user->account_id; + + if (Auth::check()) { + $activity->user_id = Auth::user()->id; + $activity->account_id = Auth::user()->account_id; + } else if ($entity) { + $activity->user_id = $entity->user_id; + $activity->account_id = $entity->account_id; + } else { + exit; // TODO_FIX log error + } return $activity; } @@ -56,11 +63,12 @@ class Activity extends Eloquent public static function createInvoice($invoice) { - $activity = Activity::getBlank(); + $userName = Auth::check() ? Auth::user()->getFullName() : 'System'; + $activity = Activity::getBlank($invoice); $activity->invoice_id = $invoice->id; $activity->client_id = $invoice->client_id; $activity->activity_type_id = ACTIVITY_TYPE_CREATE_INVOICE; - $activity->message = Auth::user()->getFullName() . ' created invoice ' . link_to('invoices/'.$invoice->public_id, $invoice->invoice_number); + $activity->message = $userName . ' created invoice ' . link_to('invoices/'.$invoice->public_id, $invoice->invoice_number); $activity->save(); } @@ -76,12 +84,13 @@ class Activity extends Eloquent public static function emailInvoice($invitation) { - $activity = Activity::getBlank(); + $userName = Auth::check() ? Auth::user()->getFullName() : 'System'; + $activity = Activity::getBlank($invitation); $activity->client_id = $invitation->invoice->client_id; $activity->invoice_id = $invitation->invoice_id; $activity->contact_id = $invitation->contact_id; $activity->activity_type_id = ACTIVITY_TYPE_EMAIL_INVOICE; - $activity->message = Auth::user()->getFullName() . ' emailed invoice ' . link_to('invoices/'.$invitation->invoice->public_id, $invitation->invoice->invoice_number) . ' to ' . $invitation->contact->getFullName(); + $activity->message = $userName . ' emailed invoice ' . link_to('invoices/'.$invitation->invoice->public_id, $invitation->invoice->invoice_number) . ' to ' . $invitation->contact->getFullName(); $activity->save(); } diff --git a/app/models/EntityModel.php b/app/models/EntityModel.php index 163ece8b5b9a..9b3a080ad213 100755 --- a/app/models/EntityModel.php +++ b/app/models/EntityModel.php @@ -5,13 +5,22 @@ class EntityModel extends Eloquent protected $softDelete = true; protected $hidden = array('id', 'created_at', 'updated_at', 'deleted_at'); - public static function createNew() - { + public static function createNew($parent = false) + { $className = get_called_class(); $entity = new $className(); - $entity->account_id = Auth::user()->account_id; - $lastEntity = $className::scope()->orderBy('public_id', 'DESC')->first(); + if (Auth::check()) { + $entity->user_id = Auth::user()->id; + $entity->account_id = Auth::user()->account_id; + } else if ($parent) { + $entity->user_id = $parent->user_id; + $entity->account_id = $parent->account_id; + } else { + exit; // TODO_FIX + } + + $lastEntity = $className::scope(false, $entity->account_id)->orderBy('public_id', 'DESC')->first(); if ($lastEntity) { @@ -21,7 +30,7 @@ class EntityModel extends Eloquent { $entity->public_id = 1; } - + return $entity; } @@ -36,9 +45,12 @@ class EntityModel extends Eloquent return ''; } - public function scopeScope($query, $publicId = false) + public function scopeScope($query, $publicId = false, $accountId = false) { - $query->whereAccountId(Auth::user()->account_id); + if (!$accountId) { + $accountId = Auth::user()->account_id; + } + $query->whereAccountId($accountId); if ($publicId) { diff --git a/app/models/Invoice.php b/app/models/Invoice.php index d8bed2abb04a..49407714dfa7 100755 --- a/app/models/Invoice.php +++ b/app/models/Invoice.php @@ -36,22 +36,52 @@ class Invoice extends EntityModel public function isRecurring() { - return $this->how_often || $this->start_date || $this->end_date; + return $this->how_often || $this->start_date || $this->end_date; } - /* - public function getTotal() + public function shouldSendToday() { - $total = 0; + $dayOfWeekToday = date('w'); + $dayOfWeekStart = date('w', strtotime($this->start_date)); - foreach ($this->invoice_items as $invoiceItem) - { - $total += $invoiceItem->qty * $invoiceItem->cost; + $dayOfMonthToday = date('j'); + $dayOfMonthStart = date('j', strtotime($this->start_date)); + + if (!$this->last_sent_date) { + $daysSinceLastSent = 0; + $monthsSinceLastSent = 0; + } else { + $date1 = new DateTime($this->last_sent_date); + $date2 = new DateTime(); + $diff = $date2->diff($date1); + $daysSinceLastSent = $diff->format("%a"); + $monthsSinceLastSent = ($diff->format('%y') * 12) + $diff->format('%m'); + + if ($daysSinceLastSent == 0) { + return false; + } } - return $total; + switch ($this->how_often) + { + case FREQUENCY_WEEKLY: + return $dayOfWeekStart == $dayOfWeekToday; + case FREQUENCY_TWO_WEEKS: + return $dayOfWeekStart == $dayOfWeekToday && (!$daysSinceLastSent || $daysSinceLastSent == 14); + case FREQUENCY_FOUR_WEEKS: + return $dayOfWeekStart == $dayOfWeekToday && (!$daysSinceLastSent || $daysSinceLastSent == 28); + case FREQUENCY_MONTHLY: + return $dayOfMonthStart == $dayOfMonthToday || $daysSinceLastSent > 31; + case FREQUENCY_THREE_MONTHS: + return ($dayOfMonthStart == $dayOfMonthToday && (!$daysSinceLastSent || $monthsSinceLastSent == 3)) || $daysSinceLastSent > (3 * 31); + case FREQUENCY_SIX_MONTHS: + return ($dayOfMonthStart == $dayOfMonthToday && (!$daysSinceLastSent || $monthsSinceLastSent == 6)) || $daysSinceLastSent > (6 * 31); + case FREQUENCY_ANNUALLY: + return ($dayOfMonthStart == $dayOfMonthToday && (!$daysSinceLastSent || $monthsSinceLastSent == 12)) || $daysSinceLastSent > (12 *31); + } + + return false; } - */ } Invoice::created(function($invoice) diff --git a/app/models/Theme.php b/app/models/Theme.php index fe066adf7846..79631bed84c8 100755 --- a/app/models/Theme.php +++ b/app/models/Theme.php @@ -1,6 +1,6 @@ redirectIfTrailingSlash(); $env = $app->detectEnvironment(array( - 'local' => array('precise64'), + 'development' => array('precise64'), 'staging' => array('host107.hostmonster.com') - )); /* diff --git a/composer.json b/composer.json index d2743351c647..98cb3e0c852b 100755 --- a/composer.json +++ b/composer.json @@ -23,7 +23,8 @@ "app/database/migrations", "app/database/seeds", "app/tests/TestCase.php", - "app/libraries" + "app/libraries", + "app/mailers" ] }, "scripts": { diff --git a/public/js/script.js b/public/js/script.js index 35eb0ee55580..db6a1992451e 100755 --- a/public/js/script.js +++ b/public/js/script.js @@ -93,9 +93,13 @@ function generatePDF(invoice) { // show at most one blank line if (shownItem && !cost && !qty && !notes && !productKey) { continue; - } + } shownItem = true; + // process date variables + notes = processVariables(notes); + productKey = processVariables(productKey); + var lineTotal = item.cost * item.qty; if (lineTotal) total += lineTotal; lineTotal = formatNumber(lineTotal); @@ -200,6 +204,77 @@ function formatNumber(num) { }, "") + "." + p[1]; } + +/* Handle converting variables in the invoices (ie, MONTH+1) */ +function processVariables(str) { + if (!str) return ''; + var variables = ['MONTH','QUARTER','YEAR']; + for (var i=0; i 1) { + offset = match.split('+')[1]; + } else if (match.split('-').length > 1) { + offset = parseInt(match.split('-')[1]) * -1; + } + str = str.replace(match, getDatePart(variable, offset)); + } + } + + return str; +} + +function getDatePart(part, offset) { + offset = parseInt(offset); + if (!offset) { + offset = 0; + } + if (part == 'MONTH') { + return getMonth(offset); + } else if (part == 'QUARTER') { + return getQuarter(offset); + } else if (part == 'YEAR') { + return getYear(offset); + } +} + +function getMonth(offset) { + var today = new Date(); + var months = [ "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" ]; + var month = today.getMonth(); + month = parseInt(month) + offset; + month = month % 12; + return months[month]; +} + +function getYear(offset) { + var today = new Date(); + var year = today.getFullYear(); + return parseInt(year) + offset; +} + +function getQuarter(offset) { + var today = new Date(); + var quarter = Math.floor((today.getMonth() + 3) / 3); + quarter += offset; + quarter = quarter % 4; + if (quarter == 0) { + quarter = 4; + } + return 'Q' + quarter; +} + + + + function formatMoney(num) { num = parseFloat(num); if (!num) return '$0.00'; diff --git a/scheduler.yml b/scheduler.yml new file mode 100755 index 000000000000..85c7045aa957 --- /dev/null +++ b/scheduler.yml @@ -0,0 +1,8 @@ +SendRecurringInvoicesCron: + type: cron + script: htdocs/artisan + args: + - "ninja:send-invoices" + interval: + minute: 0 + hour: * \ No newline at end of file