mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Working on recurring invoices
This commit is contained in:
parent
78d2d749fb
commit
0611004e77
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,4 +1,5 @@
|
||||
/app/config/staging
|
||||
/app/config/development
|
||||
/public/logo
|
||||
/bootstrap/compiled.php
|
||||
/vendor
|
||||
|
@ -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(
|
||||
|
@ -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' => '',
|
||||
|
@ -1,12 +1,18 @@
|
||||
<?php
|
||||
|
||||
use Ninja\Mailers\ContactMailer as Mailer;
|
||||
|
||||
class InvoiceController extends \BaseController {
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
protected $mailer;
|
||||
|
||||
public function __construct(Mailer $mailer)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->mailer = $mailer;
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
return View::make('list', array(
|
||||
@ -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'));
|
||||
@ -443,21 +450,7 @@ 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 {
|
||||
|
@ -21,15 +21,14 @@ 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::create('countries', function($table)
|
||||
{
|
||||
$table->increments('id');
|
||||
@ -147,8 +146,8 @@ class ConfideSetupUsersTable extends Migration {
|
||||
Schema::create('clients', function($t)
|
||||
{
|
||||
$t->increments('id');
|
||||
$t->unsignedInteger('user_id');
|
||||
$t->unsignedInteger('account_id');
|
||||
$t->unsignedInteger('country_id')->nullable();
|
||||
$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,10 +223,14 @@ 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,6 +272,7 @@ 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');
|
||||
|
@ -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<count($variables); $i++)
|
||||
{
|
||||
$variable = $variables[$i];
|
||||
$regExp = '/\[' . $variable . '[+-]?[\d]*\]/';
|
||||
preg_match_all($regExp, $str, $matches);
|
||||
$matches = $matches[0];
|
||||
if (count($matches) == 0) {
|
||||
continue;
|
||||
}
|
||||
foreach ($matches as $match) {
|
||||
$offset = 0;
|
||||
$addArray = explode('+', $match);
|
||||
$minArray = explode('-', $match);
|
||||
if (count($addArray) > 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;
|
||||
}
|
||||
}
|
31
app/mailers/ContactMailer.php
Executable file
31
app/mailers/ContactMailer.php
Executable file
@ -0,0 +1,31 @@
|
||||
<?php namespace Ninja\Mailers;
|
||||
|
||||
use Invoice;
|
||||
use Contact;
|
||||
use Invitation;
|
||||
use URL;
|
||||
use Auth;
|
||||
|
||||
class ContactMailer extends Mailer {
|
||||
|
||||
public function sendInvoice(Invoice $invoice, Contact $contact)
|
||||
{
|
||||
$view = 'invoice';
|
||||
$data = array('link' => 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);
|
||||
}
|
||||
}
|
19
app/mailers/Mailer.php
Executable file
19
app/mailers/Mailer.php
Executable file
@ -0,0 +1,19 @@
|
||||
<?php namespace Ninja\Mailers;
|
||||
|
||||
use Mail;
|
||||
|
||||
abstract class Mailer {
|
||||
|
||||
public function sendTo($email, $subject, $view, $data = [])
|
||||
{
|
||||
$views = [
|
||||
'html' => 'emails.'.$view.'_html',
|
||||
'text' => 'emails.'.$view.'_text'
|
||||
];
|
||||
|
||||
Mail::queue($views, $data, function($message) use($email, $subject)
|
||||
{
|
||||
$message->to($email)->subject($subject);
|
||||
});
|
||||
}
|
||||
}
|
0
app/mailers/UserMailer.php
Executable file
0
app/mailers/UserMailer.php
Executable file
@ -79,7 +79,7 @@ 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)
|
||||
{
|
||||
|
@ -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() : '<i>System</i>';
|
||||
$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() : '<i>System</i>';
|
||||
$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();
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
@ -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)
|
||||
{
|
||||
|
@ -39,19 +39,49 @@ class Invoice extends EntityModel
|
||||
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)
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
class Theme extends EntityModel
|
||||
class Theme extends Eloquent
|
||||
{
|
||||
public $timestamps = false;
|
||||
protected $softDelete = false;
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
//dd(DB::getQueryLog());
|
||||
//dd(Client::getPrivateId(1));
|
||||
//dd(new DateTime());
|
||||
|
||||
Route::get('/', 'HomeController@showWelcome');
|
||||
Route::post('get_started', 'AccountController@getStarted');
|
||||
|
@ -11,5 +11,4 @@
|
||||
|
|
||||
*/
|
||||
|
||||
//Artisan::add(new SendRecurringInvoices);
|
||||
Artisan::resolve('SendRecurringInvoices');
|
@ -256,7 +256,7 @@
|
||||
refreshPDF();
|
||||
});
|
||||
|
||||
$('#due_date,#start_date').datepicker({
|
||||
$('#due_date, #start_date, #end_date').datepicker({
|
||||
autoclose: true,
|
||||
todayHighlight: true
|
||||
});
|
||||
|
@ -28,9 +28,8 @@ $app->redirectIfTrailingSlash();
|
||||
|
||||
$env = $app->detectEnvironment(array(
|
||||
|
||||
'local' => array('precise64'),
|
||||
'development' => array('precise64'),
|
||||
'staging' => array('host107.hostmonster.com')
|
||||
|
||||
));
|
||||
|
||||
/*
|
||||
|
@ -23,7 +23,8 @@
|
||||
"app/database/migrations",
|
||||
"app/database/seeds",
|
||||
"app/tests/TestCase.php",
|
||||
"app/libraries"
|
||||
"app/libraries",
|
||||
"app/mailers"
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
|
@ -96,6 +96,10 @@ function generatePDF(invoice) {
|
||||
}
|
||||
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<variables.length; i++) {
|
||||
var variable = variables[i];
|
||||
var regexp = new RegExp('\\[' + variable + '[+-]?[\\d]*\\]', 'g');
|
||||
var matches = str.match(regexp);
|
||||
if (!matches) {
|
||||
continue;
|
||||
}
|
||||
for (var j=0; j<matches.length; j++) {
|
||||
var match = matches[j];
|
||||
var offset = 0;
|
||||
if (match.split('+').length > 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';
|
||||
|
8
scheduler.yml
Executable file
8
scheduler.yml
Executable file
@ -0,0 +1,8 @@
|
||||
SendRecurringInvoicesCron:
|
||||
type: cron
|
||||
script: htdocs/artisan
|
||||
args:
|
||||
- "ninja:send-invoices"
|
||||
interval:
|
||||
minute: 0
|
||||
hour: *
|
Loading…
x
Reference in New Issue
Block a user