mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Recurring invoices no longer prevent invoice numbers from being sequential
This commit is contained in:
parent
07b3fdb30c
commit
78bf49cd19
@ -7,6 +7,7 @@ use Illuminate\Console\Command;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use App\Ninja\Mailers\ContactMailer as Mailer;
|
||||
use App\Ninja\Repositories\InvoiceRepository;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\InvoiceItem;
|
||||
use App\Models\Invitation;
|
||||
@ -16,12 +17,14 @@ class SendRecurringInvoices extends Command
|
||||
protected $name = 'ninja:send-invoices';
|
||||
protected $description = 'Send recurring invoices';
|
||||
protected $mailer;
|
||||
protected $invoiceRepo;
|
||||
|
||||
public function __construct(Mailer $mailer)
|
||||
public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->mailer = $mailer;
|
||||
$this->invoiceRepo = $invoiceRepo;
|
||||
}
|
||||
|
||||
public function fire()
|
||||
@ -34,74 +37,10 @@ class SendRecurringInvoices extends Command
|
||||
$this->info(count($invoices).' recurring invoice(s) found');
|
||||
|
||||
foreach ($invoices as $recurInvoice) {
|
||||
if ($recurInvoice->client->deleted_at) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$recurInvoice->user->confirmed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$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->recurring_invoice_id = $recurInvoice->id;
|
||||
$invoice->invoice_number = $recurInvoice->account->getNextInvoiceNumber(false, 'R');
|
||||
$invoice->amount = $recurInvoice->amount;
|
||||
$invoice->balance = $recurInvoice->amount;
|
||||
$invoice->invoice_date = date_create()->format('Y-m-d');
|
||||
$invoice->discount = $recurInvoice->discount;
|
||||
$invoice->po_number = $recurInvoice->po_number;
|
||||
$invoice->public_notes = Utils::processVariables($recurInvoice->public_notes);
|
||||
$invoice->terms = Utils::processVariables($recurInvoice->terms);
|
||||
$invoice->invoice_footer = Utils::processVariables($recurInvoice->invoice_footer);
|
||||
$invoice->tax_name = $recurInvoice->tax_name;
|
||||
$invoice->tax_rate = $recurInvoice->tax_rate;
|
||||
$invoice->invoice_design_id = $recurInvoice->invoice_design_id;
|
||||
$invoice->custom_value1 = $recurInvoice->custom_value1;
|
||||
$invoice->custom_value2 = $recurInvoice->custom_value2;
|
||||
$invoice->custom_taxes1 = $recurInvoice->custom_taxes1;
|
||||
$invoice->custom_taxes2 = $recurInvoice->custom_taxes2;
|
||||
$invoice->is_amount_discount = $recurInvoice->is_amount_discount;
|
||||
|
||||
if ($invoice->client->payment_terms != 0) {
|
||||
$days = $invoice->client->payment_terms;
|
||||
if ($days == -1) {
|
||||
$days = 0;
|
||||
}
|
||||
$invoice->due_date = date_create()->modify($days.' day')->format('Y-m-d');
|
||||
}
|
||||
|
||||
$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);
|
||||
$item->tax_name = $recurItem->tax_name;
|
||||
$item->tax_rate = $recurItem->tax_rate;
|
||||
$invoice->invoice_items()->save($item);
|
||||
}
|
||||
|
||||
foreach ($recurInvoice->invitations as $recurInvitation) {
|
||||
$invitation = Invitation::createNew($recurInvitation);
|
||||
$invitation->contact_id = $recurInvitation->contact_id;
|
||||
$invitation->invitation_key = str_random(RANDOM_KEY_LENGTH);
|
||||
$invoice->invitations()->save($invitation);
|
||||
}
|
||||
|
||||
$this->invoiceRepo->createRecurringInvoice($recurInvoice);
|
||||
$this->mailer->sendInvoice($invoice);
|
||||
|
||||
$recurInvoice->last_sent_date = Carbon::now()->toDateTimeString();
|
||||
$recurInvoice->save();
|
||||
}
|
||||
|
||||
$this->info('Done');
|
||||
|
@ -280,7 +280,7 @@ class InvoiceController extends BaseController
|
||||
$method = 'POST';
|
||||
$url = "{$entityType}s";
|
||||
} else {
|
||||
Utils::trackViewed($invoice->invoice_number.' - '.$invoice->client->getDisplayName(), $invoice->getEntityType());
|
||||
Utils::trackViewed($invoice->getDisplayName().' - '.$invoice->client->getDisplayName(), $invoice->getEntityType());
|
||||
$method = 'PUT';
|
||||
$url = "{$entityType}s/{$publicId}";
|
||||
}
|
||||
@ -335,6 +335,7 @@ class InvoiceController extends BaseController
|
||||
'url' => $url,
|
||||
'title' => trans("texts.edit_{$entityType}"),
|
||||
'client' => $invoice->client,
|
||||
'isRecurring' => $invoice->is_recurring,
|
||||
'actions' => $actions);
|
||||
$data = array_merge($data, self::getViewModel());
|
||||
|
||||
@ -358,10 +359,10 @@ class InvoiceController extends BaseController
|
||||
return View::make('invoices.edit', $data);
|
||||
}
|
||||
|
||||
public function create($clientPublicId = 0)
|
||||
public function create($clientPublicId = 0, $isRecurring = false)
|
||||
{
|
||||
$client = null;
|
||||
$invoiceNumber = Auth::user()->account->getNextInvoiceNumber();
|
||||
$invoiceNumber = $isRecurring ? microtime(true) : Auth::user()->account->getNextInvoiceNumber();
|
||||
|
||||
if ($clientPublicId) {
|
||||
$client = Client::scope($clientPublicId)->firstOrFail();
|
||||
@ -375,12 +376,18 @@ class InvoiceController extends BaseController
|
||||
'method' => 'POST',
|
||||
'url' => 'invoices',
|
||||
'title' => trans('texts.new_invoice'),
|
||||
'isRecurring' => $isRecurring,
|
||||
'client' => $client);
|
||||
$data = array_merge($data, self::getViewModel());
|
||||
|
||||
return View::make('invoices.edit', $data);
|
||||
}
|
||||
|
||||
public function createRecurring($clientPublicId = 0)
|
||||
{
|
||||
return self::create($clientPublicId, true);
|
||||
}
|
||||
|
||||
private static function getViewModel()
|
||||
{
|
||||
$recurringHelp = '';
|
||||
@ -510,7 +517,16 @@ class InvoiceController extends BaseController
|
||||
return $this->convertQuote($publicId);
|
||||
} elseif ($action == 'email') {
|
||||
if (Auth::user()->confirmed && !Auth::user()->isDemo()) {
|
||||
if ($invoice->is_recurring) {
|
||||
if ($invoice->shouldSendToday()) {
|
||||
$invoice = $this->invoiceRepo->createRecurringInvoice($invoice);
|
||||
$response = $this->mailer->sendInvoice($invoice);
|
||||
} else {
|
||||
$response = trans('texts.recurring_too_soon');
|
||||
}
|
||||
} else {
|
||||
$response = $this->mailer->sendInvoice($invoice);
|
||||
}
|
||||
if ($response === true) {
|
||||
$message = trans("texts.emailed_{$entityType}");
|
||||
Session::flash('message', $message);
|
||||
|
@ -158,7 +158,8 @@ class QuoteController extends BaseController
|
||||
'paymentTerms' => Cache::get('paymentTerms'),
|
||||
'industries' => Cache::get('industries'),
|
||||
'invoiceDesigns' => InvoiceDesign::getDesigns(),
|
||||
'invoiceLabels' => Auth::user()->account->getInvoiceLabels()
|
||||
'invoiceLabels' => Auth::user()->account->getInvoiceLabels(),
|
||||
'isRecurring' => false,
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
<?php
|
||||
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Routes
|
||||
@ -132,7 +131,6 @@ Route::group(['middleware' => 'auth'], function() {
|
||||
Route::get('tasks/create/{client_id?}', 'TaskController@create');
|
||||
Route::post('tasks/bulk', 'TaskController@bulk');
|
||||
|
||||
Route::get('recurring_invoices', 'InvoiceController@recurringIndex');
|
||||
Route::get('api/recurring_invoices/{client_id?}', array('as'=>'api.recurring_invoices', 'uses'=>'InvoiceController@getRecurringDatatable'));
|
||||
|
||||
Route::get('invoices/invoice_history/{invoice_id}', 'InvoiceController@invoiceHistory');
|
||||
@ -141,6 +139,7 @@ Route::group(['middleware' => 'auth'], function() {
|
||||
Route::resource('invoices', 'InvoiceController');
|
||||
Route::get('api/invoices/{client_id?}', array('as'=>'api.invoices', 'uses'=>'InvoiceController@getDatatable'));
|
||||
Route::get('invoices/create/{client_id?}', 'InvoiceController@create');
|
||||
Route::get('recurring_invoices/create/{client_id?}', 'InvoiceController@createRecurring');
|
||||
Route::get('invoices/{public_id}/clone', 'InvoiceController@cloneInvoice');
|
||||
Route::post('invoices/bulk', 'InvoiceController@bulk');
|
||||
|
||||
|
@ -83,10 +83,6 @@ class Client extends EntityModel
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
if (!$this->contacts || !count($this->contacts)) {
|
||||
$this->load('contacts');
|
||||
}
|
||||
|
||||
$contact = $this->contacts()->first();
|
||||
|
||||
return $contact->getDisplayName();
|
||||
|
@ -44,7 +44,7 @@ class EntityModel extends Eloquent
|
||||
|
||||
public function getActivityKey()
|
||||
{
|
||||
return '[' . $this->getEntityType().':'.$this->public_id.':'.$this->getName() . ']';
|
||||
return '[' . $this->getEntityType().':'.$this->public_id.':'.$this->getDisplayName() . ']';
|
||||
}
|
||||
|
||||
/*
|
||||
@ -83,6 +83,11 @@ class EntityModel extends Eloquent
|
||||
return $this->public_id;
|
||||
}
|
||||
|
||||
public function getDisplayName()
|
||||
{
|
||||
return $this->getName();
|
||||
}
|
||||
|
||||
// Remap ids to public_ids and show name
|
||||
public function toPublicArray()
|
||||
{
|
||||
|
@ -48,6 +48,11 @@ class Invoice extends EntityModel
|
||||
return $this->belongsTo('App\Models\Invoice');
|
||||
}
|
||||
|
||||
public function recurring_invoices()
|
||||
{
|
||||
return $this->hasMany('App\Models\Invoice', 'recurring_invoice_id');
|
||||
}
|
||||
|
||||
public function invitations()
|
||||
{
|
||||
return $this->hasMany('App\Models\Invitation')->orderBy('invitations.contact_id');
|
||||
@ -55,7 +60,7 @@ class Invoice extends EntityModel
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return $this->invoice_number;
|
||||
return $this->is_recurring ? trans('texts.recurring') : $this->invoice_number;
|
||||
}
|
||||
|
||||
public function getFileName()
|
||||
@ -258,7 +263,9 @@ class Invoice extends EntityModel
|
||||
}
|
||||
|
||||
Invoice::creating(function ($invoice) {
|
||||
if (!$invoice->is_recurring) {
|
||||
$invoice->account->incrementCounter($invoice->is_quote);
|
||||
}
|
||||
});
|
||||
|
||||
Invoice::created(function ($invoice) {
|
||||
|
@ -1,11 +1,12 @@
|
||||
<?php namespace App\Ninja\Repositories;
|
||||
|
||||
use Carbon;
|
||||
use Utils;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\InvoiceItem;
|
||||
use App\Models\Invitation;
|
||||
use App\Models\Product;
|
||||
use App\Models\Task;
|
||||
use Utils;
|
||||
|
||||
class InvoiceRepository
|
||||
{
|
||||
@ -552,4 +553,76 @@ class InvoiceRepository
|
||||
->select(['public_id', 'invoice_number'])
|
||||
->get();
|
||||
}
|
||||
|
||||
public function createRecurringInvoice($recurInvoice)
|
||||
{
|
||||
$recurInvoice->load('account.timezone', 'invoice_items', 'client', 'user');
|
||||
|
||||
if ($recurInvoice->client->deleted_at) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$recurInvoice->user->confirmed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$recurInvoice->shouldSendToday()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$invoice = Invoice::createNew($recurInvoice);
|
||||
$invoice->client_id = $recurInvoice->client_id;
|
||||
$invoice->recurring_invoice_id = $recurInvoice->id;
|
||||
$invoice->invoice_number = $recurInvoice->account->getNextInvoiceNumber(false, 'R');
|
||||
$invoice->amount = $recurInvoice->amount;
|
||||
$invoice->balance = $recurInvoice->amount;
|
||||
$invoice->invoice_date = date_create()->format('Y-m-d');
|
||||
$invoice->discount = $recurInvoice->discount;
|
||||
$invoice->po_number = $recurInvoice->po_number;
|
||||
$invoice->public_notes = Utils::processVariables($recurInvoice->public_notes);
|
||||
$invoice->terms = Utils::processVariables($recurInvoice->terms);
|
||||
$invoice->invoice_footer = Utils::processVariables($recurInvoice->invoice_footer);
|
||||
$invoice->tax_name = $recurInvoice->tax_name;
|
||||
$invoice->tax_rate = $recurInvoice->tax_rate;
|
||||
$invoice->invoice_design_id = $recurInvoice->invoice_design_id;
|
||||
$invoice->custom_value1 = $recurInvoice->custom_value1;
|
||||
$invoice->custom_value2 = $recurInvoice->custom_value2;
|
||||
$invoice->custom_taxes1 = $recurInvoice->custom_taxes1;
|
||||
$invoice->custom_taxes2 = $recurInvoice->custom_taxes2;
|
||||
$invoice->is_amount_discount = $recurInvoice->is_amount_discount;
|
||||
|
||||
if ($invoice->client->payment_terms != 0) {
|
||||
$days = $invoice->client->payment_terms;
|
||||
if ($days == -1) {
|
||||
$days = 0;
|
||||
}
|
||||
$invoice->due_date = date_create()->modify($days.' day')->format('Y-m-d');
|
||||
}
|
||||
|
||||
$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);
|
||||
$item->tax_name = $recurItem->tax_name;
|
||||
$item->tax_rate = $recurItem->tax_rate;
|
||||
$invoice->invoice_items()->save($item);
|
||||
}
|
||||
|
||||
foreach ($recurInvoice->invitations as $recurInvitation) {
|
||||
$invitation = Invitation::createNew($recurInvitation);
|
||||
$invitation->contact_id = $recurInvitation->contact_id;
|
||||
$invitation->invitation_key = str_random(RANDOM_KEY_LENGTH);
|
||||
$invoice->invitations()->save($invitation);
|
||||
}
|
||||
|
||||
$recurInvoice->last_sent_date = Carbon::now()->toDateTimeString();
|
||||
$recurInvoice->save();
|
||||
|
||||
return $invoice;
|
||||
}
|
||||
}
|
||||
|
@ -40,10 +40,13 @@ class AppServiceProvider extends ServiceProvider {
|
||||
<ul class="dropdown-menu" id="menu1">
|
||||
<li><a href="'.URL::to($types.'/create').'">'.trans("texts.new_$type").'</a></li>';
|
||||
|
||||
if ($type == ENTITY_INVOICE && Auth::user()->isPro()) {
|
||||
if ($type == ENTITY_INVOICE) {
|
||||
$str .= '<li><a href="'.URL::to('recurring_invoices/create').'">'.trans("texts.new_recurring_invoice").'</a></li>';
|
||||
if (Auth::user()->isPro()) {
|
||||
$str .= '<li class="divider"></li>
|
||||
<li><a href="'.URL::to('quotes').'">'.trans("texts.quotes").'</a></li>
|
||||
<li><a href="'.URL::to('quotes/create').'">'.trans("texts.new_quote").'</a></li>';
|
||||
}
|
||||
} else if ($type == ENTITY_CLIENT) {
|
||||
$str .= '<li class="divider"></li>
|
||||
<li><a href="'.URL::to('credits').'">'.trans("texts.credits").'</a></li>
|
||||
|
@ -19,7 +19,7 @@ class AddPartialAmountToInvoices extends Migration {
|
||||
|
||||
Schema::table('accounts', function($table)
|
||||
{
|
||||
$table->boolean('utf8_invoices')->default(false);
|
||||
$table->boolean('utf8_invoices')->default(true);
|
||||
$table->boolean('auto_wrap')->default(false);
|
||||
$table->string('subdomain')->nullable();
|
||||
});
|
||||
|
@ -31736,7 +31736,7 @@ NINJA.invoiceLines = function(invoice) {
|
||||
return NINJA.prepareDataTable(grid, 'invoiceItems');
|
||||
}
|
||||
|
||||
NINJA.subtotals = function(invoice, removeBalance)
|
||||
NINJA.subtotals = function(invoice, hideBalance)
|
||||
{
|
||||
if (!invoice) {
|
||||
return;
|
||||
@ -31774,7 +31774,7 @@ NINJA.subtotals = function(invoice, removeBalance)
|
||||
data.push([{text:invoiceLabels.paid_to_date}, {text:formatMoney(paid, invoice.client.currency_id)}]);
|
||||
}
|
||||
|
||||
if (!removeBalance) {
|
||||
if (!hideBalance) {
|
||||
var isPartial = NINJA.parseFloat(invoice.partial);
|
||||
data.push([
|
||||
{text: isPartial ? invoiceLabels.amount_due : invoiceLabels.balance_due, style:['balanceDueLabel']},
|
||||
|
@ -262,7 +262,7 @@ NINJA.invoiceLines = function(invoice) {
|
||||
return NINJA.prepareDataTable(grid, 'invoiceItems');
|
||||
}
|
||||
|
||||
NINJA.subtotals = function(invoice, removeBalance)
|
||||
NINJA.subtotals = function(invoice, hideBalance)
|
||||
{
|
||||
if (!invoice) {
|
||||
return;
|
||||
@ -300,7 +300,7 @@ NINJA.subtotals = function(invoice, removeBalance)
|
||||
data.push([{text:invoiceLabels.paid_to_date}, {text:formatMoney(paid, invoice.client.currency_id)}]);
|
||||
}
|
||||
|
||||
if (!removeBalance) {
|
||||
if (!hideBalance) {
|
||||
var isPartial = NINJA.parseFloat(invoice.partial);
|
||||
data.push([
|
||||
{text: isPartial ? invoiceLabels.amount_due : invoiceLabels.balance_due, style:['balanceDueLabel']},
|
||||
|
@ -707,7 +707,6 @@ return array(
|
||||
'or' => 'or',
|
||||
|
||||
'email_error' => 'There was a problem sending the email',
|
||||
'created_by_recurring' => 'Created by recurring invoice :invoice',
|
||||
'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.',
|
||||
'old_browser' => 'Please use a <a href="'.OUTDATE_BROWSER_URL.'" target="_blank">newer browser</a>',
|
||||
'payment_terms_help' => 'Sets the default invoice due date',
|
||||
@ -745,6 +744,12 @@ return array(
|
||||
'manage_companies' => 'Manage Companies',
|
||||
'total_revenue' => 'Total Revenue',
|
||||
|
||||
'current_user' => 'Current User',
|
||||
'new_recurring_invoice' => 'New Recurring Invoice',
|
||||
'recurring_invoice' => 'Recurring Invoice',
|
||||
'recurring_too_soon' => 'It\'s too soon to create the next recurring invoice',
|
||||
'created_by_invoice' => 'Created by :invoice',
|
||||
|
||||
|
||||
|
||||
);
|
||||
|
@ -697,7 +697,6 @@ return array(
|
||||
'or' => 'oder',
|
||||
|
||||
'email_error' => 'Es gab ein Problem beim Senden dieses E-Mails.',
|
||||
'created_by_recurring' => 'Erzeugt durch die wiederkehrende Rechnung :invoice',
|
||||
'confirm_recurring_timing' => 'Beachten Sie: E-Mails werden zu Beginn der Stunde gesendet.',
|
||||
'old_browser' => 'Bitte verwenden Sie einen <a href="'.OUTDATE_BROWSER_URL.'" target="_blank">neueren Browser</a>',
|
||||
'payment_terms_help' => 'Setzt das Standardfälligkeitssdatum',
|
||||
@ -735,5 +734,11 @@ return array(
|
||||
'manage_companies' => 'Manage Companies',
|
||||
'total_revenue' => 'Total Revenue',
|
||||
|
||||
'current_user' => 'Current User',
|
||||
'new_recurring_invoice' => 'New Recurring Invoice',
|
||||
'recurring_invoice' => 'Recurring Invoice',
|
||||
'recurring_too_soon' => 'It\'s too soon to create the next recurring invoice',
|
||||
'created_by_invoice' => 'Created by :invoice',
|
||||
|
||||
|
||||
);
|
@ -705,7 +705,6 @@ return array(
|
||||
'or' => 'or',
|
||||
|
||||
'email_error' => 'There was a problem sending the email',
|
||||
'created_by_recurring' => 'Created by recurring invoice :invoice',
|
||||
'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.',
|
||||
'old_browser' => 'Please use a <a href="'.OUTDATE_BROWSER_URL.'" target="_blank">newer browser</a>',
|
||||
'payment_terms_help' => 'Sets the default invoice due date',
|
||||
@ -744,6 +743,10 @@ return array(
|
||||
'total_revenue' => 'Total Revenue',
|
||||
|
||||
'current_user' => 'Current User',
|
||||
'new_recurring_invoice' => 'New Recurring Invoice',
|
||||
'recurring_invoice' => 'Recurring Invoice',
|
||||
'recurring_too_soon' => 'It\'s too soon to create the next recurring invoice',
|
||||
'created_by_invoice' => 'Created by :invoice',
|
||||
|
||||
|
||||
);
|
||||
|
@ -677,7 +677,6 @@ return array(
|
||||
'or' => 'or',
|
||||
|
||||
'email_error' => 'There was a problem sending the email',
|
||||
'created_by_recurring' => 'Created by recurring invoice :invoice',
|
||||
'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.',
|
||||
'old_browser' => 'Please use a <a href="'.OUTDATE_BROWSER_URL.'" target="_blank">newer browser</a>',
|
||||
'payment_terms_help' => 'Sets the default invoice due date',
|
||||
@ -715,5 +714,11 @@ return array(
|
||||
'manage_companies' => 'Manage Companies',
|
||||
'total_revenue' => 'Total Revenue',
|
||||
|
||||
'current_user' => 'Current User',
|
||||
'new_recurring_invoice' => 'New Recurring Invoice',
|
||||
'recurring_invoice' => 'Recurring Invoice',
|
||||
'recurring_too_soon' => 'It\'s too soon to create the next recurring invoice',
|
||||
'created_by_invoice' => 'Created by :invoice',
|
||||
|
||||
|
||||
);
|
@ -706,7 +706,6 @@ return array(
|
||||
'or' => 'or',
|
||||
|
||||
'email_error' => 'There was a problem sending the email',
|
||||
'created_by_recurring' => 'Created by recurring invoice :invoice',
|
||||
'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.',
|
||||
'old_browser' => 'Please use a <a href="'.OUTDATE_BROWSER_URL.'" target="_blank">newer browser</a>',
|
||||
'payment_terms_help' => 'Sets the default invoice due date',
|
||||
@ -744,6 +743,12 @@ return array(
|
||||
'manage_companies' => 'Manage Companies',
|
||||
'total_revenue' => 'Total Revenue',
|
||||
|
||||
'current_user' => 'Current User',
|
||||
'new_recurring_invoice' => 'New Recurring Invoice',
|
||||
'recurring_invoice' => 'Recurring Invoice',
|
||||
'recurring_too_soon' => 'It\'s too soon to create the next recurring invoice',
|
||||
'created_by_invoice' => 'Created by :invoice',
|
||||
|
||||
|
||||
|
||||
);
|
@ -698,7 +698,6 @@ return array(
|
||||
'or' => 'ou',
|
||||
|
||||
'email_error' => 'There was a problem sending the email',
|
||||
'created_by_recurring' => 'Created by recurring invoice :invoice',
|
||||
'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.',
|
||||
'old_browser' => 'Please use a <a href="'.OUTDATE_BROWSER_URL.'" target="_blank">newer browser</a>',
|
||||
'payment_terms_help' => 'Sets the default invoice due date',
|
||||
@ -736,6 +735,12 @@ return array(
|
||||
'manage_companies' => 'Manage Companies',
|
||||
'total_revenue' => 'Total Revenue',
|
||||
|
||||
'current_user' => 'Current User',
|
||||
'new_recurring_invoice' => 'New Recurring Invoice',
|
||||
'recurring_invoice' => 'Recurring Invoice',
|
||||
'recurring_too_soon' => 'It\'s too soon to create the next recurring invoice',
|
||||
'created_by_invoice' => 'Created by :invoice',
|
||||
|
||||
|
||||
|
||||
);
|
||||
|
@ -699,7 +699,6 @@ return array(
|
||||
'or' => 'or',
|
||||
|
||||
'email_error' => 'There was a problem sending the email',
|
||||
'created_by_recurring' => 'Created by recurring invoice :invoice',
|
||||
'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.',
|
||||
'old_browser' => 'Please use a <a href="'.OUTDATE_BROWSER_URL.'" target="_blank">newer browser</a>',
|
||||
'payment_terms_help' => 'Sets the default invoice due date',
|
||||
@ -737,5 +736,11 @@ return array(
|
||||
'manage_companies' => 'Manage Companies',
|
||||
'total_revenue' => 'Total Revenue',
|
||||
|
||||
'current_user' => 'Current User',
|
||||
'new_recurring_invoice' => 'New Recurring Invoice',
|
||||
'recurring_invoice' => 'Recurring Invoice',
|
||||
'recurring_too_soon' => 'It\'s too soon to create the next recurring invoice',
|
||||
'created_by_invoice' => 'Created by :invoice',
|
||||
|
||||
|
||||
);
|
||||
|
@ -701,7 +701,6 @@ return array(
|
||||
'or' => 'or',
|
||||
|
||||
'email_error' => 'There was a problem sending the email',
|
||||
'created_by_recurring' => 'Created by recurring invoice :invoice',
|
||||
'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.',
|
||||
'old_browser' => 'Please use a <a href="'.OUTDATE_BROWSER_URL.'" target="_blank">newer browser</a>',
|
||||
'payment_terms_help' => 'Sets the default invoice due date',
|
||||
@ -739,6 +738,12 @@ return array(
|
||||
'manage_companies' => 'Manage Companies',
|
||||
'total_revenue' => 'Total Revenue',
|
||||
|
||||
'current_user' => 'Current User',
|
||||
'new_recurring_invoice' => 'New Recurring Invoice',
|
||||
'recurring_invoice' => 'Recurring Invoice',
|
||||
'recurring_too_soon' => 'It\'s too soon to create the next recurring invoice',
|
||||
'created_by_invoice' => 'Created by :invoice',
|
||||
|
||||
|
||||
|
||||
);
|
||||
|
@ -708,7 +708,6 @@ return array(
|
||||
'or' => 'or',
|
||||
|
||||
'email_error' => 'There was a problem sending the email',
|
||||
'created_by_recurring' => 'Created by recurring invoice :invoice',
|
||||
'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.',
|
||||
'old_browser' => 'Please use a <a href="'.OUTDATE_BROWSER_URL.'" target="_blank">newer browser</a>',
|
||||
'payment_terms_help' => 'Sets the default invoice due date',
|
||||
@ -746,6 +745,12 @@ return array(
|
||||
'manage_companies' => 'Manage Companies',
|
||||
'total_revenue' => 'Total Revenue',
|
||||
|
||||
'current_user' => 'Current User',
|
||||
'new_recurring_invoice' => 'New Recurring Invoice',
|
||||
'recurring_invoice' => 'Recurring Invoice',
|
||||
'recurring_too_soon' => 'It\'s too soon to create the next recurring invoice',
|
||||
'created_by_invoice' => 'Created by :invoice',
|
||||
|
||||
|
||||
|
||||
);
|
||||
|
@ -706,7 +706,6 @@ return array(
|
||||
'or' => 'or',
|
||||
|
||||
'email_error' => 'There was a problem sending the email',
|
||||
'created_by_recurring' => 'Created by recurring invoice :invoice',
|
||||
'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.',
|
||||
'old_browser' => 'Please use a <a href="'.OUTDATE_BROWSER_URL.'" target="_blank">newer browser</a>',
|
||||
'payment_terms_help' => 'Sets the default invoice due date',
|
||||
@ -744,6 +743,12 @@ return array(
|
||||
'manage_companies' => 'Manage Companies',
|
||||
'total_revenue' => 'Total Revenue',
|
||||
|
||||
'current_user' => 'Current User',
|
||||
'new_recurring_invoice' => 'New Recurring Invoice',
|
||||
'recurring_invoice' => 'Recurring Invoice',
|
||||
'recurring_too_soon' => 'It\'s too soon to create the next recurring invoice',
|
||||
'created_by_invoice' => 'Created by :invoice',
|
||||
|
||||
|
||||
|
||||
);
|
@ -701,7 +701,6 @@ return array(
|
||||
'or' => 'or',
|
||||
|
||||
'email_error' => 'There was a problem sending the email',
|
||||
'created_by_recurring' => 'Created by recurring invoice :invoice',
|
||||
'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.',
|
||||
'old_browser' => 'Please use a <a href="'.OUTDATE_BROWSER_URL.'" target="_blank">newer browser</a>',
|
||||
'payment_terms_help' => 'Sets the default invoice due date',
|
||||
@ -739,6 +738,12 @@ return array(
|
||||
'manage_companies' => 'Manage Companies',
|
||||
'total_revenue' => 'Total Revenue',
|
||||
|
||||
'current_user' => 'Current User',
|
||||
'new_recurring_invoice' => 'New Recurring Invoice',
|
||||
'recurring_invoice' => 'Recurring Invoice',
|
||||
'recurring_too_soon' => 'It\'s too soon to create the next recurring invoice',
|
||||
'created_by_invoice' => 'Created by :invoice',
|
||||
|
||||
|
||||
|
||||
);
|
||||
|
@ -701,7 +701,6 @@ return array(
|
||||
'or' => 'or',
|
||||
|
||||
'email_error' => 'There was a problem sending the email',
|
||||
'created_by_recurring' => 'Created by recurring invoice :invoice',
|
||||
'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.',
|
||||
'old_browser' => 'Please use a <a href="'.OUTDATE_BROWSER_URL.'" target="_blank">newer browser</a>',
|
||||
'payment_terms_help' => 'Sets the default invoice due date',
|
||||
@ -739,5 +738,11 @@ return array(
|
||||
'manage_companies' => 'Manage Companies',
|
||||
'total_revenue' => 'Total Revenue',
|
||||
|
||||
'current_user' => 'Current User',
|
||||
'new_recurring_invoice' => 'New Recurring Invoice',
|
||||
'recurring_invoice' => 'Recurring Invoice',
|
||||
'recurring_too_soon' => 'It\'s too soon to create the next recurring invoice',
|
||||
'created_by_invoice' => 'Created by :invoice',
|
||||
|
||||
|
||||
);
|
||||
|
@ -704,7 +704,6 @@ return array(
|
||||
'or' => 'or',
|
||||
|
||||
'email_error' => 'There was a problem sending the email',
|
||||
'created_by_recurring' => 'Created by recurring invoice :invoice',
|
||||
'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.',
|
||||
'old_browser' => 'Please use a <a href="'.OUTDATE_BROWSER_URL.'" target="_blank">newer browser</a>',
|
||||
'payment_terms_help' => 'Sets the default invoice due date',
|
||||
@ -742,6 +741,12 @@ return array(
|
||||
'manage_companies' => 'Manage Companies',
|
||||
'total_revenue' => 'Total Revenue',
|
||||
|
||||
'current_user' => 'Current User',
|
||||
'new_recurring_invoice' => 'New Recurring Invoice',
|
||||
'recurring_invoice' => 'Recurring Invoice',
|
||||
'recurring_too_soon' => 'It\'s too soon to create the next recurring invoice',
|
||||
'created_by_invoice' => 'Created by :invoice',
|
||||
|
||||
|
||||
|
||||
);
|
||||
|
@ -17,8 +17,12 @@
|
||||
|
||||
@if ($invoice && $invoice->id)
|
||||
<ol class="breadcrumb">
|
||||
@if ($isRecurring)
|
||||
<li>{!! link_to('invoices', trans('texts.recurring_invoice')) !!}</li>
|
||||
@else
|
||||
<li>{!! link_to(($entityType == ENTITY_QUOTE ? 'quotes' : 'invoices'), trans('texts.' . ($entityType == ENTITY_QUOTE ? 'quotes' : 'invoices'))) !!}</li>
|
||||
<li class='active'>{{ $invoice->invoice_number }}</li>
|
||||
@endif
|
||||
</ol>
|
||||
@endif
|
||||
|
||||
@ -79,45 +83,31 @@
|
||||
<div class="col-md-4" id="col_2">
|
||||
<div data-bind="visible: !is_recurring()">
|
||||
{!! Former::text('invoice_date')->data_bind("datePicker: invoice_date, valueUpdate: 'afterkeydown'")->label(trans("texts.{$entityType}_date"))
|
||||
->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT, DEFAULT_DATE_PICKER_FORMAT))->append('<i class="glyphicon glyphicon-calendar" onclick="toggleDatePicker(\'invoice_date\')"></i>') !!}
|
||||
->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT, DEFAULT_DATE_PICKER_FORMAT))->appendIcon('calendar')->addGroupClass('invoice_date') !!}
|
||||
{!! Former::text('due_date')->data_bind("datePicker: due_date, valueUpdate: 'afterkeydown'")
|
||||
->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT, DEFAULT_DATE_PICKER_FORMAT))->append('<i class="glyphicon glyphicon-calendar" onclick="toggleDatePicker(\'due_date\')"></i>') !!}
|
||||
->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT, DEFAULT_DATE_PICKER_FORMAT))->appendIcon('calendar')->addGroupClass('due_date') !!}
|
||||
|
||||
{!! Former::text('partial')->data_bind("value: partial, valueUpdate: 'afterkeydown'")->onchange('onPartialChange()')
|
||||
->rel('tooltip')->data_toggle('tooltip')->data_placement('bottom')->title(trans('texts.partial_value')) !!}
|
||||
</div>
|
||||
@if ($entityType == ENTITY_INVOICE)
|
||||
<div data-bind="visible: is_recurring" style="display: none">
|
||||
{!! Former::select('frequency_id')->options($frequencies)->data_bind("value: frequency_id") !!}
|
||||
{!! Former::select('frequency_id')->options($frequencies)->data_bind("value: frequency_id")
|
||||
->appendIcon('question-sign')->addGroupClass('frequency_id') !!}
|
||||
{!! Former::text('start_date')->data_bind("datePicker: start_date, valueUpdate: 'afterkeydown'")
|
||||
->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT, DEFAULT_DATE_PICKER_FORMAT))->append('<i class="glyphicon glyphicon-calendar" onclick="toggleDatePicker(\'start_date\')"></i>') !!}
|
||||
->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT, DEFAULT_DATE_PICKER_FORMAT))->appendIcon('calendar')->addGroupClass('start_date') !!}
|
||||
{!! Former::text('end_date')->data_bind("datePicker: end_date, valueUpdate: 'afterkeydown'")
|
||||
->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT, DEFAULT_DATE_PICKER_FORMAT))->append('<i class="glyphicon glyphicon-calendar" onclick="toggleDatePicker(\'end_date\')"></i>') !!}
|
||||
->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT, DEFAULT_DATE_PICKER_FORMAT))->appendIcon('calendar')->addGroupClass('end_date') !!}
|
||||
</div>
|
||||
@if ($invoice && $invoice->recurring_invoice)
|
||||
<div class="pull-right" style="padding-top: 6px">
|
||||
{!! trans('texts.created_by_recurring', ['invoice' => link_to('/invoices/'.$invoice->recurring_invoice->public_id, $invoice->recurring_invoice->invoice_number)]) !!}
|
||||
{!! trans('texts.created_by_invoice', ['invoice' => link_to('/invoices/'.$invoice->recurring_invoice->public_id, trans('texts.recurring_invoice'))]) !!}
|
||||
</div>
|
||||
@else
|
||||
<div data-bind="visible: invoice_status_id() === 0">
|
||||
<div class="form-group">
|
||||
<label for="" class="control-label col-lg-4 col-sm-4">
|
||||
{{ trans('texts.recurring') }}
|
||||
</label>
|
||||
<div class="col-lg-8 col-sm-8">
|
||||
<div class="checkbox">
|
||||
<label for="recurring" class="">
|
||||
<input onclick="onRecurringEnabled()" data-bind="checked: is_recurring" id="recurring" type="checkbox" name="recurring" value="1">{{ trans('texts.enable') }}
|
||||
<a href="#" onclick="showLearnMore()"><i class="glyphicon glyphicon-question-sign"></i> {{ trans('texts.learn_more') }}</a>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@if ($invoice && $invoice->last_sent_date)
|
||||
<div class="pull-right">
|
||||
{{ trans('texts.last_invoice_sent', ['date' => Utils::dateToString($invoice->last_sent_date)]) }}
|
||||
</div>
|
||||
@endif
|
||||
@elseif ($invoice && $invoice->last_sent_date)
|
||||
<div class="pull-right" style="padding-top: 6px">
|
||||
{!! trans('texts.last_invoice_sent', [
|
||||
'date' => link_to('/invoices/'.$invoice->recurring_invoices->last()->public_id, Utils::dateToString($invoice->last_sent_date))
|
||||
]) !!}
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
@ -125,7 +115,9 @@
|
||||
</div>
|
||||
|
||||
<div class="col-md-4" id="col_2">
|
||||
@if (!$isRecurring)
|
||||
{!! Former::text('invoice_number')->label(trans("texts.{$entityType}_number_short"))->data_bind("value: invoice_number, valueUpdate: 'afterkeydown'") !!}
|
||||
@endif
|
||||
{!! Former::text('po_number')->label(trans('texts.po_number_short'))->data_bind("value: po_number, valueUpdate: 'afterkeydown'") !!}
|
||||
{!! Former::text('discount')->data_bind("value: discount, valueUpdate: 'afterkeydown'")
|
||||
->addGroupClass('discount-group')->type('number')->min('0')->step('any')->append(
|
||||
@ -334,10 +326,7 @@
|
||||
@if (!$invoice || (!$invoice->trashed() && !$invoice->client->trashed()))
|
||||
|
||||
{!! Button::success(trans("texts.save_{$entityType}"))->withAttributes(array('id' => 'saveButton', 'onclick' => 'onSaveClick()'))->appendIcon(Icon::create('floppy-disk')) !!}
|
||||
|
||||
@if (!$invoice || ($invoice && !$invoice->is_recurring))
|
||||
{!! Button::info(trans("texts.email_{$entityType}"))->withAttributes(array('id' => 'email_button', 'onclick' => 'onEmailClick()'))->appendIcon(Icon::create('send')) !!}
|
||||
@endif
|
||||
|
||||
@if ($invoice && $invoice->id)
|
||||
{!! DropdownButton::normal(trans('texts.more_actions'))
|
||||
@ -604,6 +593,20 @@
|
||||
}, 1);
|
||||
});
|
||||
|
||||
$('.frequency_id .input-group-addon').click(function() {
|
||||
showLearnMore();
|
||||
});
|
||||
|
||||
var fields = ['invoice_date', 'due_date', 'start_date', 'end_date'];
|
||||
for (var i=0; i<fields.length; i++) {
|
||||
var field = fields[i];
|
||||
(function (_field) {
|
||||
$('.' + _field + ' .input-group-addon').click(function() {
|
||||
toggleDatePicker(_field);
|
||||
});
|
||||
})(field);
|
||||
}
|
||||
|
||||
@if ($client || $invoice || count($clients) == 0)
|
||||
$('#invoice_number').focus();
|
||||
@else
|
||||
@ -688,6 +691,10 @@
|
||||
invoice.is_quote = {{ $entityType == ENTITY_QUOTE ? 'true' : 'false' }};
|
||||
invoice.contact = _.findWhere(invoice.client.contacts, {send_invoice: true});
|
||||
|
||||
if (invoice.is_recurring) {
|
||||
invoice.invoice_number = '0000';
|
||||
}
|
||||
|
||||
@if (!$invoice)
|
||||
if (!invoice.terms) {
|
||||
invoice.terms = wordWrapText('{!! str_replace(["\r\n","\r","\n"], '\n', addslashes($account->invoice_terms)) !!}', 300);
|
||||
@ -1115,10 +1122,10 @@
|
||||
var self = this;
|
||||
this.client = ko.observable(data ? false : new ClientModel());
|
||||
self.account = {!! $account !!};
|
||||
this.id = ko.observable('');
|
||||
self.id = ko.observable('');
|
||||
self.discount = ko.observable('');
|
||||
self.is_amount_discount = ko.observable(0);
|
||||
self.frequency_id = ko.observable('');
|
||||
self.frequency_id = ko.observable(4); // default to monthly
|
||||
self.terms = ko.observable('');
|
||||
self.default_terms = ko.observable({{ !$invoice && $account->invoice_terms ? 'true' : 'false' }} ? wordWrapText('{!! str_replace(["\r\n","\r","\n"], '\n', addslashes($account->invoice_terms)) !!}', 300) : '');
|
||||
self.set_default_terms = ko.observable(false);
|
||||
@ -1134,7 +1141,7 @@
|
||||
self.end_date = ko.observable('');
|
||||
self.tax_name = ko.observable();
|
||||
self.tax_rate = ko.observable();
|
||||
self.is_recurring = ko.observable(false);
|
||||
self.is_recurring = ko.observable({{ $isRecurring ? 'true' : 'false' }});
|
||||
self.invoice_status_id = ko.observable(0);
|
||||
self.invoice_items = ko.observableArray();
|
||||
self.amount = ko.observable(0);
|
||||
|
@ -65,13 +65,13 @@
|
||||
"$notesAndTerms",
|
||||
{
|
||||
"table": {
|
||||
"widths": ["*", "auto"],
|
||||
"widths": ["*", "40%"],
|
||||
"body": "$subtotals"
|
||||
},
|
||||
"layout": {
|
||||
"hLineWidth": "$none",
|
||||
"vLineWidth": "$none",
|
||||
"paddingLeft": "$amount:34",
|
||||
"paddingLeft": "$amount:8",
|
||||
"paddingRight": "$amount:8",
|
||||
"paddingTop": "$amount:4",
|
||||
"paddingBottom": "$amount:4"
|
||||
|
@ -74,7 +74,7 @@
|
||||
"$notesAndTerms",
|
||||
{
|
||||
"table": {
|
||||
"widths": ["*", "auto"],
|
||||
"widths": ["*", "40%"],
|
||||
"body": "$subtotals"
|
||||
},
|
||||
"layout": {
|
||||
@ -114,6 +114,9 @@
|
||||
"color": "$primaryColor:#37a3c6",
|
||||
"bold": true
|
||||
},
|
||||
"invoiceDetails": {
|
||||
"margin": [0, 0, 8, 0]
|
||||
},
|
||||
"accountDetails": {
|
||||
"margin": [0, 2, 0, 2]
|
||||
},
|
||||
@ -134,10 +137,10 @@
|
||||
"bold": true
|
||||
},
|
||||
"balanceDueLabel": {
|
||||
"fontSize": "$fontSizeLargest"
|
||||
"fontSize": "$fontSizeLarger"
|
||||
},
|
||||
"balanceDue": {
|
||||
"fontSize": "$fontSizeLargest",
|
||||
"fontSize": "$fontSizeLarger",
|
||||
"color": "$primaryColor:#37a3c6"
|
||||
},
|
||||
"invoiceNumber": {
|
||||
@ -145,7 +148,7 @@
|
||||
},
|
||||
"tableHeader": {
|
||||
"bold": true,
|
||||
"fontSize": "$fontSizeLargest"
|
||||
"fontSize": "$fontSizeLarger"
|
||||
},
|
||||
"invoiceLineItemsTable": {
|
||||
"margin": [0, 16, 0, 16]
|
||||
|
@ -37,7 +37,7 @@
|
||||
"$notesAndTerms",
|
||||
{
|
||||
"table": {
|
||||
"widths": ["*", "auto"],
|
||||
"widths": ["*", "40%"],
|
||||
"body": "$subtotalsWithoutBalance"
|
||||
},
|
||||
"layout": {
|
||||
|
@ -66,7 +66,7 @@
|
||||
{
|
||||
"style": "subtotals",
|
||||
"table": {
|
||||
"widths": ["*", "auto"],
|
||||
"widths": ["*", "40%"],
|
||||
"body": "$subtotals"
|
||||
},
|
||||
"layout": {
|
||||
|
Loading…
x
Reference in New Issue
Block a user