1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-08 12:12:48 +01:00

Enabled customizing invoice designs

This commit is contained in:
Hillel Coren 2015-07-21 21:51:56 +03:00
parent 48b73e7e22
commit 35d794b36f
41 changed files with 1922 additions and 565 deletions

28
.gitignore vendored
View File

@ -13,18 +13,26 @@
/bootstrap/environment.php
/vendor
/node_modules
.env
/.DS_Store
/Thumbs.db
.env.development.php
.env.php
.idea
.project
error_log
public/error_log
/.env
/.env.development.php
/.env.php
/error_log
/auth.json
/public/error_log
/ninja.sublime-project
/ninja.sublime-workspace
auth.json
/.phpstorm.meta.php
/_ide_helper.php
/.idea
/.project
.phpstorm.meta.php
_ide_helper.php
/public/js/templates/business.js
/public/js/templates/creative.js
/public/js/templates/elegant.js
/public/js/templates/hipster.js
/public/js/templates/photo.js
/public/js/templates/playful.js

View File

@ -195,9 +195,11 @@ class AccountController extends BaseController
'title' => trans('texts.invoice_settings'),
];
if ($subSection == ACCOUNT_INVOICE_DESIGN) {
if ($subSection == ACCOUNT_INVOICE_DESIGN
|| $subSection == ACCOUNT_CUSTOMIZE_DESIGN) {
$invoice = new stdClass();
$client = new stdClass();
$contact = new stdClass();
$invoiceItem = new stdClass();
$client->name = 'Sample Client';
@ -208,11 +210,17 @@ class AccountController extends BaseController
$client->work_phone = '';
$client->work_email = '';
$invoice->invoice_number = Auth::user()->account->getNextInvoiceNumber();
$invoice->invoice_number = $account->getNextInvoiceNumber();
$invoice->invoice_date = date_create()->format('Y-m-d');
$invoice->account = json_decode(Auth::user()->account->toJson());
$invoice->account = json_decode($account->toJson());
$invoice->amount = $invoice->balance = 100;
$invoice->terms = $account->invoice_terms;
$invoice->invoice_footer = $account->invoice_footer;
$contact->email = 'contact@gmail.com';
$client->contacts = [$contact];
$invoiceItem->cost = 100;
$invoiceItem->qty = 1;
$invoiceItem->notes = 'Notes';
@ -221,10 +229,23 @@ class AccountController extends BaseController
$invoice->client = $client;
$invoice->invoice_items = [$invoiceItem];
$data['account'] = $account;
$data['invoice'] = $invoice;
$data['invoiceDesigns'] = InvoiceDesign::availableDesigns();
$data['invoiceLabels'] = json_decode($account->invoice_labels) ?: [];
$data['title'] = trans('texts.invoice_design');
$data['invoiceDesigns'] = InvoiceDesign::availableDesigns($subSection == ACCOUNT_CUSTOMIZE_DESIGN);
$design = false;
foreach ($data['invoiceDesigns'] as $item) {
if ($item->id == $account->invoice_design_id) {
$design = $item->javascript;
break;
}
}
if ($subSection == ACCOUNT_CUSTOMIZE_DESIGN) {
$data['customDesign'] = $account->custom_design ?: $design;
}
} else if ($subSection == ACCOUNT_EMAIL_TEMPLATES) {
$data['invoiceEmail'] = $account->getEmailTemplate(ENTITY_INVOICE);
$data['quoteEmail'] = $account->getEmailTemplate(ENTITY_QUOTE);
@ -263,6 +284,8 @@ class AccountController extends BaseController
return AccountController::saveInvoiceSettings();
} elseif ($subSection == ACCOUNT_INVOICE_DESIGN) {
return AccountController::saveInvoiceDesign();
} elseif ($subSection == ACCOUNT_CUSTOMIZE_DESIGN) {
return AccountController::saveCustomizeDesign();
} elseif ($subSection == ACCOUNT_EMAIL_TEMPLATES) {
return AccountController::saveEmailTemplates();
}
@ -271,6 +294,24 @@ class AccountController extends BaseController
}
}
private function saveCustomizeDesign() {
if (Auth::user()->account->isPro()) {
$account = Auth::user()->account;
$account->custom_design = Input::get('custom_design');
$account->invoice_design_id = CUSTOM_DESIGN;
if (!$account->utf8_invoices) {
$account->utf8_invoices = true;
}
$account->save();
Session::flash('message', trans('texts.updated_settings'));
}
return Redirect::to('company/advanced_settings/customize_design');
}
private function saveEmailTemplates()
{
if (Auth::user()->account->isPro()) {

View File

@ -213,6 +213,10 @@ class InvoiceController extends BaseController
$invoice->due_date = Utils::fromSqlDate($invoice->due_date);
$invoice->is_pro = $account->isPro();
if ($invoice->invoice_design_id == CUSTOM_DESIGN) {
$invoice->invoice_design->javascript = $account->custom_design;
}
$contact = $invitation->contact;
$contact->setVisible([
'first_name',

View File

@ -1,6 +1,5 @@
<?php
/*
|--------------------------------------------------------------------------
| Application Routes
@ -247,6 +246,8 @@ define('ACCOUNT_USER_MANAGEMENT', 'user_management');
define('ACCOUNT_DATA_VISUALIZATIONS', 'data_visualizations');
define('ACCOUNT_EMAIL_TEMPLATES', 'email_templates');
define('ACCOUNT_TOKEN_MANAGEMENT', 'token_management');
define('ACCOUNT_CUSTOMIZE_DESIGN', 'customize_design');
define('ACTIVITY_TYPE_CREATE_CLIENT', 1);
define('ACTIVITY_TYPE_ARCHIVE_CLIENT', 2);
@ -300,6 +301,7 @@ define('INVOICE_STATUS_PARTIAL', 4);
define('INVOICE_STATUS_PAID', 5);
define('PAYMENT_TYPE_CREDIT', 1);
define('CUSTOM_DESIGN', 11);
define('FREQUENCY_WEEKLY', 1);
define('FREQUENCY_TWO_WEEKS', 2);

View File

@ -12,6 +12,10 @@ class Account extends Eloquent
use SoftDeletes;
protected $dates = ['deleted_at'];
protected $casts = [
'utf8_invoice' => 'boolean',
];
public function users()
{
return $this->hasMany('App\Models\User');
@ -261,6 +265,8 @@ class Account extends Eloquent
'rate',
'hours',
'balance',
'from',
'to',
];
foreach ($fields as $field) {

View File

@ -2,20 +2,30 @@
use Eloquent;
use Auth;
use App\Models\InvoiceDesign;
class InvoiceDesign extends Eloquent
{
public $timestamps = false;
public function scopeAvailableDesigns($query)
public function scopeAvailableDesigns($query, $utf8 = false)
{
$designs = $query->where('id', '<=', \Auth::user()->maxInvoiceDesignId())->orderBy('id')->get();
$account = Auth::user()->account;
$designs = $query->where('id', '<=', Auth::user()->maxInvoiceDesignId())->orderBy('id')->get();
foreach ($designs as $design) {
$fileName = public_path(strtolower("js/templates/{$design->name}.js"));
if (Auth::user()->account->utf8_invoices && file_exists($fileName)) {
if (($utf8 || Auth::user()->account->utf8_invoices) && file_exists($fileName)) {
$design->javascript = file_get_contents($fileName);
}
if ($design->id == CUSTOM_DESIGN) {
if ($account->utf8_invoices && $account->custom_design) {
$design->javascript = $account->custom_design;
} else {
$designs->pop();
}
}
}
return $designs;

View File

@ -100,7 +100,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
public function maxInvoiceDesignId()
{
return $this->isPro() ? 10 : COUNT_FREE_DESIGNS;
return $this->isPro() ? 11 : COUNT_FREE_DESIGNS;
}
public function getDisplayName()

View File

@ -20,7 +20,8 @@
"d3": "3.4.11",
"handsontable": "*",
"pdfmake": "*",
"moment": "*"
"moment": "*",
"jsoneditor": "*"
},
"resolutions": {
"jquery": "~1.11"

View File

@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddCustomDesign extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('accounts', function($table)
{
$table->text('custom_design')->nullable();
});
DB::table('invoice_designs')->insert(['id' => CUSTOM_DESIGN, 'name' => 'Custom']);
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('accounts', function($table)
{
$table->dropColumn('custom_design');
});
}
}

1
public/css/jsoneditor.min.css vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -31644,33 +31644,51 @@ var isIE = /*@cc_on!@*/false || !!document.documentMode; // At least IE6
var invoiceOld;
var refreshTimer;
function generatePDF(invoice, javascript, force, cb) {
if (!invoice || !javascript) {
return;
}
console.log('== generatePDF - force: %s', force);
if (force || !invoiceOld) {
refreshTimer = null;
} else {
if (refreshTimer) {
clearTimeout(refreshTimer);
}
refreshTimer = setTimeout(function() {
generatePDF(invoice, javascript, true, cb);
}, 500);
return;
}
invoice = calculateAmounts(invoice);
var a = copyInvoice(invoice);
var b = copyInvoice(invoiceOld);
var a = copyObject(invoice);
var b = copyObject(invoiceOld);
if (!force && _.isEqual(a, b)) {
return;
}
pdfmakeMarker = "//pdfmake";
invoiceOld = invoice;
report_id = invoice.invoice_design_id;
pdfmakeMarker = "{";
if(javascript.slice(0, pdfmakeMarker.length) === pdfmakeMarker) {
doc = GetPdfMake(invoice, javascript, cb);
//doc.getDataUrl(cb);
} else {
doc = GetPdf(invoice, javascript);
doc.getDataUrl = function(cb) {
cb( this.output("datauristring"));
};
}
if (cb) {
doc.getDataUrl(cb);
}
return doc;
}
function copyInvoice(orig) {
function copyObject(orig) {
if (!orig) return false;
var copy = JSON.stringify(orig);
var copy = JSON.parse(copy);
return copy;
return JSON.parse(JSON.stringify(orig));
}
@ -33213,73 +33231,63 @@ function twoDigits(value) {
}
var NINJA = NINJA || {};
NINJA.TEMPLATES = {
CLEAN: "1",
BOLD:"2",
MODERN: "3",
NORMAL:"4",
BUSINESS:"5",
CREATIVE:"6",
ELEGANT:"7",
HIPSTER:"8",
PLAYFUL:"9",
PHOTO:"10"
};
function GetPdfMake(invoice, javascript, callback) {
var account = invoice.account;
var baseDD = {
pageMargins: [40, 40, 40, 40],
styles: {
bold: {
bold: true
},
cost: {
alignment: 'right'
},
quantity: {
alignment: 'right'
},
tax: {
alignment: 'right'
},
lineTotal: {
alignment: 'right'
},
right: {
alignment: 'right'
},
subtotals: {
alignment: 'right'
},
termsLabel: {
bold: true,
margin: [0, 10, 0, 4]
}
},
footer: function(){
f = [{ text:invoice.invoice_footer?processVariables(invoice.invoice_footer):"", margin: [40, 0]}]
if (!invoice.is_pro && logoImages.imageLogo1) {
f.push({
image: logoImages.imageLogo1,
width: 150,
margin: [40,0]
});
}
return f;
},
//console.log("== GetPdfMake.. ");
//console.log(javascript);
javascript = NINJA.decodeJavascript(invoice, javascript);
function jsonCallBack(key, val) {
if ((val+'').indexOf('$borderTopAndBottom') === 0) {
var parts = val.split(':');
return function (i, node) {
return (i === 0 || i === node.table.body.length) ? parseFloat(parts[1]) : 0;
};
} else if ((val+'').indexOf('$borderNone') === 0) {
return function (i, node) {
return 0;
};
} else if ((val+'').indexOf('$borderNotTop') === 0) {
var parts = val.split(':');
return function (i, node) {
return i === 0 ? 0 : parseFloat(parts[1]);
};
} else if ((val+'').indexOf('$padding') === 0) {
var parts = val.split(':');
return function (i, node) {
return parseInt(parts[1], 10);
};
} else if ((val+'').indexOf('$primaryColor') === 0) {
var parts = val.split(':');
return NINJA.primaryColor || parts[1];
} else if ((val+'').indexOf('$secondaryColor') === 0) {
var parts = val.split(':');
return NINJA.secondaryColor || parts[1];
}
eval(javascript);
dd = $.extend(true, baseDD, dd);
return val;
}
//console.log(javascript);
var dd = JSON.parse(javascript, jsonCallBack);
//console.log(JSON.stringify(dd));
/*
pdfMake.fonts = {
wqy: {
normal: 'wqy.ttf',
bold: 'wqy.ttf',
italics: 'wqy.ttf',
bolditalics: 'wqy.ttf'
}
};
*/
/*
pdfMake.fonts = {
NotoSansCJKsc: {
normal: 'NotoSansCJKsc-Regular.ttf',
bold: 'NotoSansCJKsc-Medium.ttf',
italics: 'NotoSansCJKsc-Italic.ttf',
bolditalics: 'NotoSansCJKsc-Italic.ttf'
},
var fonts = {
Roboto: {
normal: 'Roboto-Regular.ttf',
bold: 'Roboto-Medium.ttf',
@ -33296,30 +33304,82 @@ function GetPdfMake(invoice, javascript, callback) {
return doc;
}
NINJA.decodeJavascript = function(invoice, javascript)
{
var account = invoice.account;
var blankImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVQYV2NgYAAAAAMAAWgmWQ0AAAAASUVORK5CYII=';
var json = {
'accountName': account.name || ' ',
'accountLogo': window.accountLogo || blankImage,
'accountDetails': NINJA.accountDetails(invoice),
'accountAddress': NINJA.accountAddress(invoice),
'invoiceDetails': NINJA.invoiceDetails(invoice),
'invoiceDetailsHeight': NINJA.invoiceDetails(invoice).length * 22,
'invoiceLineItems': NINJA.invoiceLines(invoice),
'invoiceLineItemColumns': NINJA.invoiceColumns(invoice),
'clientDetails': NINJA.clientDetails(invoice),
'notesAndTerms': NINJA.notesAndTerms(invoice),
'subtotals': NINJA.subtotals(invoice),
'subtotalsHeight': NINJA.subtotals(invoice).length * 22,
'subtotalsWithoutBalance': NINJA.subtotals(invoice, true),
'balanceDue': formatMoney(invoice.balance_amount, invoice.client.currency_id),
'balanceDueLabel': invoiceLabels.balance_due,
'invoiceFooter': account.invoice_footer || ' ',
'entityType': invoice.is_quote ? invoiceLabels.quote : invoiceLabels.invoice,
'entityTypeUpper': (invoice.is_quote ? invoiceLabels.quote : invoiceLabels.invoice).toUpperCase(),
'yourInvoice': invoiceLabels.your_invoice,
'yourInvoiceUpper': invoiceLabels.your_invoice.toUpperCase(),
'invoiceIssuedTo': invoiceLabels.invoice_issued_to + ':',
'fontSize': NINJA.fontSize,
'fontSizeLarger': NINJA.fontSize + 1,
'fontSizeLargest': NINJA.fontSize + 2,
}
for (var key in json) {
var regExp = new RegExp('"\\$'+key+'"', 'g');
var val = JSON.stringify(json[key]);
javascript = javascript.replace(regExp, val);
}
return javascript;
}
NINJA.notesAndTerms = function(invoice)
{
var text = [];
var data = [];
if (invoice.public_notes) {
text.push({text:processVariables(invoice.public_notes), style:'notes'});
data.push({text:invoice.public_notes, style: ['notes']});
data.push({text:' '});
}
if (invoice.terms) {
text.push({text:invoiceLabels.terms, style:'termsLabel'});
text.push({text:processVariables(invoice.terms), style:'terms'});
data.push({text:invoiceLabels.terms, style: ['bold']});
data.push({text:invoice.terms, style: ['terms']});
}
return text;
return NINJA.prepareDataList(data, 'notesAndTerms');
}
NINJA.invoiceColumns = function(invoice)
{
if (invoice.has_taxes) {
return ["15%", "*", "auto", "auto", "auto", "15%"];
} else {
return ["15%", "*", "auto", "auto", "15%"]
}
}
NINJA.invoiceLines = function(invoice) {
var grid = [
[
{text: invoiceLabels.item, style: 'tableHeader'},
{text: invoiceLabels.description, style: 'tableHeader'},
{text: invoiceLabels.unit_cost, style: 'tableHeader'},
{text: invoiceLabels.quantity, style: 'tableHeader'},
{text: invoice.has_taxes?invoiceLabels.tax:'', style: 'tableHeader'},
{text: invoiceLabels.line_total, style: 'tableHeader'}
{text: invoiceLabels.item, style: ['tableHeader', 'itemTableHeader']},
{text: invoiceLabels.description, style: ['tableHeader', 'descriptionTableHeader']},
{text: invoiceLabels.unit_cost, style: ['tableHeader', 'costTableHeader']},
{text: invoiceLabels.quantity, style: ['tableHeader', 'qtyTableHeader']},
{text: invoice.has_taxes ? invoiceLabels.tax : '', style: ['tableHeader', 'taxTableHeader']},
{text: invoiceLabels.line_total, style: ['tableHeader', 'lineTotalTableHeader']}
]
];
@ -33329,13 +33389,15 @@ NINJA.invoiceLines = function(invoice) {
var hideQuantity = invoice.account.hide_quantity == '1';
for (var i = 0; i < invoice.invoice_items.length; i++) {
var row = [];
var item = invoice.invoice_items[i];
var cost = formatMoney(item.cost, currencyId, true);
var qty = NINJA.parseFloat(item.qty) ? roundToTwo(NINJA.parseFloat(item.qty)) + '' : '';
var notes = item.notes;
var productKey = item.product_key;
var tax = "";
var tax = '';
if (item.tax && parseFloat(item.tax.rate)) {
tax = parseFloat(item.tax.rate);
} else if (item.tax_rate && parseFloat(item.tax_rate)) {
@ -33343,9 +33405,11 @@ NINJA.invoiceLines = function(invoice) {
}
// show at most one blank line
if (shownItem && (!cost || cost == '0.00') && !notes && !productKey) {
//if (shownItem && (!cost || cost == '0.00') && !notes && !productKey) {
if ((!cost || cost == '0.00') && !notes && !productKey) {
continue;
}
shownItem = true;
// process date variables
@ -33363,139 +33427,165 @@ NINJA.invoiceLines = function(invoice) {
}
lineTotal = formatMoney(lineTotal, currencyId);
rowStyle = i%2===0?'odd':'even';
rowStyle = (i % 2 == 0) ? 'odd' : 'even';
row[0] = {style:["productKey", rowStyle], text:productKey};
row[1] = {style:["notes", rowStyle], text:notes};
row[2] = {style:["cost", rowStyle], text:cost};
row[3] = {style:["quantity", rowStyle], text:qty};
row[4] = {style:["tax", rowStyle], text:""+tax};
row[5] = {style:["lineTotal", rowStyle], text:lineTotal};
row.push({style:["productKey", rowStyle], text:productKey || ' '}); // product key can be blank when selecting from a datalist
row.push({style:["notes", rowStyle], text:notes || ' '});
row.push({style:["cost", rowStyle], text:cost});
row.push({style:["quantity", rowStyle], text:qty || ' '});
if (invoice.has_taxes) {
row.push({style:["tax", rowStyle], text: tax+'' || ''});
}
row.push({style:["lineTotal", rowStyle], text:lineTotal || ' '});
grid.push(row);
}
return grid;
return NINJA.prepareDataTable(grid, 'invoiceItems');
}
NINJA.subtotals = function(invoice)
NINJA.subtotals = function(invoice, removeBalance)
{
if (!invoice) {
return;
}
var data = [
[invoiceLabels.subtotal, formatMoney(invoice.subtotal_amount, invoice.client.currency_id)],
];
var account = invoice.account;
var data = [];
data.push([{text: invoiceLabels.subtotal}, {text: formatMoney(invoice.subtotal_amount, invoice.client.currency_id)}]);
if (invoice.discount_amount != 0) {
data.push([invoiceLabels.discount, formatMoney(invoice.discount_amount, invoice.client.currency_id)]);
data.push([{text: invoiceLabels.discount}, {text: formatMoney(invoice.discount_amount, invoice.client.currency_id)}]);
}
if (NINJA.parseFloat(invoice.custom_value1) && invoice.custom_taxes1 == '1') {
data.push([invoiceLabels.custom_invoice_label1, formatMoney(invoice.custom_value1, invoice.client.currency_id)]);
data.push([{text: account.custom_invoice_label1}, {text: formatMoney(invoice.custom_value1, invoice.client.currency_id)}]);
}
if (NINJA.parseFloat(invoice.custom_value2) && invoice.custom_taxes2 == '1') {
data.push([invoiceLabels.custom_invoice_label2, formatMoney(invoice.custom_value2, invoice.client.currency_id)]);
data.push([{text: account.custom_invoice_label2}, {text: formatMoney(invoice.custom_value2, invoice.client.currency_id)}]);
}
if (invoice.tax && invoice.tax.name || invoice.tax_name) {
data.push([invoiceLabels.tax, formatMoney(invoice.tax_amount, invoice.client.currency_id)]);
data.push([{text: invoiceLabels.tax}, {text: formatMoney(invoice.tax_amount, invoice.client.currency_id)}]);
}
if (NINJA.parseFloat(invoice.custom_value1) && invoice.custom_taxes1 != '1') {
data.push([invoiceLabels.custom_invoice_label1, formatMoney(invoice.custom_value1, invoice.client.currency_id)]);
data.push([{text: account.custom_invoice_label1}, {text: formatMoney(invoice.custom_value1, invoice.client.currency_id)}]);
}
if (NINJA.parseFloat(invoice.custom_value2) && invoice.custom_taxes2 != '1') {
data.push([invoiceLabels.custom_invoice_label2, formatMoney(invoice.custom_value2, invoice.client.currency_id)]);
data.push([{text: account.custom_invoice_label2}, {text: formatMoney(invoice.custom_value2, invoice.client.currency_id)}]);
}
var paid = invoice.amount - invoice.balance;
if (invoice.account.hide_paid_to_date != '1' || paid) {
data.push([invoiceLabels.paid_to_date, formatMoney(paid, invoice.client.currency_id)]);
data.push([{text:invoiceLabels.paid_to_date}, {text:formatMoney(paid, invoice.client.currency_id)}]);
}
data.push([{text:invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due, style:'balanceDueLabel'},
{text:formatMoney(invoice.balance_amount, invoice.client.currency_id), style:'balanceDueValue'}]);
return data;
if (!removeBalance) {
data.push([
{text:invoice.is_quote ? invoiceLabels.balance_due : invoiceLabels.balance_due, style:['balanceDueLabel']},
{text:formatMoney(invoice.balance_amount, invoice.client.currency_id), style:['balanceDue']}
]);
}
NINJA.accountDetails = function(account) {
var data = [];
if(account.name) data.push({text:account.name, style:'accountName'});
if(account.id_number) data.push({text:account.id_number, style:'accountDetails'});
if(account.vat_number) data.push({text:account.vat_number, style:'accountDetails'});
if(account.work_email) data.push({text:account.work_email, style:'accountDetails'});
if(account.work_phone) data.push({text:account.work_phone, style:'accountDetails'});
return data;
//return data;
return NINJA.prepareDataPairs(data, 'subtotals');
}
NINJA.accountAddress = function(account) {
var address = '';
NINJA.accountDetails = function(invoice) {
var account = invoice.account;
var data = [
{text:account.name, style: ['accountName']},
{text:account.id_number},
{text:account.vat_number},
{text:account.work_email},
{text:account.work_phone}
];
return NINJA.prepareDataList(data, 'accountDetails');
}
NINJA.accountAddress = function(invoice) {
var account = invoice.account;
var cityStatePostal = '';
if (account.city || account.state || account.postal_code) {
address = ((account.city ? account.city + ', ' : '') + account.state + ' ' + account.postal_code).trim();
cityStatePostal = ((account.city ? account.city + ', ' : '') + account.state + ' ' + account.postal_code).trim();
}
var data = [];
if(account.address1) data.push({text:account.address1, style:'accountDetails'});
if(account.address2) data.push({text:account.address2, style:'accountDetails'});
if(address) data.push({text:address, style:'accountDetails'});
if(account.country) data.push({text:account.country.name, style: 'accountDetails'});
if(account.custom_label1 && account.custom_value1) data.push({text:account.custom_label1 +' '+ account.custom_value1, style: 'accountDetails'});
if(account.custom_label2 && account.custom_value2) data.push({text:account.custom_label2 +' '+ account.custom_value2, style: 'accountDetails'});
return data;
var data = [
{text: account.address1},
{text: account.address2},
{text: cityStatePostal},
{text: account.country ? account.country.name : ''}
];
return NINJA.prepareDataList(data, 'accountAddress');
}
NINJA.invoiceDetails = function(invoice) {
var data = [
[
invoice.is_quote ? invoiceLabels.quote_number : invoiceLabels.invoice_number,
{style: 'bold', text: invoice.invoice_number},
{text: (invoice.is_quote ? invoiceLabels.quote_number : invoiceLabels.invoice_number), style: ['invoiceNumberLabel']},
{text: invoice.invoice_number, style: ['invoiceNumber']}
],
[
invoice.is_quote ? invoiceLabels.quote_date : invoiceLabels.invoice_date,
invoice.invoice_date,
{text: invoiceLabels.po_number},
{text: invoice.po_number}
],
[
invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due,
formatMoney(invoice.balance_amount, invoice.client.currency_id),
{text: invoiceLabels.invoice_date},
{text: invoice.invoice_date}
],
[
{text: invoiceLabels.due_date},
{text: invoice.due_date}
]
];
return data;
if (NINJA.parseFloat(invoice.balance) < NINJA.parseFloat(invoice.amount)) {
data.push([
{text: invoiceLabels.total},
{text: formatMoney(invoice.amount, invoice.client.currency_id)}
]);
}
if (NINJA.parseFloat(invoice.partial)) {
data.push([
{text: invoiceLabels.balance},
{text: formatMoney(invoice.total_amount, invoice.client.currency_id)}
]);
}
data.push([
{text: invoiceLabels.balance_due},
{text: formatMoney(invoice.balance_amount, invoice.client.currency_id), style: ['invoiceDetailBalanceDue']}
])
return NINJA.prepareDataPairs(data, 'invoiceDetails');
}
NINJA.clientDetails = function(invoice) {
var client = invoice.client;
var data;
if (!client) {
return;
}
var contact = client.contacts[0];
var clientName = client.name || (contact.first_name || contact.last_name ? (contact.first_name + ' ' + contact.last_name) : contact.email);
var clientEmail = client.contacts[0].email == clientName ? '' : client.contacts[0].email;
var fields = [
getClientDisplayName(client),
client.id_number,
client.vat_number,
concatStrings(client.address1, client.address2),
concatStrings(client.city, client.state, client.postal_code),
client.country ? client.country.name : false,
invoice.contact && getClientDisplayName(client) != invoice.contact.email ? invoice.contact.email : false,
invoice.client.custom_value1 ? invoice.account['custom_client_label1'] + ' ' + invoice.client.custom_value1 : false,
invoice.client.custom_value2 ? invoice.account['custom_client_label2'] + ' ' + invoice.client.custom_value2 : false,
data = [
{text:clientName || ' ', style: ['clientName']},
{text:client.address1},
{text:concatStrings(client.city, client.state, client.postal_code)},
{text:client.country ? client.country.name : ''},
{text:clientEmail}
];
var data = [];
for (var i=0; i<fields.length; i++) {
var field = fields[i];
if (!field) {
continue;
return NINJA.prepareDataList(data, 'clientDetails');
}
data.push([field]);
}
if (!data.length) {
data.push(['']);
}
return data;
}
NINJA.getPrimaryColor = function(defaultColor) {
return NINJA.primaryColor ? NINJA.primaryColor : defaultColor;
@ -33505,6 +33595,62 @@ NINJA.getSecondaryColor = function(defaultColor) {
return NINJA.primaryColor ? NINJA.secondaryColor : defaultColor;
}
NINJA.getEntityLabel = function(invoice) {
return invoice.is_quote ? invoiceLabels.quote : invoiceLabels.invoice;
// remove blanks and add section style to all elements
NINJA.prepareDataList = function(oldData, section) {
var newData = [];
for (var i=0; i<oldData.length; i++) {
var item = NINJA.processItem(oldData[i], section);
if (item.text) {
newData.push(item);
}
}
return newData;
}
NINJA.prepareDataTable = function(oldData, section) {
var newData = [];
for (var i=0; i<oldData.length; i++) {
var row = oldData[i];
var newRow = [];
for (var j=0; j<row.length; j++) {
var item = NINJA.processItem(row[j], section);
if (item.text) {
newRow.push(item);
}
}
if (newRow.length) {
newData.push(newRow);
}
}
return newData;
}
NINJA.prepareDataPairs = function(oldData, section) {
var newData = [];
for (var i=0; i<oldData.length; i++) {
var row = oldData[i];
var isBlank = false;
for (var j=0; j<row.length; j++) {
var item = NINJA.processItem(row[j], section);
if (!item.text) {
isBlank = true;
}
if (j == 1) {
NINJA.processItem(row[j], section + "Value");
}
}
if (!isBlank) {
newData.push(oldData[i]);
}
}
return newData;
}
NINJA.processItem = function(item, section) {
if (item.style && item.style instanceof Array) {
item.style.push(section);
} else {
item.style = [section];
}
return item;
}

44
public/js/jsoneditor.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,72 +1,62 @@
var NINJA = NINJA || {};
NINJA.TEMPLATES = {
CLEAN: "1",
BOLD:"2",
MODERN: "3",
NORMAL:"4",
BUSINESS:"5",
CREATIVE:"6",
ELEGANT:"7",
HIPSTER:"8",
PLAYFUL:"9",
PHOTO:"10"
};
function GetPdfMake(invoice, javascript, callback) {
var account = invoice.account;
var baseDD = {
pageMargins: [40, 40, 40, 40],
styles: {
bold: {
bold: true
},
cost: {
alignment: 'right'
},
quantity: {
alignment: 'right'
},
tax: {
alignment: 'right'
},
lineTotal: {
alignment: 'right'
},
right: {
alignment: 'right'
},
subtotals: {
alignment: 'right'
},
termsLabel: {
bold: true,
margin: [0, 10, 0, 4]
}
},
footer: function(){
f = [{ text:invoice.invoice_footer?processVariables(invoice.invoice_footer):"", margin: [40, 0]}]
if (!invoice.is_pro && logoImages.imageLogo1) {
f.push({
image: logoImages.imageLogo1,
width: 150,
margin: [40,0]
});
}
return f;
},
//console.log("== GetPdfMake.. ");
//console.log(javascript);
javascript = NINJA.decodeJavascript(invoice, javascript);
function jsonCallBack(key, val) {
if ((val+'').indexOf('$borderTopAndBottom') === 0) {
var parts = val.split(':');
return function (i, node) {
return (i === 0 || i === node.table.body.length) ? parseFloat(parts[1]) : 0;
};
} else if ((val+'').indexOf('$borderNone') === 0) {
return function (i, node) {
return 0;
};
} else if ((val+'').indexOf('$borderNotTop') === 0) {
var parts = val.split(':');
return function (i, node) {
return i === 0 ? 0 : parseFloat(parts[1]);
};
} else if ((val+'').indexOf('$padding') === 0) {
var parts = val.split(':');
return function (i, node) {
return parseInt(parts[1], 10);
};
} else if ((val+'').indexOf('$primaryColor') === 0) {
var parts = val.split(':');
return NINJA.primaryColor || parts[1];
} else if ((val+'').indexOf('$secondaryColor') === 0) {
var parts = val.split(':');
return NINJA.secondaryColor || parts[1];
}
eval(javascript);
dd = $.extend(true, baseDD, dd);
return val;
}
//console.log(javascript);
var dd = JSON.parse(javascript, jsonCallBack);
//console.log(JSON.stringify(dd));
/*
pdfMake.fonts = {
wqy: {
normal: 'wqy.ttf',
bold: 'wqy.ttf',
italics: 'wqy.ttf',
bolditalics: 'wqy.ttf'
}
};
*/
/*
pdfMake.fonts = {
NotoSansCJKsc: {
normal: 'NotoSansCJKsc-Regular.ttf',
bold: 'NotoSansCJKsc-Medium.ttf',
italics: 'NotoSansCJKsc-Italic.ttf',
bolditalics: 'NotoSansCJKsc-Italic.ttf'
},
var fonts = {
Roboto: {
normal: 'Roboto-Regular.ttf',
bold: 'Roboto-Medium.ttf',
@ -83,30 +73,82 @@ function GetPdfMake(invoice, javascript, callback) {
return doc;
}
NINJA.decodeJavascript = function(invoice, javascript)
{
var account = invoice.account;
var blankImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVQYV2NgYAAAAAMAAWgmWQ0AAAAASUVORK5CYII=';
var json = {
'accountName': account.name || ' ',
'accountLogo': window.accountLogo || blankImage,
'accountDetails': NINJA.accountDetails(invoice),
'accountAddress': NINJA.accountAddress(invoice),
'invoiceDetails': NINJA.invoiceDetails(invoice),
'invoiceDetailsHeight': NINJA.invoiceDetails(invoice).length * 22,
'invoiceLineItems': NINJA.invoiceLines(invoice),
'invoiceLineItemColumns': NINJA.invoiceColumns(invoice),
'clientDetails': NINJA.clientDetails(invoice),
'notesAndTerms': NINJA.notesAndTerms(invoice),
'subtotals': NINJA.subtotals(invoice),
'subtotalsHeight': NINJA.subtotals(invoice).length * 22,
'subtotalsWithoutBalance': NINJA.subtotals(invoice, true),
'balanceDue': formatMoney(invoice.balance_amount, invoice.client.currency_id),
'balanceDueLabel': invoiceLabels.balance_due,
'invoiceFooter': account.invoice_footer || ' ',
'entityType': invoice.is_quote ? invoiceLabels.quote : invoiceLabels.invoice,
'entityTypeUpper': (invoice.is_quote ? invoiceLabels.quote : invoiceLabels.invoice).toUpperCase(),
'yourInvoice': invoiceLabels.your_invoice,
'yourInvoiceUpper': invoiceLabels.your_invoice.toUpperCase(),
'invoiceIssuedTo': invoiceLabels.invoice_issued_to + ':',
'fontSize': NINJA.fontSize,
'fontSizeLarger': NINJA.fontSize + 1,
'fontSizeLargest': NINJA.fontSize + 2,
}
for (var key in json) {
var regExp = new RegExp('"\\$'+key+'"', 'g');
var val = JSON.stringify(json[key]);
javascript = javascript.replace(regExp, val);
}
return javascript;
}
NINJA.notesAndTerms = function(invoice)
{
var text = [];
var data = [];
if (invoice.public_notes) {
text.push({text:processVariables(invoice.public_notes), style:'notes'});
data.push({text:invoice.public_notes, style: ['notes']});
data.push({text:' '});
}
if (invoice.terms) {
text.push({text:invoiceLabels.terms, style:'termsLabel'});
text.push({text:processVariables(invoice.terms), style:'terms'});
data.push({text:invoiceLabels.terms, style: ['bold']});
data.push({text:invoice.terms, style: ['terms']});
}
return text;
return NINJA.prepareDataList(data, 'notesAndTerms');
}
NINJA.invoiceColumns = function(invoice)
{
if (invoice.has_taxes) {
return ["15%", "*", "auto", "auto", "auto", "15%"];
} else {
return ["15%", "*", "auto", "auto", "15%"]
}
}
NINJA.invoiceLines = function(invoice) {
var grid = [
[
{text: invoiceLabels.item, style: 'tableHeader'},
{text: invoiceLabels.description, style: 'tableHeader'},
{text: invoiceLabels.unit_cost, style: 'tableHeader'},
{text: invoiceLabels.quantity, style: 'tableHeader'},
{text: invoice.has_taxes?invoiceLabels.tax:'', style: 'tableHeader'},
{text: invoiceLabels.line_total, style: 'tableHeader'}
{text: invoiceLabels.item, style: ['tableHeader', 'itemTableHeader']},
{text: invoiceLabels.description, style: ['tableHeader', 'descriptionTableHeader']},
{text: invoiceLabels.unit_cost, style: ['tableHeader', 'costTableHeader']},
{text: invoiceLabels.quantity, style: ['tableHeader', 'qtyTableHeader']},
{text: invoice.has_taxes ? invoiceLabels.tax : '', style: ['tableHeader', 'taxTableHeader']},
{text: invoiceLabels.line_total, style: ['tableHeader', 'lineTotalTableHeader']}
]
];
@ -116,13 +158,15 @@ NINJA.invoiceLines = function(invoice) {
var hideQuantity = invoice.account.hide_quantity == '1';
for (var i = 0; i < invoice.invoice_items.length; i++) {
var row = [];
var item = invoice.invoice_items[i];
var cost = formatMoney(item.cost, currencyId, true);
var qty = NINJA.parseFloat(item.qty) ? roundToTwo(NINJA.parseFloat(item.qty)) + '' : '';
var notes = item.notes;
var productKey = item.product_key;
var tax = "";
var tax = '';
if (item.tax && parseFloat(item.tax.rate)) {
tax = parseFloat(item.tax.rate);
} else if (item.tax_rate && parseFloat(item.tax_rate)) {
@ -130,9 +174,11 @@ NINJA.invoiceLines = function(invoice) {
}
// show at most one blank line
if (shownItem && (!cost || cost == '0.00') && !notes && !productKey) {
//if (shownItem && (!cost || cost == '0.00') && !notes && !productKey) {
if ((!cost || cost == '0.00') && !notes && !productKey) {
continue;
}
shownItem = true;
// process date variables
@ -150,139 +196,165 @@ NINJA.invoiceLines = function(invoice) {
}
lineTotal = formatMoney(lineTotal, currencyId);
rowStyle = i%2===0?'odd':'even';
rowStyle = (i % 2 == 0) ? 'odd' : 'even';
row[0] = {style:["productKey", rowStyle], text:productKey};
row[1] = {style:["notes", rowStyle], text:notes};
row[2] = {style:["cost", rowStyle], text:cost};
row[3] = {style:["quantity", rowStyle], text:qty};
row[4] = {style:["tax", rowStyle], text:""+tax};
row[5] = {style:["lineTotal", rowStyle], text:lineTotal};
row.push({style:["productKey", rowStyle], text:productKey || ' '}); // product key can be blank when selecting from a datalist
row.push({style:["notes", rowStyle], text:notes || ' '});
row.push({style:["cost", rowStyle], text:cost});
row.push({style:["quantity", rowStyle], text:qty || ' '});
if (invoice.has_taxes) {
row.push({style:["tax", rowStyle], text: tax+'' || ''});
}
row.push({style:["lineTotal", rowStyle], text:lineTotal || ' '});
grid.push(row);
}
return grid;
return NINJA.prepareDataTable(grid, 'invoiceItems');
}
NINJA.subtotals = function(invoice)
NINJA.subtotals = function(invoice, removeBalance)
{
if (!invoice) {
return;
}
var data = [
[invoiceLabels.subtotal, formatMoney(invoice.subtotal_amount, invoice.client.currency_id)],
];
var account = invoice.account;
var data = [];
data.push([{text: invoiceLabels.subtotal}, {text: formatMoney(invoice.subtotal_amount, invoice.client.currency_id)}]);
if (invoice.discount_amount != 0) {
data.push([invoiceLabels.discount, formatMoney(invoice.discount_amount, invoice.client.currency_id)]);
data.push([{text: invoiceLabels.discount}, {text: formatMoney(invoice.discount_amount, invoice.client.currency_id)}]);
}
if (NINJA.parseFloat(invoice.custom_value1) && invoice.custom_taxes1 == '1') {
data.push([invoiceLabels.custom_invoice_label1, formatMoney(invoice.custom_value1, invoice.client.currency_id)]);
data.push([{text: account.custom_invoice_label1}, {text: formatMoney(invoice.custom_value1, invoice.client.currency_id)}]);
}
if (NINJA.parseFloat(invoice.custom_value2) && invoice.custom_taxes2 == '1') {
data.push([invoiceLabels.custom_invoice_label2, formatMoney(invoice.custom_value2, invoice.client.currency_id)]);
data.push([{text: account.custom_invoice_label2}, {text: formatMoney(invoice.custom_value2, invoice.client.currency_id)}]);
}
if (invoice.tax && invoice.tax.name || invoice.tax_name) {
data.push([invoiceLabels.tax, formatMoney(invoice.tax_amount, invoice.client.currency_id)]);
data.push([{text: invoiceLabels.tax}, {text: formatMoney(invoice.tax_amount, invoice.client.currency_id)}]);
}
if (NINJA.parseFloat(invoice.custom_value1) && invoice.custom_taxes1 != '1') {
data.push([invoiceLabels.custom_invoice_label1, formatMoney(invoice.custom_value1, invoice.client.currency_id)]);
data.push([{text: account.custom_invoice_label1}, {text: formatMoney(invoice.custom_value1, invoice.client.currency_id)}]);
}
if (NINJA.parseFloat(invoice.custom_value2) && invoice.custom_taxes2 != '1') {
data.push([invoiceLabels.custom_invoice_label2, formatMoney(invoice.custom_value2, invoice.client.currency_id)]);
data.push([{text: account.custom_invoice_label2}, {text: formatMoney(invoice.custom_value2, invoice.client.currency_id)}]);
}
var paid = invoice.amount - invoice.balance;
if (invoice.account.hide_paid_to_date != '1' || paid) {
data.push([invoiceLabels.paid_to_date, formatMoney(paid, invoice.client.currency_id)]);
data.push([{text:invoiceLabels.paid_to_date}, {text:formatMoney(paid, invoice.client.currency_id)}]);
}
data.push([{text:invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due, style:'balanceDueLabel'},
{text:formatMoney(invoice.balance_amount, invoice.client.currency_id), style:'balanceDueValue'}]);
return data;
if (!removeBalance) {
data.push([
{text:invoice.is_quote ? invoiceLabels.balance_due : invoiceLabels.balance_due, style:['balanceDueLabel']},
{text:formatMoney(invoice.balance_amount, invoice.client.currency_id), style:['balanceDue']}
]);
}
NINJA.accountDetails = function(account) {
var data = [];
if(account.name) data.push({text:account.name, style:'accountName'});
if(account.id_number) data.push({text:account.id_number, style:'accountDetails'});
if(account.vat_number) data.push({text:account.vat_number, style:'accountDetails'});
if(account.work_email) data.push({text:account.work_email, style:'accountDetails'});
if(account.work_phone) data.push({text:account.work_phone, style:'accountDetails'});
return data;
//return data;
return NINJA.prepareDataPairs(data, 'subtotals');
}
NINJA.accountAddress = function(account) {
var address = '';
NINJA.accountDetails = function(invoice) {
var account = invoice.account;
var data = [
{text:account.name, style: ['accountName']},
{text:account.id_number},
{text:account.vat_number},
{text:account.work_email},
{text:account.work_phone}
];
return NINJA.prepareDataList(data, 'accountDetails');
}
NINJA.accountAddress = function(invoice) {
var account = invoice.account;
var cityStatePostal = '';
if (account.city || account.state || account.postal_code) {
address = ((account.city ? account.city + ', ' : '') + account.state + ' ' + account.postal_code).trim();
cityStatePostal = ((account.city ? account.city + ', ' : '') + account.state + ' ' + account.postal_code).trim();
}
var data = [];
if(account.address1) data.push({text:account.address1, style:'accountDetails'});
if(account.address2) data.push({text:account.address2, style:'accountDetails'});
if(address) data.push({text:address, style:'accountDetails'});
if(account.country) data.push({text:account.country.name, style: 'accountDetails'});
if(account.custom_label1 && account.custom_value1) data.push({text:account.custom_label1 +' '+ account.custom_value1, style: 'accountDetails'});
if(account.custom_label2 && account.custom_value2) data.push({text:account.custom_label2 +' '+ account.custom_value2, style: 'accountDetails'});
return data;
var data = [
{text: account.address1},
{text: account.address2},
{text: cityStatePostal},
{text: account.country ? account.country.name : ''}
];
return NINJA.prepareDataList(data, 'accountAddress');
}
NINJA.invoiceDetails = function(invoice) {
var data = [
[
invoice.is_quote ? invoiceLabels.quote_number : invoiceLabels.invoice_number,
{style: 'bold', text: invoice.invoice_number},
{text: (invoice.is_quote ? invoiceLabels.quote_number : invoiceLabels.invoice_number), style: ['invoiceNumberLabel']},
{text: invoice.invoice_number, style: ['invoiceNumber']}
],
[
invoice.is_quote ? invoiceLabels.quote_date : invoiceLabels.invoice_date,
invoice.invoice_date,
{text: invoiceLabels.po_number},
{text: invoice.po_number}
],
[
invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due,
formatMoney(invoice.balance_amount, invoice.client.currency_id),
{text: invoiceLabels.invoice_date},
{text: invoice.invoice_date}
],
[
{text: invoiceLabels.due_date},
{text: invoice.due_date}
]
];
return data;
if (NINJA.parseFloat(invoice.balance) < NINJA.parseFloat(invoice.amount)) {
data.push([
{text: invoiceLabels.total},
{text: formatMoney(invoice.amount, invoice.client.currency_id)}
]);
}
if (NINJA.parseFloat(invoice.partial)) {
data.push([
{text: invoiceLabels.balance},
{text: formatMoney(invoice.total_amount, invoice.client.currency_id)}
]);
}
data.push([
{text: invoiceLabels.balance_due},
{text: formatMoney(invoice.balance_amount, invoice.client.currency_id), style: ['invoiceDetailBalanceDue']}
])
return NINJA.prepareDataPairs(data, 'invoiceDetails');
}
NINJA.clientDetails = function(invoice) {
var client = invoice.client;
var data;
if (!client) {
return;
}
var contact = client.contacts[0];
var clientName = client.name || (contact.first_name || contact.last_name ? (contact.first_name + ' ' + contact.last_name) : contact.email);
var clientEmail = client.contacts[0].email == clientName ? '' : client.contacts[0].email;
var fields = [
getClientDisplayName(client),
client.id_number,
client.vat_number,
concatStrings(client.address1, client.address2),
concatStrings(client.city, client.state, client.postal_code),
client.country ? client.country.name : false,
invoice.contact && getClientDisplayName(client) != invoice.contact.email ? invoice.contact.email : false,
invoice.client.custom_value1 ? invoice.account['custom_client_label1'] + ' ' + invoice.client.custom_value1 : false,
invoice.client.custom_value2 ? invoice.account['custom_client_label2'] + ' ' + invoice.client.custom_value2 : false,
data = [
{text:clientName || ' ', style: ['clientName']},
{text:client.address1},
{text:concatStrings(client.city, client.state, client.postal_code)},
{text:client.country ? client.country.name : ''},
{text:clientEmail}
];
var data = [];
for (var i=0; i<fields.length; i++) {
var field = fields[i];
if (!field) {
continue;
return NINJA.prepareDataList(data, 'clientDetails');
}
data.push([field]);
}
if (!data.length) {
data.push(['']);
}
return data;
}
NINJA.getPrimaryColor = function(defaultColor) {
return NINJA.primaryColor ? NINJA.primaryColor : defaultColor;
@ -292,6 +364,62 @@ NINJA.getSecondaryColor = function(defaultColor) {
return NINJA.primaryColor ? NINJA.secondaryColor : defaultColor;
}
NINJA.getEntityLabel = function(invoice) {
return invoice.is_quote ? invoiceLabels.quote : invoiceLabels.invoice;
// remove blanks and add section style to all elements
NINJA.prepareDataList = function(oldData, section) {
var newData = [];
for (var i=0; i<oldData.length; i++) {
var item = NINJA.processItem(oldData[i], section);
if (item.text) {
newData.push(item);
}
}
return newData;
}
NINJA.prepareDataTable = function(oldData, section) {
var newData = [];
for (var i=0; i<oldData.length; i++) {
var row = oldData[i];
var newRow = [];
for (var j=0; j<row.length; j++) {
var item = NINJA.processItem(row[j], section);
if (item.text) {
newRow.push(item);
}
}
if (newRow.length) {
newData.push(newRow);
}
}
return newData;
}
NINJA.prepareDataPairs = function(oldData, section) {
var newData = [];
for (var i=0; i<oldData.length; i++) {
var row = oldData[i];
var isBlank = false;
for (var j=0; j<row.length; j++) {
var item = NINJA.processItem(row[j], section);
if (!item.text) {
isBlank = true;
}
if (j == 1) {
NINJA.processItem(row[j], section + "Value");
}
}
if (!isBlank) {
newData.push(oldData[i]);
}
}
return newData;
}
NINJA.processItem = function(item, section) {
if (item.style && item.style instanceof Array) {
item.style.push(section);
} else {
item.style = [section];
}
return item;
}

View File

@ -8,33 +8,51 @@ var isIE = /*@cc_on!@*/false || !!document.documentMode; // At least IE6
var invoiceOld;
var refreshTimer;
function generatePDF(invoice, javascript, force, cb) {
if (!invoice || !javascript) {
return;
}
console.log('== generatePDF - force: %s', force);
if (force || !invoiceOld) {
refreshTimer = null;
} else {
if (refreshTimer) {
clearTimeout(refreshTimer);
}
refreshTimer = setTimeout(function() {
generatePDF(invoice, javascript, true, cb);
}, 500);
return;
}
invoice = calculateAmounts(invoice);
var a = copyInvoice(invoice);
var b = copyInvoice(invoiceOld);
var a = copyObject(invoice);
var b = copyObject(invoiceOld);
if (!force && _.isEqual(a, b)) {
return;
}
pdfmakeMarker = "//pdfmake";
invoiceOld = invoice;
report_id = invoice.invoice_design_id;
pdfmakeMarker = "{";
if(javascript.slice(0, pdfmakeMarker.length) === pdfmakeMarker) {
doc = GetPdfMake(invoice, javascript, cb);
//doc.getDataUrl(cb);
} else {
doc = GetPdf(invoice, javascript);
doc.getDataUrl = function(cb) {
cb( this.output("datauristring"));
};
}
if (cb) {
doc.getDataUrl(cb);
}
return doc;
}
function copyInvoice(orig) {
function copyObject(orig) {
if (!orig) return false;
var copy = JSON.stringify(orig);
var copy = JSON.parse(copy);
return copy;
return JSON.parse(JSON.stringify(orig));
}

188
public/js/templates/bold.js Normal file
View File

@ -0,0 +1,188 @@
{
"content": [
{
"columns": [
{
"image": "$accountLogo",
"width": 80,
"margin": [60, -40, 0, 0]
},
{
"width": 300,
"stack": [
{"text":"$yourInvoiceUpper", "style": "yourInvoice"},
"$clientDetails"
],
"margin": [-32, 150, 0, 0]
},
{
"canvas": [
{
"type": "rect",
"x": 0,
"y": 0,
"w": 225,
"h": 80,
"r":0,
"lineWidth": 1,
"color": "#36a399"
}
],
"width":10,
"margin":[-10,150,0,0]
},
{
"table": {
"body": "$invoiceDetails"
},
"layout": "noBorders",
"margin": [0, 160, 0, 0]
}
]
},
{
"style": "invoiceLineItemsTable",
"table": {
"headerRows": 1,
"widths": ["15%", "*", "auto", "auto", "auto"],
"body": "$invoiceLineItems"
},
"layout": {
"hLineWidth": "$borderNone",
"vLineWidth": "$borderNone",
"paddingLeft": "$padding:8",
"paddingRight": "$padding:8",
"paddingTop": "$padding:14",
"paddingBottom": "$padding:14"
}
},
{
"columns": [
{
"width": 46,
"text": " "
},
"$notesAndTerms",
{
"table": {
"widths": ["*", "*"],
"body": "$subtotals"
},
"layout": {
"hLineWidth": "$borderNone",
"vLineWidth": "$borderNone",
"paddingLeft": "$padding:8",
"paddingRight": "$padding:8",
"paddingTop": "$padding:4",
"paddingBottom": "$padding:4"
}
}]
}
],
"footer": [
{"canvas": [{ "type": "line", "x1": 0, "y1": 0, "x2": 600, "y2": 0,"lineWidth": 100,"lineColor":"#2e2b2b"}]},
{
"text": "$invoiceFooter",
"margin": [40, -20, 40, 0],
"alignment": "left",
"color": "#FFFFFF"
}
],
"header": [
{"canvas": [{ "type": "line", "x1": 0, "y1": 0, "x2": 50, "y2":0,"lineWidth": 200,"lineColor":"#2e2b2b"}],"width":100,"margin":[0,0,0,0]},
{"canvas": [{ "type": "line", "x1": 0, "y1": 0, "x2": 150, "y2":0,"lineWidth": 60,"lineColor":"#2e2b2b"}],"width":100,"margin":[0,0,0,0]},
{"canvas": [{ "type": "line", "x1": 149, "y1": 0, "x2": 600, "y2":0,"lineWidth": 200,"lineColor":"#2e2b2b"}],"width":10,"margin":[0,0,0,0]},
{
"stack": "$accountDetails",
"margin": [380, 16, 0, 0]
}
],
"defaultStyle": {
"fontSize": "$fontSize",
"margin": [8, 4, 8, 4]
},
"styles": {
"primaryColor":{
"color": "$primaryColor:#299CC2"
},
"accountName": {
"margin": [4, 2, 4, 2],
"color": "$primaryColor:#299CC2"
},
"accountDetails": {
"margin": [4, 2, 4, 2],
"color": "#AAA9A9"
},
"odd": {
"fillColor": "#ebebeb",
"margin": [0,0,0,0]
},
"productKey": {
"color": "$primaryColor:#299CC2"
},
"balanceDueLabel": {
"fontSize": "$fontSizeLargest",
"bold": true
},
"balanceDue": {
"fontSize": "$fontSizeLargest",
"color": "$primaryColor:#299CC2",
"bold": true
},
"invoiceDetails": {
"color": "#ffffff"
},
"invoiceNumber": {
"bold": true
},
"itemTableHeader": {
"margin": [40,0,0,0]
},
"totalTableHeader": {
"margin": [0,0,40,0]
},
"tableHeader": {
"fontSize": 12,
"bold": true
},
"productKey": {
"color": "$primaryColor:#299CC2",
"margin": [40,0,0,0],
"bold": true
},
"yourInvoice": {
"bold": true,
"fontSize": 14,
"color": "#36a399",
"margin": [0,0,0,8]
},
"invoiceLineItemsTable": {
"margin": [0, 16, 0, 16]
},
"clientName": {
"bold": true
},
"cost": {
"alignment": "right"
},
"quantity": {
"alignment": "right"
},
"tax": {
"alignment": "right"
},
"lineTotal": {
"alignment": "right",
"margin": [0,0,40,0]
},
"subtotals": {
"alignment": "right",
"margin": [0,0,40,0]
},
"termsLabel": {
"bold": true,
"margin": [0, 10, 0, 4]
}
},
"pageMargins": [0, 80, 0, 40]
}

View File

@ -1,162 +1,173 @@
//pdfmake
/*
var dd = {
content: 'wqy中文wqy',
defaultStyle: {
font: 'wqy'
}
};
*/
var dd = {
content: [
{
columns: [
[
invoice.image?
"content": [{
"columns": [
{
image: invoice.image,
fit: [150, 80]
}:""
],
{
stack: NINJA.accountDetails(account)
"image": "$accountLogo",
"width": 100
},
{
stack: NINJA.accountAddress(account)
"stack": "$accountDetails",
"margin": [80, 0, 0, 0]
},
{
"stack": "$accountAddress"
}
]
},
{
text:(NINJA.getEntityLabel(invoice)).toUpperCase(),
margin: [8, 70, 8, 16],
style: 'primaryColor',
fontSize: NINJA.fontSize + 2
"text": "$entityTypeUpper",
"margin": [8, 50, 8, 5],
"style": "entityTypeLabel"
},
{
table: {
headerRows: 1,
widths: ['auto', 'auto', '*'],
body: [
"table": {
"headerRows": 1,
"widths": ["auto", "auto", "*"],
"body": [
[
{
table: {
body: NINJA.invoiceDetails(invoice),
"table": {
"body": "$invoiceDetails"
},
layout: 'noBorders',
"margin": [0, 4, 12, 4],
"layout": "noBorders"
},
{
table: {
body: NINJA.clientDetails(invoice),
"stack": "$clientDetails"
},
layout: 'noBorders',
},
''
]
]
},
layout: {
hLineWidth: function (i, node) {
return (i === 0 || i === node.table.body.length) ? .5 : 0;
},
vLineWidth: function (i, node) {
return 0;
},
hLineColor: function (i, node) {
return '#D8D8D8';
},
paddingLeft: function(i, node) { return 8; },
paddingRight: function(i, node) { return 8; },
paddingTop: function(i, node) { return 4; },
paddingBottom: function(i, node) { return 4; }
}
},
'\n',
{
table: {
headerRows: 1,
widths: ['15%', '*', 'auto', 'auto', 'auto', 'auto'],
body: NINJA.invoiceLines(invoice),
},
layout: {
hLineWidth: function (i, node) {
return i === 0 ? 0 : .5;
},
vLineWidth: function (i, node) {
return 0;
},
hLineColor: function (i, node) {
return '#D8D8D8';
},
paddingLeft: function(i, node) { return 8; },
paddingRight: function(i, node) { return 8; },
paddingTop: function(i, node) { return 8; },
paddingBottom: function(i, node) { return 8; }
},
},
'\n',
{
columns: [
NINJA.notesAndTerms(invoice),
{
style: 'subtotals',
table: {
widths: ['*', '*'],
body: NINJA.subtotals(invoice),
},
layout: {
hLineWidth: function (i, node) {
return 0;
},
vLineWidth: function (i, node) {
return 0;
},
paddingLeft: function(i, node) { return 8; },
paddingRight: function(i, node) { return 8; },
paddingTop: function(i, node) { return 4; },
paddingBottom: function(i, node) { return 4; }
},
"text": ""
}
]
]
},
"layout": {
"hLineWidth": "$borderTopAndBottom:.5",
"vLineWidth": "$borderNone",
"hLineColor": "#D8D8D8",
"paddingLeft": "$padding:8",
"paddingRight": "$padding:8",
"paddingTop": "$padding:4",
"paddingBottom": "$padding:4"
}
},
{
"style": "invoiceLineItemsTable",
"table": {
"headerRows": 1,
"widths": "$invoiceLineItemColumns",
"body": "$invoiceLineItems"
},
"layout": {
"hLineWidth": "$borderNotTop:.5",
"vLineWidth": "$borderNone",
"hLineColor": "#D8D8D8",
"paddingLeft": "$padding:8",
"paddingRight": "$padding:8",
"paddingTop": "$padding:14",
"paddingBottom": "$padding:14"
}
},
{
"columns": [
"$notesAndTerms",
{
"table": {
"widths": ["*", "*"],
"body": "$subtotals"
},
"layout": {
"hLineWidth": "$borderNone",
"vLineWidth": "$borderNone",
"paddingLeft": "$padding:8",
"paddingRight": "$padding:8",
"paddingTop": "$padding:4",
"paddingBottom": "$padding:4"
}
}
]
}
],
defaultStyle: {
//font: 'arialuni',
fontSize: NINJA.fontSize,
margin: [8, 4, 8, 4]
"defaultStyle": {
"fontSize": "$fontSize",
"margin": [8, 4, 8, 4]
},
styles: {
primaryColor:{
color: NINJA.getPrimaryColor('#299CC2')
"footer": {
"text": "$invoiceFooter",
"margin": [40, -20, 40, 0],
"alignment": "left"
},
accountName: {
margin: [4, 2, 4, 2],
color: NINJA.getPrimaryColor('#299CC2')
"styles": {
"entityTypeLabel": {
"fontSize": "$fontSizeLargest",
"color": "$primaryColor:#299CC2"
},
accountDetails: {
margin: [4, 2, 4, 2],
color: '#AAA9A9'
"primaryColor":{
"color": "$primaryColor:#299CC2"
},
even: {
"accountName": {
"color": "$primaryColor:#299CC2",
"bold": true
},
odd: {
fillColor:'#F4F4F4'
"accountDetails": {
"margin": [0, 2, 0, 2]
},
productKey: {
color: NINJA.getPrimaryColor('#299CC2')
"clientDetails": {
"margin": [0, 2, 0, 2]
},
tableHeader: {
bold: true
"notesAndTerms": {
"margin": [0, 2, 0, 2]
},
balanceDueLabel: {
fontSize: NINJA.fontSize + 2
"accountAddress": {
"margin": [0, 2, 0, 2]
},
balanceDueValue: {
fontSize: NINJA.fontSize + 2,
color: NINJA.getPrimaryColor('#299CC2')
"odd": {
"fillColor": "#fbfbfb"
},
"productKey": {
"color": "$primaryColor:#299CC2",
"bold": true
},
pageMargins: [40, 40, 40, 40],
};
"balanceDueLabel": {
"fontSize": "$fontSizeLargest"
},
"balanceDue": {
"fontSize": "$fontSizeLargest",
"color": "$primaryColor:#299CC2"
},
"invoiceNumber": {
"bold": true
},
"tableHeader": {
"bold": true,
"fontSize": "$fontSizeLargest"
},
"invoiceLineItemsTable": {
"margin": [0, 16, 0, 16]
},
"clientName": {
"bold": true
},
"cost": {
"alignment": "right"
},
"quantity": {
"alignment": "right"
},
"tax": {
"alignment": "right"
},
"lineTotal": {
"alignment": "right"
},
"subtotals": {
"alignment": "right"
},
"termsLabel": {
"bold": true,
"margin": [0, 10, 0, 4]
}
},
"pageMargins": [40, 40, 40, 40]
}

View File

@ -0,0 +1,220 @@
{
"content": [
{
"columns": [
{
"image": "$accountLogo",
"width": 80,
"margin": [0, 60, 0, 30]
},
{
"stack": "$clientDetails",
"margin": [260, 80, 0, 0]
}
]
},
{
"canvas": [{ "type": "rect", "x": 0, "y": 0, "w": 515, "h": 26, "r":0, "lineWidth": 1, "color":"#403d3d"}],"width":10,"margin":[0,25,0,-30]},
{
"style": "invoiceLineItemsTable",
"table": {
"headerRows": 1,
"widths": ["15%", "*", "auto", "auto", "auto"],
"body": "$invoiceLineItems"
},
"layout": {
"hLineWidth": "$borderNotTop:.5",
"vLineWidth": "$borderNone",
"hLineColor": "#888888",
"paddingLeft": "$padding:8",
"paddingRight": "$padding:8",
"paddingTop": "$padding:8",
"paddingBottom": "$padding:8"
}
},
{
"columns": [
"$notesAndTerms",
{
"table": {
"widths": ["*", "*"],
"body": "$subtotalsWithoutBalance"
},
"layout": {
"hLineWidth": "$borderNone",
"vLineWidth": "$borderNone",
"paddingLeft": "$padding:8",
"paddingRight": "$padding:8",
"paddingTop": "$padding:4",
"paddingBottom": "$padding:4"
}
}
]
},
{
"columns": [
{
"canvas": [
{
"type": "rect",
"x": 0,
"y": 0,
"w": 515,
"h": 26,
"r": 0,
"lineWidth": 1,
"color": "#403d3d"
}
],
"width": 10,
"margin": [
0,
10,
0,
0
]
},
{
"text": "$balanceDueLabel",
"style": "balanceDueLabel",
"margin": [0, 16, 0, 0],
"width": 370
},
{
"text": "$balanceDue",
"style": "balanceDue",
"margin": [0, 16, 8, 0]
}
]
} ],
"footer": [
{
"canvas": [
{
"type": "line", "x1": 0, "y1": 0, "x2": 600, "y2": 0,"lineWidth": 100,"lineColor":"#f26621"
}]
,"width":10
},
{
"columns": [
{
"text": "$invoiceFooter",
"margin": [40, -30, 40, 0],
"alignment": "left",
"color": "#FFFFFF",
"width": 350
},
{
"stack": "$accountDetails",
"margin": [0, -40, 0, 0],
"width": "*"
},
{
"stack": "$accountAddress",
"margin": [0, -40, 0, 0],
"width": "*"
}
]
}
],
"header": [
{
"canvas": [{ "type": "line", "x1": 0, "y1": 0, "x2": 600, "y2": 0,"lineWidth": 200,"lineColor":"#f26621"}],"width":10
},
{
"columns": [
{
"text": "$accountName", "bold": true,"fontSize":30,"color":"#ffffff","margin":[40,20,0,0],"width":350
}
]
},
{
"width": 300,
"table": {
"body": "$invoiceDetails"
},
"layout": "noBorders",
"margin": [400, -40, 0, 0]
}
],
"defaultStyle": {
"fontSize": "$fontSize",
"margin": [8, 4, 8, 4]
},
"styles": {
"primaryColor":{
"color": "$primaryColor:#299CC2"
},
"accountName": {
"margin": [4, 2, 4, 2],
"color": "$primaryColor:#299CC2"
},
"accountDetails": {
"margin": [4, 2, 4, 2],
"color": "#FFFFFF"
},
"accountAddress": {
"margin": [4, 2, 4, 2],
"color": "#FFFFFF"
},
"clientDetails": {
"margin": [0, 2, 4, 2]
},
"invoiceDetails": {
"color": "#FFFFFF"
},
"invoiceLineItemsTable": {
"margin": [0, 0, 0, 16]
},
"productKey": {
"bold": true
},
"clientName": {
"bold": true
},
"tableHeader": {
"bold": true,
"color": "#FFFFFF",
"fontSize": "$fontSizeLargest"
},
"balanceDueLabel": {
"fontSize": "$fontSizeLargest",
"color":"#FFFFFF",
"alignment":"right",
"bold": true
},
"balanceDue": {
"fontSize": "$fontSizeLargest",
"color":"#FFFFFF",
"bold": true,
"alignment":"right"
},
"cost": {
"alignment": "right"
},
"quantity": {
"alignment": "right"
},
"tax": {
"alignment": "right"
},
"lineTotal": {
"alignment": "right"
},
"subtotals": {
"alignment": "right"
},
"termsLabel": {
"bold": true,
"margin": [0, 10, 0, 4]
},
"invoiceNumberLabel": {
"bold": true
},
"invoiceNumber": {
"bold": true
}
},
"pageMargins": [40, 80, 40, 50]
}

View File

@ -0,0 +1,133 @@
{
"content": [
{
"columns": [
{
"stack": "$accountDetails"
},
{
"stack": "$accountAddress"
},
[
{
"image": "$accountLogo",
"width": 100
}
]
]},
{
"columns": [
{
"width": 340,
"stack": "$clientDetails",
"margin": [0,40,0,0]
},
{
"canvas": [{ "type": "rect", "x": 0, "y": 0, "w": 175, "h": 15, "r":0, "lineWidth": 1, "color":"#e6e6e6"}],
"width":10,
"margin":[0,70,0,0]
},
{
"width":200,
"table": {
"body": "$invoiceDetails"
},
"layout": "noBorders",
"margin":[0,40,0,0]
}
]
},
{
"canvas": [{ "type": "rect", "x": 0, "y": 0, "w": 515, "h": 25,"r":0, "lineWidth": 1,"color":"#e6e6e6"}],"width":10,"margin":[0,30,0,-43]
},
{
"style": "invoiceLineItemsTable",
"table": {
"headerRows": 1,
"widths": "$invoiceLineItemColumns",
"body": "$invoiceLineItems"
},
"layout": {
"hLineWidth": "$borderNotTop:1",
"vLineWidth": "$borderNone",
"hLineColor": "#e6e6e6",
"paddingLeft": "$padding:8",
"paddingRight": "$padding:8",
"paddingTop": "$padding:8",
"paddingBottom": "$padding:8"
}
},
{
"columns": [
"$notesAndTerms",
{
"canvas": [{ "type": "rect", "x": -360, "y": 0, "w": 200, "h": 20,"r":0, "lineWidth": 2, "color":"#e6e6e6","lineColor":"#e6e6e6"}],"width":10,"margin":[420,37,0,0]
},
{
"style": "subtotals",
"table": {
"widths": ["*", "*"],
"body": "$subtotals"
},
"layout": {
"hLineWidth": "$borderNone",
"vLineWidth": "$borderNone",
"paddingLeft": "$padding:8",
"paddingRight": "$padding:8",
"paddingTop": "$padding:4",
"paddingBottom": "$padding:4"
}
}
]
}
],
"footer": {
"text": "$invoiceFooter",
"margin": [40, -40, 40, 0],
"alignment": "left"
},
"defaultStyle": {
"fontSize": "$fontSize",
"margin": [8, 4, 8, 4]
},
"styles": {
"primaryColor":{
"color": "$primaryColor:#299CC2"
},
"accountDetails": {
"margin": [0, 2, 0, 1]
},
"accountAddress": {
"margin": [0, 2, 0, 1]
},
"clientDetails": {
"margin": [0, 2, 0, 1]
},
"tableHeader": {
"bold": true
},
"invoiceLineItemsTable": {
"margin": [0, 16, 0, 16]
},
"cost": {
"alignment": "right"
},
"quantity": {
"alignment": "right"
},
"tax": {
"alignment": "right"
},
"lineTotal": {
"alignment": "right"
},
"subtotals": {
"alignment": "right"
},
"termsLabel": {
"bold": true,
"margin": [0, 10, 0, 4]
}
},
"pageMargins": [40, 40, 40, 40]
}

View File

@ -71,3 +71,4 @@ If you'd like to translate the site please use [caouecs/Laravel4-long](https://g
* [caouecs/Laravel4-long](https://github.com/caouecs/Laravel4-lang) - List of languages for Laravel4
* [bgrins/spectrum](https://github.com/bgrins/spectrum) - The No Hassle JavaScript Colorpicker
* [lokesh/lightbox2](https://github.com/lokesh/lightbox2/) - The original lightbox script
* [josdejong/jsoneditor](https://github.com/josdejong/jsoneditor/) - A web-based tool to view, edit and format JSON

View File

@ -599,7 +599,7 @@ return array(
'less_fields' => 'Less Fields',
'client_name' => 'Client Name',
'pdf_settings' => 'PDF Settings',
'utf8_invoices' => 'Cyrillic Support <sup>Beta</sup>',
'utf8_invoices' => 'New PDF Engine <sup>Beta</sup>',
'product_settings' => 'Product Settings',
'auto_wrap' => 'Auto Line Wrap',
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
@ -724,6 +724,20 @@ return array(
'add_to_invoice' => 'Add to invoice :invoice',
'create_new_invoice' => 'Create new invoice',
'task_errors' => 'Please correct any overlapping times',
'from' => 'From',
'to' => 'To',
'font_size' => 'Font Size',
'primary_color' => 'Primary Color',
'secondary_color' => 'Secondary Color',
'customize_design' => 'Customize Design',
'content' => 'Content',
'styles' => 'Styles',
'defaults' => 'Defaults',
'margins' => 'Margins',
'header' => 'Header',
'footer' => 'Footer',
'custom' => 'Custom',

View File

@ -590,7 +590,6 @@ return array(
'less_fields' => 'Weniger Felder',
'client_name' => 'Kundenname',
'pdf_settings' => 'PDF Einstellungen',
'utf8_invoices' => 'Cyrillic Unterstützung <sup>Beta</sup>',
'product_settings' => 'Produkt Einstellungen',
'auto_wrap' => 'Automatischer Zeilenumbruch',
'duplicate_post' => 'Achtung: Die vorherige Seite wurde zweimal abgeschickt. Das zweite Abschicken wurde ignoriert.',
@ -715,6 +714,22 @@ return array(
'add_to_invoice' => 'Add to invoice :invoice',
'create_new_invoice' => 'Create new invoice',
'task_errors' => 'Please correct any overlapping times',
'utf8_invoices' => 'New PDF Engine <sup>Beta</sup>',
'from' => 'From',
'to' => 'To',
'font_size' => 'Font Size',
'primary_color' => 'Primary Color',
'secondary_color' => 'Secondary Color',
'customize_design' => 'Customize Design',
'content' => 'Content',
'styles' => 'Styles',
'defaults' => 'Defaults',
'margins' => 'Margins',
'header' => 'Header',
'footer' => 'Footer',
'custom' => 'Custom',
);

View File

@ -41,7 +41,7 @@ return array(
'tax' => 'Tax',
'item' => 'Item',
'description' => 'Description',
'unit_cost' => 'Unit Cost',
'unit_cost' => 'Cost',
'quantity' => 'Quantity',
'line_total' => 'Line Total',
'subtotal' => 'Subtotal',
@ -401,9 +401,9 @@ return array(
'invoice_fields' => 'Invoice Fields',
'invoice_options' => 'Invoice Options',
'hide_quantity' => 'Hide quantity',
'hide_quantity' => 'Hide Quantity',
'hide_quantity_help' => 'If your line items quantities are always 1, then you can declutter invoices by no longer displaying this field.',
'hide_paid_to_date' => 'Hide paid to date',
'hide_paid_to_date' => 'Hide Paid to Date',
'hide_paid_to_date_help' => 'Only display the "Paid to Date" area on your invoices once a payment has been received.',
'charge_taxes' => 'Charge taxes',
@ -597,7 +597,7 @@ return array(
'less_fields' => 'Less Fields',
'client_name' => 'Client Name',
'pdf_settings' => 'PDF Settings',
'utf8_invoices' => 'Cyrillic Support <sup>Beta</sup>',
'utf8_invoices' => 'New PDF Engine <sup>Beta</sup>',
'product_settings' => 'Product Settings',
'auto_wrap' => 'Auto Line Wrap',
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
@ -722,5 +722,21 @@ return array(
'add_to_invoice' => 'Add to invoice :invoice',
'create_new_invoice' => 'Create new invoice',
'task_errors' => 'Please correct any overlapping times',
'from' => 'From',
'to' => 'To',
'font_size' => 'Font Size',
'primary_color' => 'Primary Color',
'secondary_color' => 'Secondary Color',
'customize_design' => 'Customize Design',
'content' => 'Content',
'styles' => 'Styles',
'defaults' => 'Defaults',
'margins' => 'Margins',
'header' => 'Header',
'footer' => 'Footer',
'custom' => 'Custom',
);

View File

@ -569,7 +569,7 @@ return array(
'less_fields' => 'Less Fields',
'client_name' => 'Client Name',
'pdf_settings' => 'PDF Settings',
'utf8_invoices' => 'Cyrillic Support <sup>Beta</sup>',
'utf8_invoices' => 'New PDF Engine <sup>Beta</sup>',
'product_settings' => 'Product Settings',
'auto_wrap' => 'Auto Line Wrap',
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
@ -694,6 +694,20 @@ return array(
'add_to_invoice' => 'Add to invoice :invoice',
'create_new_invoice' => 'Create new invoice',
'task_errors' => 'Please correct any overlapping times',
'from' => 'From',
'to' => 'To',
'font_size' => 'Font Size',
'primary_color' => 'Primary Color',
'secondary_color' => 'Secondary Color',
'customize_design' => 'Customize Design',
'content' => 'Content',
'styles' => 'Styles',
'defaults' => 'Defaults',
'margins' => 'Margins',
'header' => 'Header',
'footer' => 'Footer',
'custom' => 'Custom',
);

View File

@ -598,7 +598,7 @@ return array(
'less_fields' => 'Less Fields',
'client_name' => 'Client Name',
'pdf_settings' => 'PDF Settings',
'utf8_invoices' => 'Cyrillic Support <sup>Beta</sup>',
'utf8_invoices' => 'New PDF Engine <sup>Beta</sup>',
'product_settings' => 'Product Settings',
'auto_wrap' => 'Auto Line Wrap',
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
@ -723,6 +723,20 @@ return array(
'add_to_invoice' => 'Add to invoice :invoice',
'create_new_invoice' => 'Create new invoice',
'task_errors' => 'Please correct any overlapping times',
'from' => 'From',
'to' => 'To',
'font_size' => 'Font Size',
'primary_color' => 'Primary Color',
'secondary_color' => 'Secondary Color',
'customize_design' => 'Customize Design',
'content' => 'Content',
'styles' => 'Styles',
'defaults' => 'Defaults',
'margins' => 'Margins',
'header' => 'Header',
'footer' => 'Footer',
'custom' => 'Custom',

View File

@ -590,7 +590,7 @@ return array(
'less_fields' => 'Moins de champs',
'client_name' => 'Nom du client',
'pdf_settings' => 'Réglages PDF',
'utf8_invoices' => 'Cyrillic Support <sup>Beta</sup>',
'utf8_invoices' => 'New PDF Engine <sup>Beta</sup>',
'product_settings' => 'Réglages du produit',
'auto_wrap' => 'Auto Line Wrap',
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
@ -715,6 +715,20 @@ return array(
'add_to_invoice' => 'Add to invoice :invoice',
'create_new_invoice' => 'Create new invoice',
'task_errors' => 'Please correct any overlapping times',
'from' => 'From',
'to' => 'To',
'font_size' => 'Font Size',
'primary_color' => 'Primary Color',
'secondary_color' => 'Secondary Color',
'customize_design' => 'Customize Design',
'content' => 'Content',
'styles' => 'Styles',
'defaults' => 'Defaults',
'margins' => 'Margins',
'header' => 'Header',
'footer' => 'Footer',
'custom' => 'Custom',

View File

@ -590,7 +590,7 @@ return array(
'less_fields' => 'Less Fields',
'client_name' => 'Client Name',
'pdf_settings' => 'PDF Settings',
'utf8_invoices' => 'Cyrillic Support <sup>Beta</sup>',
'utf8_invoices' => 'New PDF Engine <sup>Beta</sup>',
'product_settings' => 'Product Settings',
'auto_wrap' => 'Auto Line Wrap',
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
@ -716,6 +716,20 @@ return array(
'add_to_invoice' => 'Add to invoice :invoice',
'create_new_invoice' => 'Create new invoice',
'task_errors' => 'Please correct any overlapping times',
'from' => 'From',
'to' => 'To',
'font_size' => 'Font Size',
'primary_color' => 'Primary Color',
'secondary_color' => 'Secondary Color',
'customize_design' => 'Customize Design',
'content' => 'Content',
'styles' => 'Styles',
'defaults' => 'Defaults',
'margins' => 'Margins',
'header' => 'Header',
'footer' => 'Footer',
'custom' => 'Custom',
);

View File

@ -592,7 +592,7 @@ return array(
'less_fields' => 'Less Fields',
'client_name' => 'Client Name',
'pdf_settings' => 'PDF Settings',
'utf8_invoices' => 'Cyrillic Support <sup>Beta</sup>',
'utf8_invoices' => 'New PDF Engine <sup>Beta</sup>',
'product_settings' => 'Product Settings',
'auto_wrap' => 'Auto Line Wrap',
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
@ -718,6 +718,20 @@ return array(
'add_to_invoice' => 'Add to invoice :invoice',
'create_new_invoice' => 'Create new invoice',
'task_errors' => 'Please correct any overlapping times',
'from' => 'From',
'to' => 'To',
'font_size' => 'Font Size',
'primary_color' => 'Primary Color',
'secondary_color' => 'Secondary Color',
'customize_design' => 'Customize Design',
'content' => 'Content',
'styles' => 'Styles',
'defaults' => 'Defaults',
'margins' => 'Margins',
'header' => 'Header',
'footer' => 'Footer',
'custom' => 'Custom',

View File

@ -600,7 +600,7 @@ return array(
'less_fields' => 'Less Fields',
'client_name' => 'Client Name',
'pdf_settings' => 'PDF Settings',
'utf8_invoices' => 'Cyrillic Support <sup>Beta</sup>',
'utf8_invoices' => 'New PDF Engine <sup>Beta</sup>',
'product_settings' => 'Product Settings',
'auto_wrap' => 'Auto Line Wrap',
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
@ -725,6 +725,20 @@ return array(
'add_to_invoice' => 'Add to invoice :invoice',
'create_new_invoice' => 'Create new invoice',
'task_errors' => 'Please correct any overlapping times',
'from' => 'From',
'to' => 'To',
'font_size' => 'Font Size',
'primary_color' => 'Primary Color',
'secondary_color' => 'Secondary Color',
'customize_design' => 'Customize Design',
'content' => 'Content',
'styles' => 'Styles',
'defaults' => 'Defaults',
'margins' => 'Margins',
'header' => 'Header',
'footer' => 'Footer',
'custom' => 'Custom',

View File

@ -598,7 +598,7 @@ return array(
'less_fields' => 'Less Fields',
'client_name' => 'Client Name',
'pdf_settings' => 'PDF Settings',
'utf8_invoices' => 'Cyrillic Support <sup>Beta</sup>',
'utf8_invoices' => 'New PDF Engine <sup>Beta</sup>',
'product_settings' => 'Product Settings',
'auto_wrap' => 'Auto Line Wrap',
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
@ -723,6 +723,20 @@ return array(
'add_to_invoice' => 'Add to invoice :invoice',
'create_new_invoice' => 'Create new invoice',
'task_errors' => 'Please correct any overlapping times',
'from' => 'From',
'to' => 'To',
'font_size' => 'Font Size',
'primary_color' => 'Primary Color',
'secondary_color' => 'Secondary Color',
'customize_design' => 'Customize Design',
'content' => 'Content',
'styles' => 'Styles',
'defaults' => 'Defaults',
'margins' => 'Margins',
'header' => 'Header',
'footer' => 'Footer',
'custom' => 'Custom',

View File

@ -593,7 +593,7 @@ return array(
'less_fields' => 'Less Fields',
'client_name' => 'Client Name',
'pdf_settings' => 'PDF Settings',
'utf8_invoices' => 'Cyrillic Support <sup>Beta</sup>',
'utf8_invoices' => 'New PDF Engine <sup>Beta</sup>',
'product_settings' => 'Product Settings',
'auto_wrap' => 'Auto Line Wrap',
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
@ -718,6 +718,20 @@ return array(
'add_to_invoice' => 'Add to invoice :invoice',
'create_new_invoice' => 'Create new invoice',
'task_errors' => 'Please correct any overlapping times',
'from' => 'From',
'to' => 'To',
'font_size' => 'Font Size',
'primary_color' => 'Primary Color',
'secondary_color' => 'Secondary Color',
'customize_design' => 'Customize Design',
'content' => 'Content',
'styles' => 'Styles',
'defaults' => 'Defaults',
'margins' => 'Margins',
'header' => 'Header',
'footer' => 'Footer',
'custom' => 'Custom',

View File

@ -593,7 +593,7 @@ return array(
'less_fields' => 'Less Fields',
'client_name' => 'Client Name',
'pdf_settings' => 'PDF Settings',
'utf8_invoices' => 'Cyrillic Support <sup>Beta</sup>',
'utf8_invoices' => 'New PDF Engine <sup>Beta</sup>',
'product_settings' => 'Product Settings',
'auto_wrap' => 'Auto Line Wrap',
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
@ -718,6 +718,20 @@ return array(
'add_to_invoice' => 'Add to invoice :invoice',
'create_new_invoice' => 'Create new invoice',
'task_errors' => 'Please correct any overlapping times',
'from' => 'From',
'to' => 'To',
'font_size' => 'Font Size',
'primary_color' => 'Primary Color',
'secondary_color' => 'Secondary Color',
'customize_design' => 'Customize Design',
'content' => 'Content',
'styles' => 'Styles',
'defaults' => 'Defaults',
'margins' => 'Margins',
'header' => 'Header',
'footer' => 'Footer',
'custom' => 'Custom',
);

View File

@ -596,7 +596,7 @@ return array(
'less_fields' => 'Less Fields',
'client_name' => 'Client Name',
'pdf_settings' => 'PDF Settings',
'utf8_invoices' => 'Cyrillic Support <sup>Beta</sup>',
'utf8_invoices' => 'New PDF Engine <sup>Beta</sup>',
'product_settings' => 'Product Settings',
'auto_wrap' => 'Auto Line Wrap',
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
@ -721,6 +721,20 @@ return array(
'add_to_invoice' => 'Add to invoice :invoice',
'create_new_invoice' => 'Create new invoice',
'task_errors' => 'Please correct any overlapping times',
'from' => 'From',
'to' => 'To',
'font_size' => 'Font Size',
'primary_color' => 'Primary Color',
'secondary_color' => 'Secondary Color',
'customize_design' => 'Customize Design',
'content' => 'Content',
'styles' => 'Styles',
'defaults' => 'Defaults',
'margins' => 'Margins',
'header' => 'Header',
'footer' => 'Footer',
'custom' => 'Custom',

View File

@ -0,0 +1,175 @@
@extends('accounts.nav')
@section('head')
@parent
<script src="{{ asset('js/pdf_viewer.js') }}" type="text/javascript"></script>
<script src="{{ asset('js/compatibility.js') }}" type="text/javascript"></script>
<link href="{{ asset('css/jsoneditor.min.css') }}" rel="stylesheet" type="text/css">
<script src="{{ asset('js/jsoneditor.min.js') }}" type="text/javascript"></script>
<script src="{{ asset('js/pdfmake.min.js') }}" type="text/javascript"></script>
<script src="{{ asset('js/vfs_fonts.js') }}" type="text/javascript"></script>
<style type="text/css">
select.form-control {
background: #FFFFFF !important;
margin-right: 12px;
}
table {
background: #FFFFFF !important;
}
</style>
@stop
@section('content')
@parent
@include('accounts.nav_advanced')
<script>
var invoiceDesigns = {!! $invoiceDesigns !!};
var invoice = {!! json_encode($invoice) !!};
var sections = ['content', 'styles', 'defaultStyle', 'pageMargins', 'header', 'footer'];
var customDesign = origCustomDesign = {!! $customDesign !!};
function getPDFString(cb, force) {
invoice.is_pro = {!! Auth::user()->isPro() ? 'true' : 'false' !!};
invoice.account.hide_quantity = {!! Auth::user()->account->hide_quantity ? 'true' : 'false' !!};
invoice.account.hide_paid_to_date = {!! Auth::user()->account->hide_paid_to_date ? 'true' : 'false' !!};
invoice.invoice_design_id = {!! Auth::user()->account->invoice_design_id !!};
NINJA.primaryColor = '{!! Auth::user()->account->primary_color !!}';
NINJA.secondaryColor = '{!! Auth::user()->account->secondary_color !!}';
NINJA.fontSize = {!! Auth::user()->account->font_size !!};
generatePDF(invoice, getDesignJavascript(), force, cb);
}
function getDesignJavascript() {
var id = $('#invoice_design_id').val();
if (id == '-1') {
showMoreDesigns();
$('#invoice_design_id').val(1);
return invoiceDesigns[0].javascript;
} else {
return JSON.stringify(customDesign);
}
}
function loadEditor(section)
{
editorSection = section;
editor.set(customDesign[section]);
editor.expandAll();
}
function saveEditor(data)
{
setTimeout(function() {
customDesign[editorSection] = editor.get();
refreshPDF();
}, 100)
}
function onSelectChange()
{
var id = $('#invoice_design_id').val();
if (parseInt(id)) {
customDesign = JSON.parse(invoiceDesigns[id-1].javascript);
} else {
customDesign = origCustomDesign;
}
loadEditor(editorSection);
refreshPDF(true);
}
function submitForm()
{
$('#custom_design').val(JSON.stringify(customDesign));
$('form.warn-on-exit').submit();
}
$(function() {
refreshPDF(true);
var container = document.getElementById("jsoneditor");
var options = {
mode: 'form',
modes: ['form', 'code'],
error: function (err) {
console.error(err.toString());
},
change: function() {
saveEditor();
}
};
window.editor = new JSONEditor(container, options);
loadEditor('content');
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
var target = $(e.target).attr("href") // activated tab
target = target.substring(1); // strip leading #
loadEditor(target);
});
});
</script>
<div class="row">
<div class="col-md-6">
{!! Former::open()->addClass('warn-on-exit')->onchange('refreshPDF()') !!}
{!! Former::populateField('invoice_design_id', $account->invoice_design_id) !!}
<div style="display:none">
{!! Former::text('custom_design') !!}
</div>
<div role="tabpanel">
<ul class="nav nav-tabs" role="tablist" style="border: none">
<li role="presentation" class="active"><a href="#content" aria-controls="content" role="tab" data-toggle="tab">{{ trans('texts.content') }}</a></li>
<li role="presentation"><a href="#styles" aria-controls="styles" role="tab" data-toggle="tab">{{ trans('texts.styles') }}</a></li>
<li role="presentation"><a href="#defaultStyle" aria-controls="defaultStyle" role="tab" data-toggle="tab">{{ trans('texts.defaults') }}</a></li>
<li role="presentation"><a href="#pageMargins" aria-controls="margins" role="tab" data-toggle="tab">{{ trans('texts.margins') }}</a></li>
<li role="presentation"><a href="#header" aria-controls="header" role="tab" data-toggle="tab">{{ trans('texts.header') }}</a></li>
<li role="presentation"><a href="#footer" aria-controls="footer" role="tab" data-toggle="tab">{{ trans('texts.footer') }}</a></li>
</ul>
</div>
<div id="jsoneditor" style="width: 550px; height: 743px;"></div>
<p>&nbsp;</p>
{!! Former::actions(
Former::select('invoice_design_id')->style('display:inline;width:120px')->fromQuery($invoiceDesigns, 'name', 'id')->onchange('onSelectChange()')->raw(),
Button::success(trans('texts.save'))->withAttributes(['onclick' => 'submitForm()'])->large()->appendIcon(Icon::create('floppy-disk'))
) !!}
@if (!Auth::user()->isPro())
<script>
$(function() {
$('form.warn-on-exit input').prop('disabled', true);
});
</script>
@endif
{!! Former::close() !!}
</div>
<div class="col-md-6">
@include('invoices.pdf', ['account' => Auth::user()->account, 'pdfHeight' => 800])
</div>
</div>
@stop

View File

@ -28,7 +28,8 @@
$('#invoice_design_id').val(1);
return invoiceDesigns[0].javascript;
} else {
return invoiceDesigns[id-1].javascript;
var design = _.find(invoiceDesigns, function(design){ return design.id == id});
return design ? design.javascript : '';
}
}
@ -55,8 +56,7 @@
}
}
doc = generatePDF(invoice, getDesignJavascript(), true);
doc.getDataUrl(cb);
generatePDF(invoice, getDesignJavascript(), true, cb);
}
$(function() {
@ -109,6 +109,10 @@
{!! Former::text('primary_color') !!}
{!! Former::text('secondary_color') !!}
{!! Former::actions(
Button::primary(trans('texts.customize_design'))->small()->asLinkTo(URL::to('/company/advanced_settings/customize_design'))
) !!}
</div>
</div>

View File

@ -8,7 +8,7 @@
{!! HTML::nav_link('company/products', 'product_library') !!}
{!! HTML::nav_link('company/notifications', 'notifications') !!}
{!! HTML::nav_link('company/import_export', 'import_export', 'company/import_map') !!}
{!! HTML::nav_link('company/advanced_settings/invoice_settings', 'advanced_settings', '*/advanced_settings/*') !!}
{!! HTML::nav_link('company/advanced_settings/invoice_design', 'advanced_settings', '*/advanced_settings/*') !!}
</ul>
<br/>

View File

@ -1,6 +1,6 @@
<ul class="nav nav-tabs nav nav-justified">
{!! HTML::nav_link('company/advanced_settings/invoice_settings', 'invoice_settings') !!}
{!! HTML::nav_link('company/advanced_settings/invoice_design', 'invoice_design') !!}
{!! HTML::nav_link('company/advanced_settings/invoice_settings', 'invoice_settings') !!}
{!! HTML::nav_link('company/advanced_settings/email_templates', 'email_templates') !!}
{!! HTML::nav_link('company/advanced_settings/charts_and_reports', 'charts_and_reports') !!}
{!! HTML::nav_link('company/advanced_settings/user_management', 'users_and_tokens') !!}

View File

@ -446,7 +446,7 @@
<li>{!! link_to('company/products', uctrans('texts.product_library')) !!}</li>
<li>{!! link_to('company/notifications', uctrans('texts.notifications')) !!}</li>
<li>{!! link_to('company/import_export', uctrans('texts.import_export')) !!}</li>
<li><a href="{{ url('company/advanced_settings/invoice_settings') }}">{!! uctrans('texts.advanced_settings') . Utils::getProLabel(ACCOUNT_ADVANCED_SETTINGS) !!}</a></li>
<li><a href="{{ url('company/advanced_settings/invoice_design') }}">{!! uctrans('texts.advanced_settings') . Utils::getProLabel(ACCOUNT_ADVANCED_SETTINGS) !!}</a></li>
</ul>
</li>
</ul>

View File

@ -67,7 +67,7 @@
<div data-bind="with: client">
<div style="display:none" class="form-group" data-bind="visible: contacts().length > 0 &amp;&amp; (contacts()[0].email() || contacts()[0].first_name()), foreach: contacts">
<div class="col-lg-8 col-lg-offset-4">
<label class="checkbox" data-bind="attr: {for: $index() + '_check'}" onclick="refreshPDF()">
<label class="checkbox" data-bind="attr: {for: $index() + '_check'}" onclick="refreshPDF(true)">
<input type="checkbox" value="1" data-bind="checked: send_invoice, attr: {id: $index() + '_check'}">
<span data-bind="html: email.display"/>
</label>
@ -325,9 +325,9 @@
@if (!Utils::isPro() || \App\Models\InvoiceDesign::count() == COUNT_FREE_DESIGNS)
{!! Former::select('invoice_design_id')->style('display:'.($account->utf8_invoices ? 'none' : 'inline').';width:150px;background-color:white !important')->raw()->fromQuery($invoiceDesigns, 'name', 'id')->data_bind("value: invoice_design_id")->addOption(trans('texts.more_designs') . '...', '-1') !!}
{!! Former::select('invoice_design_id')->style('display:inline;width:150px;background-color:white !important')->raw()->fromQuery($invoiceDesigns, 'name', 'id')->data_bind("value: invoice_design_id")->addOption(trans('texts.more_designs') . '...', '-1') !!}
@else
{!! Former::select('invoice_design_id')->style('display:'.($account->utf8_invoices ? 'none' : 'inline').';width:150px;background-color:white !important')->raw()->fromQuery($invoiceDesigns, 'name', 'id')->data_bind("value: invoice_design_id") !!}
{!! Former::select('invoice_design_id')->style('display:inline;width:150px;background-color:white !important')->raw()->fromQuery($invoiceDesigns, 'name', 'id')->data_bind("value: invoice_design_id") !!}
@endif
{!! Button::primary(trans('texts.download_pdf'))->withAttributes(array('onclick' => 'onDownloadClick()'))->appendIcon(Icon::create('download-alt')) !!}
@ -485,10 +485,10 @@
<tr data-bind="event: { mouseover: showActions, mouseout: hideActions }">
<td style="width:30px" class="hide-border"></td>
<td style="width:60px">
<input onkeyup="onTaxRateChange()" data-bind="value: name, valueUpdate: 'afterkeydown'" class="form-control" onchange="refreshPDF()"//>
<input onkeyup="onTaxRateChange()" data-bind="value: name, valueUpdate: 'afterkeydown'" class="form-control" onchange="refreshPDF(true)"//>
</td>
<td style="width:60px">
<input onkeyup="onTaxRateChange()" data-bind="value: prettyRate, valueUpdate: 'afterkeydown'" style="text-align: right" class="form-control" onchange="refreshPDF()"//>
<input onkeyup="onTaxRateChange()" data-bind="value: prettyRate, valueUpdate: 'afterkeydown'" style="text-align: right" class="form-control" onchange="refreshPDF(true)"//>
</td>
<td style="width:30px; cursor:pointer" class="hide-border td-icon">
&nbsp;<i style="width:12px;" data-bind="click: $root.removeTaxRate, visible: actionsVisible() &amp;&amp; !isEmpty()" class="fa fa-minus-circle redlink" title="Remove item"/>
@ -589,7 +589,7 @@
model.loadClient($.parseJSON(ko.toJSON(new ClientModel())));
model.invoice().client().country = false;
}
refreshPDF();
refreshPDF(true);
});
// If no clients exists show the client form when clicking on the client select input
@ -601,7 +601,7 @@
$('#invoice_footer, #terms, #public_notes, #invoice_number, #invoice_date, #due_date, #po_number, #discount, #currency_id, #invoice_design_id, #recurring, #is_amount_discount, #partial').change(function() {
setTimeout(function() {
refreshPDF();
refreshPDF(true);
}, 1);
});
@ -616,7 +616,7 @@
}).on('hidden.bs.modal', function () {
if (model.clientBackup) {
model.loadClient(model.clientBackup);
refreshPDF();
refreshPDF(true);
}
})
@ -639,7 +639,7 @@
@if ($client)
$input.trigger('change');
@else
refreshPDF();
refreshPDF(true);
@endif
var client = model.invoice().client();
@ -655,7 +655,7 @@
function applyComboboxListeners() {
var selectorStr = '.invoice-table input, .invoice-table select, .invoice-table textarea';
$(selectorStr).off('blur').on('blur', function() {
refreshPDF();
refreshPDF(true);
});
$('textarea').on('keyup focus', function(e) {
@ -711,14 +711,11 @@
return invoice;
}
function getPDFString(cb) {
function getPDFString(cb, force) {
var invoice = createInvoiceModel();
var design = getDesignJavascript();
if (!design) return;
doc = generatePDF(invoice, design, false);
if (!doc) return;
//return doc.output('datauristring');
doc.getDataUrl(cb);
generatePDF(invoice, design, force, cb);
}
function getDesignJavascript() {
@ -728,7 +725,8 @@
model.invoice().invoice_design_id(1);
return invoiceDesigns[0].javascript;
} else {
return invoiceDesigns[id-1].javascript;
var design = _.find(invoiceDesigns, function(design){ return design.id == id});
return design ? design.javascript : '';
}
}
@ -1091,7 +1089,7 @@
$('#emailError').css( "display", "none" );
//$('.client_select input.form-control').focus();
refreshPDF();
refreshPDF(true);
model.clientBackup = false;
$('#clientModal').modal('hide');
}
@ -1143,7 +1141,7 @@
self.invoice_items = ko.observableArray();
self.amount = ko.observable(0);
self.balance = ko.observable(0);
self.invoice_design_id = ko.observable({{ $account->utf8_invoices ? 1 : $account->invoice_design_id }});
self.invoice_design_id = ko.observable({{ $account->invoice_design_id }});
self.partial = ko.observable(0);
self.has_tasks = ko.observable(false);
@ -1252,7 +1250,7 @@
self.removeItem = function(item) {
self.invoice_items.remove(item);
refreshPDF();
refreshPDF(true);
}
@ -1368,7 +1366,7 @@
});
self.onDragged = function(item) {
refreshPDF();
refreshPDF(true);
}
}

View File

@ -37,8 +37,7 @@
invoiceDesign = invoiceDesigns[0];
}
doc = generatePDF(invoice, invoiceDesign.javascript, true);
doc.getDataUrl(cb);
generatePDF(invoice, invoiceDesign.javascript, true, cb);
}
$(function() {

View File

@ -63,12 +63,11 @@
logoImages.imageLogoHeight3 = 81/2;
@if (file_exists($account->getLogoPath()))
window.accountLogo = "{{ HTML::image_data($account->getLogoPath()) }}";
if (window.invoice) {
invoice.image = "{{ HTML::image_data($account->getLogoPath()) }}";
invoice.image = window.accountLogo;
invoice.imageWidth = {{ $account->getLogoWidth() }};
invoice.imageHeight = {{ $account->getLogoHeight() }};
} else {
window.accountLogo = "{{ HTML::image_data($account->getLogoPath()) }}";
}
@endif
@ -87,8 +86,8 @@
var isRefreshing = false;
var needsRefresh = false;
function refreshPDF() {
getPDFString(refreshPDFCB);
function refreshPDF(force) {
getPDFString(refreshPDFCB, force);
}
function refreshPDFCB(string) {

View File

@ -53,8 +53,7 @@
invoice.contact = {!! $contact->toJson() !!};
function getPDFString(cb) {
doc = generatePDF(invoice, invoice.invoice_design.javascript);
doc.getDataUrl(cb);
generatePDF(invoice, invoice.invoice_design.javascript, true, cb);
}
$(function() {