1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-09 20:52:56 +01:00

API improvements

This commit is contained in:
Hillel Coren 2015-09-07 12:07:55 +03:00
parent 79aa5bad92
commit 3fdad48179
56 changed files with 784 additions and 221 deletions

View File

@ -388,6 +388,7 @@ class AccountController extends BaseController
$account->primary_color = Input::get('primary_color');
$account->secondary_color = Input::get('secondary_color');
$account->invoice_design_id = Input::get('invoice_design_id');
if (Input::has('font_size')) {
$account->font_size = intval(Input::get('font_size'));
}

View File

@ -74,7 +74,7 @@ class DashboardController extends BaseController
->where('clients.deleted_at', '=', null)
->where('contacts.deleted_at', '=', null)
->where('invoices.is_recurring', '=', false)
->where('invoices.is_quote', '=', false)
//->where('invoices.is_quote', '=', false)
->where('invoices.balance', '>', 0)
->where('invoices.is_deleted', '=', false)
->where('contacts.is_primary', '=', true)
@ -91,7 +91,7 @@ class DashboardController extends BaseController
->where('clients.deleted_at', '=', null)
->where('contacts.deleted_at', '=', null)
->where('invoices.is_recurring', '=', false)
->where('invoices.is_quote', '=', false)
//->where('invoices.is_quote', '=', false)
->where('invoices.balance', '>', 0)
->where('invoices.is_deleted', '=', false)
->where('contacts.is_primary', '=', true)

View File

@ -53,7 +53,7 @@ class HomeController extends BaseController
$redirectTo = Input::get('redirect_to', 'invoices/create');
return Redirect::to($redirectTo)->with('sign_up', Input::get('sign_up'));
} else {
return View::make('public.header', ['invoiceNow' => true]);
return View::make('public.invoice_now');
}
}

View File

@ -24,13 +24,19 @@ class InvoiceApiController extends Controller
$this->mailer = $mailer;
}
public function index()
public function index($clientPublicId = false)
{
$invoices = Invoice::scope()
->with('client', 'invitations.account')
->where('invoices.is_quote', '=', false)
->orderBy('created_at', 'desc')
->get();
->where('invoices.is_quote', '=', false);
if ($clientPublicId) {
$invoices->whereHas('client', function($query) use ($clientPublicId) {
$query->where('public_id', '=', $clientPublicId);
});
}
$invoices = $invoices->orderBy('created_at', 'desc')->get();
// Add the first invitation link to the data
foreach ($invoices as $key => $invoice) {

View File

@ -246,8 +246,13 @@ class InvoiceController extends BaseController
$paymentURL = $paymentTypes[0]['url'];
}
$showApprove = $invoice->quote_invoice_id ? false : true;
if ($invoice->due_date) {
$showApprove = time() < strtotime($invoice->due_date);
}
$data = array(
'isConverted' => $invoice->quote_invoice_id ? true : false,
'showApprove' => $showApprove,
'showBreadcrumbs' => false,
'hideLogo' => $account->isWhiteLabel(),
'invoice' => $invoice->hidePrivateFields(),
@ -472,10 +477,12 @@ class InvoiceController extends BaseController
$account = Auth::user()->account;
if ($account->invoice_taxes != $input->invoice_taxes
|| $account->invoice_item_taxes != $input->invoice_item_taxes
|| $account->invoice_design_id != $input->invoice->invoice_design_id) {
|| $account->invoice_design_id != $input->invoice->invoice_design_id
|| $account->show_item_taxes != $input->show_item_taxes) {
$account->invoice_taxes = $input->invoice_taxes;
$account->invoice_item_taxes = $input->invoice_item_taxes;
$account->invoice_design_id = $input->invoice->invoice_design_id;
$account->show_item_taxes = $input->show_item_taxes;
$account->save();
}

View File

@ -16,12 +16,18 @@ class PaymentApiController extends Controller
$this->paymentRepo = $paymentRepo;
}
public function index()
public function index($clientPublicId = false)
{
$payments = Payment::scope()
->with('client', 'contact', 'invitation', 'user', 'invoice')
->orderBy('created_at', 'desc')
->get();
->with('client', 'contact', 'invitation', 'user', 'invoice');
if ($clientPublicId) {
$payments->whereHas('client', function($query) use ($clientPublicId) {
$query->where('public_id', '=', $clientPublicId);
});
}
$payments = $payments->orderBy('created_at', 'desc')->get();
$payments = Utils::remapPublicIds($payments);
$response = json_encode($payments, JSON_PRETTY_PRINT);

View File

@ -447,7 +447,7 @@ class PaymentController extends BaseController
if (!$response->isSuccessful()) {
Session::flash('error', $response->getMessage());
Utils::logError($response->getMessage());
Utils::logError('Payment Error [license]: ' . $response->getMessage());
return Redirect::to('license')->withInput();
}
@ -484,7 +484,7 @@ class PaymentController extends BaseController
} catch (\Exception $e) {
$errorMessage = trans('texts.payment_error');
Session::flash('error', $errorMessage);
Utils::logError(Utils::getErrorString($e));
Utils::logError('Payment Error [license-uncaught]: ' . Utils::getErrorString($e));
return Redirect::to('license')->withInput();
}
@ -543,7 +543,7 @@ class PaymentController extends BaseController
$validator = Validator::make(Input::all(), $rules);
if ($validator->fails()) {
Utils::logError('Payment Error [invalid]');
//Utils::logError('Payment Error [invalid]');
return Redirect::to('payment/'.$invitationKey)
->withErrors($validator)
->withInput();
@ -711,7 +711,7 @@ class PaymentController extends BaseController
if ($accountGateway->isGateway(GATEWAY_DWOLLA) && Input::get('error')) {
$errorMessage = trans('texts.payment_error')."\n\n".Input::get('error_description');
Session::flash('error', $errorMessage);
Utils::logError($errorMessage);
Utils::logError('Payment Error [dwolla]: ' . $errorMessage);
return Redirect::to('view/'.$invitation->invitation_key);
}
@ -729,7 +729,7 @@ class PaymentController extends BaseController
} else {
$errorMessage = trans('texts.payment_error')."\n\n".$response->getMessage();
Session::flash('error', $errorMessage);
Utils::logError($errorMessage);
Utils::logError('Payment Error [offsite]: ' . $errorMessage);
return Redirect::to('view/'.$invitation->invitation_key);
}
@ -742,7 +742,7 @@ class PaymentController extends BaseController
} catch (\Exception $e) {
$errorMessage = trans('texts.payment_error');
Session::flash('error', $errorMessage);
Utils::logError($errorMessage."\n\n".$e->getMessage());
Utils::logError('Payment Error [offsite-uncaught]: ' . $errorMessage."\n\n".$e->getMessage());
return Redirect::to('view/'.$invitation->invitation_key);
}

View File

@ -14,13 +14,19 @@ class QuoteApiController extends Controller
$this->invoiceRepo = $invoiceRepo;
}
public function index()
public function index($clientPublicId = false)
{
$invoices = Invoice::scope()
->with('client', 'user')
->where('invoices.is_quote', '=', true)
->orderBy('created_at', 'desc')
->get();
->where('invoices.is_quote', '=', true);
if ($clientPublicId) {
$invoices->whereHas('client', function($query) use ($clientPublicId) {
$query->where('public_id', '=', $clientPublicId);
});
}
$invoices = $invoices->orderBy('created_at', 'desc')->get();
$invoices = Utils::remapPublicIds($invoices);
$response = json_encode($invoices, JSON_PRETTY_PRINT);

View File

@ -53,7 +53,7 @@ class QuoteController extends BaseController
$data = [
'title' => trans('texts.quotes'),
'entityType' => ENTITY_QUOTE,
'columns' => Utils::trans(['checkbox', 'quote_number', 'client', 'quote_date', 'quote_total', 'due_date', 'status', 'action']),
'columns' => Utils::trans(['checkbox', 'quote_number', 'client', 'quote_date', 'quote_total', 'valid_until', 'status', 'action']),
];
/*

View File

@ -0,0 +1,56 @@
<?php namespace App\Http\Controllers;
use Utils;
use Response;
use Input;
use App\Models\Task;
use App\Ninja\Repositories\TaskRepository;
class TaskApiController extends Controller
{
protected $taskRepo;
public function __construct(TaskRepository $taskRepo)
{
$this->taskRepo = $taskRepo;
}
public function index($clientPublicId = false)
{
$tasks = Task::scope()->with('client');
if ($clientPublicId) {
$tasks->whereHas('client', function($query) use ($clientPublicId) {
$query->where('public_id', '=', $clientPublicId);
});
}
$tasks = $tasks->orderBy('created_at', 'desc')->get();
$tasks = Utils::remapPublicIds($tasks);
$response = json_encode($tasks, JSON_PRETTY_PRINT);
$headers = Utils::getApiHeaders(count($tasks));
return Response::make($response, 200, $headers);
}
public function store()
{
$data = Input::all();
$taskId = isset($data['id']) ? $data['id'] : false;
if (isset($data['client_id']) && $data['client_id']) {
$data['client'] = $data['client_id'];
}
$task = $this->taskRepo->save($taskId, $data);
$task = Task::scope($task->public_id)->with('client')->first();
$task = Utils::remapPublicIds([$task]);
$response = json_encode($task, JSON_PRETTY_PRINT);
$headers = Utils::getApiHeaders();
return Response::make($response, 200, $headers);
}
}

View File

@ -155,7 +155,7 @@ class TaskController extends BaseController
if ($task->invoice) {
$actions[] = ['url' => URL::to("inovices/{$task->invoice->public_id}/edit"), 'label' => trans("texts.view_invoice")];
} else {
$actions[] = ['url' => 'javascript:submitAction("invoice")', 'label' => trans("texts.create_invoice")];
$actions[] = ['url' => 'javascript:submitAction("invoice")', 'label' => trans("texts.invoice_task")];
// check for any open invoices
$invoices = $task->client_id ? $this->invoiceRepo->findOpenInvoices($task->client_id) : [];

View File

@ -11,6 +11,7 @@ class VerifyCsrfToken extends BaseVerifier {
'api/v1/invoices',
'api/v1/quotes',
'api/v1/payments',
'api/v1/tasks',
'api/v1/email_invoice',
'api/v1/hooks',
];

View File

@ -182,9 +182,14 @@ Route::group(['middleware' => 'api', 'prefix' => 'api/v1'], function()
{
Route::resource('ping', 'ClientApiController@ping');
Route::resource('clients', 'ClientApiController');
Route::resource('invoices', 'InvoiceApiController');
Route::get('quotes/{client_id?}', 'QuoteApiController@index');
Route::resource('quotes', 'QuoteApiController');
Route::get('invoices/{client_id?}', 'InvoiceApiController@index');
Route::resource('invoices', 'InvoiceApiController');
Route::get('payments/{client_id?}', 'PaymentApiController@index');
Route::resource('payments', 'PaymentApiController');
Route::get('tasks/{client_id?}', 'TaskApiController@index');
Route::resource('tasks', 'TaskApiController');
Route::post('hooks', 'IntegrationController@subscribe');
Route::post('email_invoice', 'InvoiceApiController@emailInvoice');
});

View File

@ -16,7 +16,7 @@ class Account extends Eloquent
/*
protected $casts = [
'hide_quantity' => 'boolean',
'invoice_settings' => 'object',
];
*/
@ -282,6 +282,7 @@ class Account extends Eloquent
'invoice_to',
'details',
'invoice_no',
'valid_until',
];
foreach ($fields as $field) {
@ -394,11 +395,8 @@ class Account extends Eloquent
}
$template = "\$client,<p/>\r\n\r\n" .
trans("texts.{$entityType}_message", ['amount' => '$amount']) . "<p/>\r\n\r\n";
if ($entityType != ENTITY_PAYMENT) {
$template .= "<a href=\"\$link\">\$link</a><p/>\r\n\r\n";
}
trans("texts.{$entityType}_message", ['amount' => '$amount']) . "<p/>\r\n\r\n" .
"<a href=\"\$link\">\$link</a><p/>\r\n\r\n";
if ($message) {
$template .= "$message<p/>\r\n\r\n";

View File

@ -6,7 +6,7 @@ class Country extends Eloquent
{
public $timestamps = false;
protected $visible = ['id', 'name'];
protected $visible = ['id', 'name', 'swap_postal_code'];
public function getName()
{

View File

@ -184,6 +184,7 @@ class Invoice extends EntityModel
'custom_invoice_label1',
'custom_invoice_label2',
'pdf_email_attachment',
'show_item_taxes',
]);
foreach ($this->invoice_items as $invoiceItem) {

View File

@ -92,16 +92,20 @@ class ContactMailer extends Mailer
'$amount' => Utils::formatMoney($payment->amount, $payment->client->getCurrencyId())
];
$data = ['body' => str_replace(array_keys($variables), array_values($variables), $emailTemplate)];
if ($payment->invitation) {
$user = $payment->invitation->user;
$contact = $payment->contact;
$variables['$link'] = $payment->invitation->getLink();
} else {
$user = $payment->user;
$contact = $payment->client->contacts[0];
$variables['$link'] = $payment->invoice->invitations[0]->getLink();
}
$data = ['body' => str_replace(array_keys($variables), array_values($variables), $emailTemplate)];
//$data['invoice_id'] = $payment->invoice->id;
if ($user->email && $contact->email) {
$this->sendTo($contact->email, $user->email, $accountName, $subject, $view, $data);
}

View File

@ -190,7 +190,7 @@ class InvoiceRepository
}
private function getStatusLabel($statusId, $statusName) {
$label = trans("texts.{$statusName}");
$label = trans("texts.status_" . strtolower($statusName));
$class = 'default';
switch ($statusId) {
case INVOICE_STATUS_SENT:
@ -206,7 +206,7 @@ class InvoiceRepository
$class = 'success';
break;
}
return "<h4><div class=\"label label-{$class}\">$statusName</div></h4>";
return "<h4><div class=\"label label-{$class}\">$label</div></h4>";
}
public function getErrors($input)

View File

@ -68,6 +68,7 @@ class TaskRepository
$timeLog = [];
}
if (isset($data['action'])) {
if ($data['action'] == 'start') {
$task->is_running = true;
$timeLog[] = [strtotime('now'), false];
@ -78,6 +79,7 @@ class TaskRepository
$timeLog[count($timeLog)-1][1] = time();
$task->is_running = false;
}
}
$task->time_log = json_encode($timeLog);
$task->save();

View File

@ -0,0 +1,38 @@
<?php
use Illuminate\Database\Migrations\Migration;
class AddSwapPostalCode extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('countries', function ($table) {
$table->boolean('swap_postal_code')->default(0);
});
Schema::table('accounts', function ($table) {
$table->boolean('show_item_taxes')->default(0);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('countries', function ($table) {
$table->dropColumn('swap_postal_code');
});
Schema::table('accounts', function ($table) {
$table->dropColumn('show_item_taxes');
});
}
}

View File

@ -6,6 +6,7 @@ use App\Models\Currency;
use App\Models\DateFormat;
use App\Models\DatetimeFormat;
use App\Models\InvoiceDesign;
use App\Models\Country;
class PaymentLibrariesSeeder extends Seeder
{
@ -18,6 +19,7 @@ class PaymentLibrariesSeeder extends Seeder
$this->createDateFormats();
$this->createDatetimeFormats();
$this->createInvoiceDesigns();
$this->updateSwapPostalCode();
}
private function createGateways() {
@ -224,4 +226,38 @@ class PaymentLibrariesSeeder extends Seeder
}
}
private function updateSwapPostalCode() {
// Source: http://www.bitboost.com/ref/international-address-formats.html
$countries = [
'AR',
'AT',
'CH',
'BE',
'DE',
'DK',
'ES',
'FI',
'FR',
'GL',
'IL',
'IS',
'IT',
'LU',
'MY',
'MX',
'NL',
'PL',
'PT',
'SE',
'UY',
];
for ($i=0; $i<count($countries); $i++) {
$code = $countries[$i];
$country = Country::where('iso_3166_2', '=', $code)->first();
$country->swap_postal_code = true;
$country->save();
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -30685,6 +30685,21 @@ function displaySubtotals(doc, layout, invoice, y, rightAlignTitleX)
return displayGrid(doc, invoice, data, 300, y, layout, options) + 10;
}
function formatAddress(city, state, zip, swap) {
var str = '';
if (swap) {
str += zip ? zip + ' ' : '';
str += city ? city : '';
str += (city && state) ? ', ' : (city ? ' ' : '');
str += state;
} else {
str += city ? city : '';
str += (city && state) ? ', ' : (state ? ' ' : '');
str += state + ' ' + zip;
}
return str;
}
function concatStrings() {
var concatStr = '';
var data = [];
@ -31613,15 +31628,16 @@ NINJA.decodeJavascript = function(invoice, javascript)
'accountDetails': NINJA.accountDetails(invoice),
'accountAddress': NINJA.accountAddress(invoice),
'invoiceDetails': NINJA.invoiceDetails(invoice),
'invoiceDetailsHeight': NINJA.invoiceDetails(invoice).length * 22,
'invoiceDetailsHeight': (NINJA.invoiceDetails(invoice).length * 16) + 16,
'invoiceLineItems': NINJA.invoiceLines(invoice),
'invoiceLineItemColumns': NINJA.invoiceColumns(invoice),
'quantityWidth': NINJA.quantityWidth(invoice),
'clientDetails': NINJA.clientDetails(invoice),
'notesAndTerms': NINJA.notesAndTerms(invoice),
'subtotals': NINJA.subtotals(invoice),
'subtotalsHeight': NINJA.subtotals(invoice).length * 22,
'subtotalsHeight': (NINJA.subtotals(invoice).length * 16) + 16,
'subtotalsWithoutBalance': NINJA.subtotals(invoice, true),
'subtotalsBalance': NINJA.subtotalsBalance(invoice),
'balanceDue': formatMoney(invoice.balance_amount, invoice.client.currency_id),
'invoiceFooter': invoice.invoice_footer || ' ',
'invoiceNumber': invoice.invoice_number || ' ',
@ -31715,16 +31731,24 @@ NINJA.notesAndTerms = function(invoice)
NINJA.invoiceColumns = function(invoice)
{
if (invoice.account.hide_quantity == '1') {
return ["15%", "*", "15%", "15%"];
} else {
return ["15%", "*", "14%", "14%", "14%"];
var account = invoice.account;
var columns = ["15%", "*"];
var count = 3;
if (account.hide_quantity == '1') {
count--;
}
if (account.show_item_taxes == '1') {
count++;
}
for (var i=0; i<count; i++) {
columns.push("14%");
}
return columns;
}
NINJA.quantityWidth = function(invoice)
{
return invoice.account.hide_quantity == '1' ? '' : '"12%", ';
return invoice.account.hide_quantity == '1' ? '' : '"14%", ';
}
NINJA.invoiceLines = function(invoice) {
@ -31732,6 +31756,7 @@ NINJA.invoiceLines = function(invoice) {
var shownItem = false;
var currencyId = invoice && invoice.client ? invoice.client.currency_id : 1;
var hideQuantity = invoice.account.hide_quantity == '1';
var showItemTaxes = invoice.account.show_item_taxes == '1';
var grid = [[
{text: invoiceLabels.item, style: ['tableHeader', 'itemTableHeader']},
@ -31742,6 +31767,9 @@ NINJA.invoiceLines = function(invoice) {
if (!hideQuantity) {
grid[0].push({text: invoiceLabels.quantity, style: ['tableHeader', 'qtyTableHeader']});
}
if (showItemTaxes) {
grid[0].push({text: invoiceLabels.tax, style: ['tableHeader', 'taxTableHeader']});
}
grid[0].push({text: invoiceLabels.line_total, style: ['tableHeader', 'lineTotalTableHeader']});
@ -31753,6 +31781,15 @@ NINJA.invoiceLines = function(invoice) {
var qty = NINJA.parseFloat(item.qty) ? roundToTwo(NINJA.parseFloat(item.qty)) + '' : '';
var notes = item.notes;
var productKey = item.product_key;
var tax = '';
if (showItemTaxes) {
if (item.tax && parseFloat(item.tax.rate)) {
tax = parseFloat(item.tax.rate);
} else if (item.tax_rate && parseFloat(item.tax_rate)) {
tax = parseFloat(item.tax_rate);
}
}
// show at most one blank line
if (shownItem && (!cost || cost == '0.00') && !notes && !productKey) {
@ -31768,6 +31805,10 @@ NINJA.invoiceLines = function(invoice) {
}
var lineTotal = roundToTwo(NINJA.parseFloat(item.cost)) * roundToTwo(NINJA.parseFloat(item.qty));
if (showItemTaxes && tax) {
tax = lineTotal * tax / 100;
lineTotal += tax;
}
lineTotal = formatMoney(lineTotal, currencyId);
rowStyle = (i % 2 == 0) ? 'odd' : 'even';
@ -31778,6 +31819,9 @@ NINJA.invoiceLines = function(invoice) {
if (!hideQuantity) {
row.push({style:["quantity", rowStyle], text:qty || ' '});
}
if (showItemTaxes) {
row.push({style:["tax", rowStyle], text:tax ? tax.toFixed(2) : ' '});
}
row.push({style:["lineTotal", rowStyle], text:lineTotal || ' '});
grid.push(row);
@ -31843,6 +31887,14 @@ NINJA.subtotals = function(invoice, hideBalance)
return NINJA.prepareDataPairs(data, 'subtotals');
}
NINJA.subtotalsBalance = function(invoice) {
var isPartial = NINJA.parseFloat(invoice.partial);
return [[
{text: isPartial ? invoiceLabels.amount_due : invoiceLabels.balance_due, style:['balanceDueLabel']},
{text: formatMoney(invoice.balance_amount, invoice.client.currency_id), style:['balanceDue']}
]];
}
NINJA.accountDetails = function(invoice) {
var account = invoice.account;
var data = [
@ -31859,9 +31911,9 @@ NINJA.accountAddress = function(invoice) {
var account = invoice.account;
var cityStatePostal = '';
if (account.city || account.state || account.postal_code) {
cityStatePostal = ((account.city ? account.city + ', ' : '') + account.state + ' ' + account.postal_code).trim();
var swap = account.country && account.country.swap_postal_code == '1';
cityStatePostal = formatAddress(account.city, account.state, account.postal_code, swap);
}
var data = [
{text: account.address1},
{text: account.address2},
@ -31870,7 +31922,6 @@ NINJA.accountAddress = function(invoice) {
{text: invoice.account.custom_value1 ? invoice.account.custom_label1 + ' ' + invoice.account.custom_value1 : false},
{text: invoice.account.custom_value2 ? invoice.account.custom_label2 + ' ' + invoice.account.custom_value2 : false}
];
return NINJA.prepareDataList(data, 'accountAddress');
}
@ -31890,7 +31941,7 @@ NINJA.invoiceDetails = function(invoice) {
{text: invoice.invoice_date}
],
[
{text: invoiceLabels.due_date},
{text: (invoice.is_quote ? invoiceLabels.valid_until : invoiceLabels.due_date)},
{text: invoice.due_date}
]
];
@ -31928,10 +31979,17 @@ NINJA.clientDetails = function(invoice) {
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 cityStatePostal = '';
if (client.city || client.state || client.postal_code) {
var swap = client.country && client.country.swap_postal_code == '1';
cityStatePostal = formatAddress(client.city, client.state, client.postal_code, swap);
}
data = [
{text:clientName || ' ', style: ['clientName']},
{text:client.address1},
{text:concatStrings(client.city, client.state, client.postal_code)},
{text:client.address2},
{text:cityStatePostal},
{text:client.country ? client.country.name : ''},
{text:clientEmail},
{text: invoice.client.custom_value1 ? invoice.account.custom_client_label1 + ' ' + invoice.client.custom_value1 : false},

View File

@ -88,15 +88,16 @@ NINJA.decodeJavascript = function(invoice, javascript)
'accountDetails': NINJA.accountDetails(invoice),
'accountAddress': NINJA.accountAddress(invoice),
'invoiceDetails': NINJA.invoiceDetails(invoice),
'invoiceDetailsHeight': NINJA.invoiceDetails(invoice).length * 22,
'invoiceDetailsHeight': (NINJA.invoiceDetails(invoice).length * 16) + 16,
'invoiceLineItems': NINJA.invoiceLines(invoice),
'invoiceLineItemColumns': NINJA.invoiceColumns(invoice),
'quantityWidth': NINJA.quantityWidth(invoice),
'clientDetails': NINJA.clientDetails(invoice),
'notesAndTerms': NINJA.notesAndTerms(invoice),
'subtotals': NINJA.subtotals(invoice),
'subtotalsHeight': NINJA.subtotals(invoice).length * 22,
'subtotalsHeight': (NINJA.subtotals(invoice).length * 16) + 16,
'subtotalsWithoutBalance': NINJA.subtotals(invoice, true),
'subtotalsBalance': NINJA.subtotalsBalance(invoice),
'balanceDue': formatMoney(invoice.balance_amount, invoice.client.currency_id),
'invoiceFooter': invoice.invoice_footer || ' ',
'invoiceNumber': invoice.invoice_number || ' ',
@ -190,16 +191,24 @@ NINJA.notesAndTerms = function(invoice)
NINJA.invoiceColumns = function(invoice)
{
if (invoice.account.hide_quantity == '1') {
return ["15%", "*", "15%", "15%"];
} else {
return ["15%", "*", "14%", "14%", "14%"];
var account = invoice.account;
var columns = ["15%", "*"];
var count = 3;
if (account.hide_quantity == '1') {
count--;
}
if (account.show_item_taxes == '1') {
count++;
}
for (var i=0; i<count; i++) {
columns.push("14%");
}
return columns;
}
NINJA.quantityWidth = function(invoice)
{
return invoice.account.hide_quantity == '1' ? '' : '"12%", ';
return invoice.account.hide_quantity == '1' ? '' : '"14%", ';
}
NINJA.invoiceLines = function(invoice) {
@ -207,6 +216,7 @@ NINJA.invoiceLines = function(invoice) {
var shownItem = false;
var currencyId = invoice && invoice.client ? invoice.client.currency_id : 1;
var hideQuantity = invoice.account.hide_quantity == '1';
var showItemTaxes = invoice.account.show_item_taxes == '1';
var grid = [[
{text: invoiceLabels.item, style: ['tableHeader', 'itemTableHeader']},
@ -217,6 +227,9 @@ NINJA.invoiceLines = function(invoice) {
if (!hideQuantity) {
grid[0].push({text: invoiceLabels.quantity, style: ['tableHeader', 'qtyTableHeader']});
}
if (showItemTaxes) {
grid[0].push({text: invoiceLabels.tax, style: ['tableHeader', 'taxTableHeader']});
}
grid[0].push({text: invoiceLabels.line_total, style: ['tableHeader', 'lineTotalTableHeader']});
@ -228,6 +241,15 @@ NINJA.invoiceLines = function(invoice) {
var qty = NINJA.parseFloat(item.qty) ? roundToTwo(NINJA.parseFloat(item.qty)) + '' : '';
var notes = item.notes;
var productKey = item.product_key;
var tax = '';
if (showItemTaxes) {
if (item.tax && parseFloat(item.tax.rate)) {
tax = parseFloat(item.tax.rate);
} else if (item.tax_rate && parseFloat(item.tax_rate)) {
tax = parseFloat(item.tax_rate);
}
}
// show at most one blank line
if (shownItem && (!cost || cost == '0.00') && !notes && !productKey) {
@ -243,6 +265,10 @@ NINJA.invoiceLines = function(invoice) {
}
var lineTotal = roundToTwo(NINJA.parseFloat(item.cost)) * roundToTwo(NINJA.parseFloat(item.qty));
if (showItemTaxes && tax) {
tax = lineTotal * tax / 100;
lineTotal += tax;
}
lineTotal = formatMoney(lineTotal, currencyId);
rowStyle = (i % 2 == 0) ? 'odd' : 'even';
@ -253,6 +279,9 @@ NINJA.invoiceLines = function(invoice) {
if (!hideQuantity) {
row.push({style:["quantity", rowStyle], text:qty || ' '});
}
if (showItemTaxes) {
row.push({style:["tax", rowStyle], text:tax ? tax.toFixed(2) : ' '});
}
row.push({style:["lineTotal", rowStyle], text:lineTotal || ' '});
grid.push(row);
@ -318,6 +347,14 @@ NINJA.subtotals = function(invoice, hideBalance)
return NINJA.prepareDataPairs(data, 'subtotals');
}
NINJA.subtotalsBalance = function(invoice) {
var isPartial = NINJA.parseFloat(invoice.partial);
return [[
{text: isPartial ? invoiceLabels.amount_due : invoiceLabels.balance_due, style:['balanceDueLabel']},
{text: formatMoney(invoice.balance_amount, invoice.client.currency_id), style:['balanceDue']}
]];
}
NINJA.accountDetails = function(invoice) {
var account = invoice.account;
var data = [
@ -334,9 +371,9 @@ NINJA.accountAddress = function(invoice) {
var account = invoice.account;
var cityStatePostal = '';
if (account.city || account.state || account.postal_code) {
cityStatePostal = ((account.city ? account.city + ', ' : '') + account.state + ' ' + account.postal_code).trim();
var swap = account.country && account.country.swap_postal_code == '1';
cityStatePostal = formatAddress(account.city, account.state, account.postal_code, swap);
}
var data = [
{text: account.address1},
{text: account.address2},
@ -345,7 +382,6 @@ NINJA.accountAddress = function(invoice) {
{text: invoice.account.custom_value1 ? invoice.account.custom_label1 + ' ' + invoice.account.custom_value1 : false},
{text: invoice.account.custom_value2 ? invoice.account.custom_label2 + ' ' + invoice.account.custom_value2 : false}
];
return NINJA.prepareDataList(data, 'accountAddress');
}
@ -365,7 +401,7 @@ NINJA.invoiceDetails = function(invoice) {
{text: invoice.invoice_date}
],
[
{text: invoiceLabels.due_date},
{text: (invoice.is_quote ? invoiceLabels.valid_until : invoiceLabels.due_date)},
{text: invoice.due_date}
]
];
@ -403,10 +439,17 @@ NINJA.clientDetails = function(invoice) {
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 cityStatePostal = '';
if (client.city || client.state || client.postal_code) {
var swap = client.country && client.country.swap_postal_code == '1';
cityStatePostal = formatAddress(client.city, client.state, client.postal_code, swap);
}
data = [
{text:clientName || ' ', style: ['clientName']},
{text:client.address1},
{text:concatStrings(client.city, client.state, client.postal_code)},
{text:client.address2},
{text:cityStatePostal},
{text:client.country ? client.country.name : ''},
{text:clientEmail},
{text: invoice.client.custom_value1 ? invoice.account.custom_client_label1 + ' ' + invoice.client.custom_value1 : false},

View File

@ -807,6 +807,21 @@ function displaySubtotals(doc, layout, invoice, y, rightAlignTitleX)
return displayGrid(doc, invoice, data, 300, y, layout, options) + 10;
}
function formatAddress(city, state, zip, swap) {
var str = '';
if (swap) {
str += zip ? zip + ' ' : '';
str += city ? city : '';
str += (city && state) ? ', ' : (city ? ' ' : '');
str += state;
} else {
str += city ? city : '';
str += (city && state) ? ', ' : (state ? ' ' : '');
str += state + ' ' + zip;
}
return str;
}
function concatStrings() {
var concatStr = '';
var data = [];

View File

@ -755,5 +755,18 @@
<p>For at tilgå under indstillingerne ved hjælp af dot notation. For eksempel kan man for at vise klient navnet bruge <code>$client.nameValue</code>.</p>
<p>Hvis du mangler svar nogen spørgsmål post et spørgsmål i vores <a href="https://www.invoiceninja.com/forums/forum/support/" target="_blank">support forum</a>.</p>',
'invoice_due_date' => 'Due Date',
'quote_due_date' => 'Valid Until',
'valid_until' => 'Valid Until',
'reset_terms' => 'Reset terms',
'reset_footer' => 'Reset footer',
'invoices_sent' => ':count invoice sent|:count invoices sent',
'status_draft' => 'Draft',
'status_sent' => 'Sent',
'status_viewed' => 'Viewed',
'status_partial' => 'Partial',
'status_paid' => 'Paid',
'show_line_item_tax' => 'Display <b>line item taxes</b> inline',
);

View File

@ -752,7 +752,21 @@ return array(
'customize_help' => '<p>We use <a href="http://pdfmake.org/" target="_blank">pdfmake</a> to define the invoice designs declaratively. The pdfmake <a href="http://pdfmake.org/playground.html" target="_blank">playground</a> provide\'s a great way to see the library in action.</p>
<p>You can access any invoice field by adding <code>Value</code> to the end. For example <code>$invoiceNumberValue</code> displays the invoice number.</p>
<p>To access a child property using dot notation. For example to show the client name you could use <code>$client.nameValue</code>.</p>
<p>If you need help figuring something out post a question to our <a href="https://www.invoiceninja.com/forums/forum/support/" target="_blank">support forum</a>.</p>'
<p>If you need help figuring something out post a question to our <a href="https://www.invoiceninja.com/forums/forum/support/" target="_blank">support forum</a>.</p>',
'invoice_due_date' => 'Due Date',
'quote_due_date' => 'Valid Until',
'valid_until' => 'Valid Until',
'reset_terms' => 'Reset terms',
'reset_footer' => 'Reset footer',
'invoices_sent' => ':count invoice sent|:count invoices sent',
'status_draft' => 'Draft',
'status_sent' => 'Sent',
'status_viewed' => 'Viewed',
'status_partial' => 'Partial',
'status_paid' => 'Paid',
'show_line_item_tax' => 'Display <b>line item taxes</b> inline',
);

View File

@ -58,8 +58,8 @@ return array(
'enable' => 'Enable',
'learn_more' => 'Learn more',
'manage_rates' => 'Manage rates',
'note_to_client' => 'Note to client',
'invoice_terms' => 'Invoice terms',
'note_to_client' => 'Note to Client',
'invoice_terms' => 'Invoice Terms',
'save_as_default_terms' => 'Save as default terms',
'download_pdf' => 'Download PDF',
'pay_now' => 'Pay Now',
@ -536,7 +536,7 @@ return array(
'click_once' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.',
'default_invoice_footer' => 'Set default <b>invoice footer</b>',
'invoice_footer' => 'Invoice footer',
'invoice_footer' => 'Invoice Footer',
'save_as_default_footer' => 'Save as default footer',
'token_management' => 'Token Management',
@ -752,8 +752,20 @@ return array(
'customize_help' => '<p>We use <a href="http://pdfmake.org/" target="_blank">pdfmake</a> to define the invoice designs declaratively. The pdfmake <a href="http://pdfmake.org/playground.html" target="_blank">playground</a> provide\'s a great way to see the library in action.</p>
<p>You can access any invoice field by adding <code>Value</code> to the end. For example <code>$invoiceNumberValue</code> displays the invoice number.</p>
<p>To access a child property using dot notation. For example to show the client name you could use <code>$client.nameValue</code>.</p>
<p>If you need help figuring something out post a question to our <a href="https://www.invoiceninja.com/forums/forum/support/" target="_blank">support forum</a>.</p>'
<p>If you need help figuring something out post a question to our <a href="https://www.invoiceninja.com/forums/forum/support/" target="_blank">support forum</a>.</p>',
'invoice_due_date' => 'Due Date',
'quote_due_date' => 'Valid Until',
'valid_until' => 'Valid Until',
'reset_terms' => 'Reset terms',
'reset_footer' => 'Reset footer',
'invoices_sent' => ':count invoice sent|:count invoices sent',
'status_draft' => 'Draft',
'status_sent' => 'Sent',
'status_viewed' => 'Viewed',
'status_partial' => 'Partial',
'status_paid' => 'Paid',
'show_line_item_tax' => 'Display <b>line item taxes</b> inline',
);

View File

@ -730,7 +730,20 @@ return array(
'customize_help' => '<p>Nosotros usamos <a href="http://pdfmake.org/" target="_blank">pdfmake</a> para definir los diseños de las cuentas de cobro de manera declarativa. El <a href="http://pdfmake.org/playground.html" target="_blank">playground</a> de pdfmake es una excelente manera de ver a la librería en acción.</p>
<p>Puede acceder cualquier campo de una factura agregando <code>Value</code> al final. Por ejemplo, <code>$invoiceNumberValue</code> muestra el número de factura.</p>
<p>Para acceder a una propiedad hija usando notación de punto.Por ejemplo, para mostrar el nombre de un cliente se puede usar <code>$client.nameValue</code>.</p>
<p>Si necesita ayuda entendiendo algo puede preguntar en nuestro <a href="https://www.invoiceninja.com/forums/forum/support/" target="_blank">foro de soporte</a>.</p>'
<p>Si necesita ayuda entendiendo algo puede preguntar en nuestro <a href="https://www.invoiceninja.com/forums/forum/support/" target="_blank">foro de soporte</a>.</p>',
'invoice_due_date' => 'Due Date',
'quote_due_date' => 'Valid Until',
'valid_until' => 'Valid Until',
'reset_terms' => 'Reset terms',
'reset_footer' => 'Reset footer',
'invoices_sent' => ':count invoice sent|:count invoices sent',
'status_draft' => 'Draft',
'status_sent' => 'Sent',
'status_viewed' => 'Viewed',
'status_partial' => 'Partial',
'status_paid' => 'Paid',
'show_line_item_tax' => 'Display <b>line item taxes</b> inline',

View File

@ -752,7 +752,20 @@ return array(
'customize_help' => '<p>We use <a href="http://pdfmake.org/" target="_blank">pdfmake</a> to define the invoice designs declaratively. The pdfmake <a href="http://pdfmake.org/playground.html" target="_blank">playground</a> provide\'s a great way to see the library in action.</p>
<p>You can access any invoice field by adding <code>Value</code> to the end. For example <code>$invoiceNumberValue</code> displays the invoice number.</p>
<p>To access a child property using dot notation. For example to show the client name you could use <code>$client.nameValue</code>.</p>
<p>If you need help figuring something out post a question to our <a href="https://www.invoiceninja.com/forums/forum/support/" target="_blank">support forum</a>.</p>'
<p>If you need help figuring something out post a question to our <a href="https://www.invoiceninja.com/forums/forum/support/" target="_blank">support forum</a>.</p>',
'invoice_due_date' => 'Due Date',
'quote_due_date' => 'Valid Until',
'valid_until' => 'Valid Until',
'reset_terms' => 'Reset terms',
'reset_footer' => 'Reset footer',
'invoices_sent' => ':count invoice sent|:count invoices sent',
'status_draft' => 'Draft',
'status_sent' => 'Sent',
'status_viewed' => 'Viewed',
'status_partial' => 'Partial',
'status_paid' => 'Paid',
'show_line_item_tax' => 'Display <b>line item taxes</b> inline',

View File

@ -744,7 +744,20 @@ return array(
'customize_help' => '<p>Nous utilisons <a href="http://pdfmake.org/" target="_blank">pdfmake</a> pour définir le design des factures. Le <a href="http://pdfmake.org/playground.html" target="_blank">bac à sable<a> de pdfmake est une bonne façon de voir cette bibliothèque en action.</p>
<p>Vous pouvez accéder à n\'importe quel champ de facture en ajoutant <code>Value</code> à la fin. Par exemple <code>$invoiceNumberValue</code> affiche le numéro de facture.</p>
<p>Pour accéder à une propriété héritée avec la notation par point. Par exemple pour montrer le nom du client vous pouvez utiliser <code>$client.nameValue</code>.</p>
<p>Si vous avez besoin d\'aide pour comprendre quelque chose envoyez une question à notre <a href="https://www.invoiceninja.com/forums/forum/support/" target="_blank">forum de support</a>.</p>'
<p>Si vous avez besoin d\'aide pour comprendre quelque chose envoyez une question à notre <a href="https://www.invoiceninja.com/forums/forum/support/" target="_blank">forum de support</a>.</p>',
'invoice_due_date' => 'Due Date',
'quote_due_date' => 'Valid Until',
'valid_until' => 'Valid Until',
'reset_terms' => 'Reset terms',
'reset_footer' => 'Reset footer',
'invoices_sent' => ':count invoice sent|:count invoices sent',
'status_draft' => 'Draft',
'status_sent' => 'Sent',
'status_viewed' => 'Viewed',
'status_partial' => 'Partial',
'status_paid' => 'Paid',
'show_line_item_tax' => 'Display <b>line item taxes</b> inline',

View File

@ -745,7 +745,21 @@ return array(
'customize_help' => '<p>We use <a href="http://pdfmake.org/" target="_blank">pdfmake</a> to define the invoice designs declaratively. The pdfmake <a href="http://pdfmake.org/playground.html" target="_blank">playground</a> provide\'s a great way to see the library in action.</p>
<p>You can access any invoice field by adding <code>Value</code> to the end. For example <code>$invoiceNumberValue</code> displays the invoice number.</p>
<p>To access a child property using dot notation. For example to show the client name you could use <code>$client.nameValue</code>.</p>
<p>If you need help figuring something out post a question to our <a href="https://www.invoiceninja.com/forums/forum/support/" target="_blank">support forum</a>.</p>'
<p>If you need help figuring something out post a question to our <a href="https://www.invoiceninja.com/forums/forum/support/" target="_blank">support forum</a>.</p>',
'invoice_due_date' => 'Due Date',
'quote_due_date' => 'Valid Until',
'valid_until' => 'Valid Until',
'reset_terms' => 'Reset terms',
'reset_footer' => 'Reset footer',
'invoices_sent' => ':count invoice sent|:count invoices sent',
'status_draft' => 'Draft',
'status_sent' => 'Sent',
'status_viewed' => 'Viewed',
'status_partial' => 'Partial',
'status_paid' => 'Paid',
'show_line_item_tax' => 'Display <b>line item taxes</b> inline',

View File

@ -747,7 +747,20 @@ return array(
'customize_help' => '<p>We use <a href="http://pdfmake.org/" target="_blank">pdfmake</a> to define the invoice designs declaratively. The pdfmake <a href="http://pdfmake.org/playground.html" target="_blank">playground</a> provide\'s a great way to see the library in action.</p>
<p>You can access any invoice field by adding <code>Value</code> to the end. For example <code>$invoiceNumberValue</code> displays the invoice number.</p>
<p>To access a child property using dot notation. For example to show the client name you could use <code>$client.nameValue</code>.</p>
<p>If you need help figuring something out post a question to our <a href="https://www.invoiceninja.com/forums/forum/support/" target="_blank">support forum</a>.</p>'
<p>If you need help figuring something out post a question to our <a href="https://www.invoiceninja.com/forums/forum/support/" target="_blank">support forum</a>.</p>',
'invoice_due_date' => 'Due Date',
'quote_due_date' => 'Valid Until',
'valid_until' => 'Valid Until',
'reset_terms' => 'Reset terms',
'reset_footer' => 'Reset footer',
'invoices_sent' => ':count invoice sent|:count invoices sent',
'status_draft' => 'Draft',
'status_sent' => 'Sent',
'status_viewed' => 'Viewed',
'status_partial' => 'Partial',
'status_paid' => 'Paid',
'show_line_item_tax' => 'Display <b>line item taxes</b> inline',

View File

@ -754,7 +754,20 @@ return array(
'customize_help' => '<p>We use <a href="http://pdfmake.org/" target="_blank">pdfmake</a> to define the invoice designs declaratively. The pdfmake <a href="http://pdfmake.org/playground.html" target="_blank">playground</a> provide\'s a great way to see the library in action.</p>
<p>You can access any invoice field by adding <code>Value</code> to the end. For example <code>$invoiceNumberValue</code> displays the invoice number.</p>
<p>To access a child property using dot notation. For example to show the client name you could use <code>$client.nameValue</code>.</p>
<p>If you need help figuring something out post a question to our <a href="https://www.invoiceninja.com/forums/forum/support/" target="_blank">support forum</a>.</p>'
<p>If you need help figuring something out post a question to our <a href="https://www.invoiceninja.com/forums/forum/support/" target="_blank">support forum</a>.</p>',
'invoice_due_date' => 'Due Date',
'quote_due_date' => 'Valid Until',
'valid_until' => 'Valid Until',
'reset_terms' => 'Reset terms',
'reset_footer' => 'Reset footer',
'invoices_sent' => ':count invoice sent|:count invoices sent',
'status_draft' => 'Draft',
'status_sent' => 'Sent',
'status_viewed' => 'Viewed',
'status_partial' => 'Partial',
'status_paid' => 'Paid',
'show_line_item_tax' => 'Display <b>line item taxes</b> inline',

View File

@ -752,7 +752,20 @@ return array(
'customize_help' => '<p>We use <a href="http://pdfmake.org/" target="_blank">pdfmake</a> to define the invoice designs declaratively. The pdfmake <a href="http://pdfmake.org/playground.html" target="_blank">playground</a> provide\'s a great way to see the library in action.</p>
<p>You can access any invoice field by adding <code>Value</code> to the end. For example <code>$invoiceNumberValue</code> displays the invoice number.</p>
<p>To access a child property using dot notation. For example to show the client name you could use <code>$client.nameValue</code>.</p>
<p>If you need help figuring something out post a question to our <a href="https://www.invoiceninja.com/forums/forum/support/" target="_blank">support forum</a>.</p>'
<p>If you need help figuring something out post a question to our <a href="https://www.invoiceninja.com/forums/forum/support/" target="_blank">support forum</a>.</p>',
'invoice_due_date' => 'Due Date',
'quote_due_date' => 'Valid Until',
'valid_until' => 'Valid Until',
'reset_terms' => 'Reset terms',
'reset_footer' => 'Reset footer',
'invoices_sent' => ':count invoice sent|:count invoices sent',
'status_draft' => 'Draft',
'status_sent' => 'Sent',
'status_viewed' => 'Viewed',
'status_partial' => 'Partial',
'status_paid' => 'Paid',
'show_line_item_tax' => 'Display <b>line item taxes</b> inline',

View File

@ -747,7 +747,20 @@ return array(
'customize_help' => '<p>We gebruiken <a href="http://pdfmake.org/" target="_blank">pdfmake</a> om de factuur ontwerpen declaratief te definieren. De pdfmake <a href="http://pdfmake.org/playground.html" target="_blank">playground</a> is een interessante manier om de library in actie te zien.</p>
<p>Je kan elk factuur veld gebruiken door <code>Veld</code> toe te voegen op het einde. Bijvoorbeeld <code>$invoiceNumberValue</code> toont de factuur nummer.</p>
<p>Gebruik dot notatie om een "kind eigenschap" te gebruiken. Bijvoorbeeld voor de klant naam te tonen gebruik je <code>$client.nameValue</code>.</p>
<p>Als je ergens hulp bij nodig hebt, post dan een vraag op ons <a href="https://www.invoiceninja.com/forums/forum/support/" target="_blank">support forum</a>.</p>'
<p>Als je ergens hulp bij nodig hebt, post dan een vraag op ons <a href="https://www.invoiceninja.com/forums/forum/support/" target="_blank">support forum</a>.</p>',
'invoice_due_date' => 'Due Date',
'quote_due_date' => 'Valid Until',
'valid_until' => 'Valid Until',
'reset_terms' => 'Reset terms',
'reset_footer' => 'Reset footer',
'invoices_sent' => ':count invoice sent|:count invoices sent',
'status_draft' => 'Draft',
'status_sent' => 'Sent',
'status_viewed' => 'Viewed',
'status_partial' => 'Partial',
'status_paid' => 'Paid',
'show_line_item_tax' => 'Display <b>line item taxes</b> inline',

View File

@ -747,8 +747,20 @@ return array(
'customize_help' => '<p>We use <a href="http://pdfmake.org/" target="_blank">pdfmake</a> to define the invoice designs declaratively. The pdfmake <a href="http://pdfmake.org/playground.html" target="_blank">playground</a> provide\'s a great way to see the library in action.</p>
<p>You can access any invoice field by adding <code>Value</code> to the end. For example <code>$invoiceNumberValue</code> displays the invoice number.</p>
<p>To access a child property using dot notation. For example to show the client name you could use <code>$client.nameValue</code>.</p>
<p>If you need help figuring something out post a question to our <a href="https://www.invoiceninja.com/forums/forum/support/" target="_blank">support forum</a>.</p>'
<p>If you need help figuring something out post a question to our <a href="https://www.invoiceninja.com/forums/forum/support/" target="_blank">support forum</a>.</p>',
'invoice_due_date' => 'Due Date',
'quote_due_date' => 'Valid Until',
'valid_until' => 'Valid Until',
'reset_terms' => 'Reset terms',
'reset_footer' => 'Reset footer',
'invoices_sent' => ':count invoice sent|:count invoices sent',
'status_draft' => 'Draft',
'status_sent' => 'Sent',
'status_viewed' => 'Viewed',
'status_partial' => 'Partial',
'status_paid' => 'Paid',
'show_line_item_tax' => 'Display <b>line item taxes</b> inline',
);

View File

@ -750,7 +750,20 @@ return array(
'customize_help' => '<p>We use <a href="http://pdfmake.org/" target="_blank">pdfmake</a> to define the invoice designs declaratively. The pdfmake <a href="http://pdfmake.org/playground.html" target="_blank">playground</a> provide\'s a great way to see the library in action.</p>
<p>You can access any invoice field by adding <code>Value</code> to the end. For example <code>$invoiceNumberValue</code> displays the invoice number.</p>
<p>To access a child property using dot notation. For example to show the client name you could use <code>$client.nameValue</code>.</p>
<p>If you need help figuring something out post a question to our <a href="https://www.invoiceninja.com/forums/forum/support/" target="_blank">support forum</a>.</p>'
<p>If you need help figuring something out post a question to our <a href="https://www.invoiceninja.com/forums/forum/support/" target="_blank">support forum</a>.</p>',
'invoice_due_date' => 'Due Date',
'quote_due_date' => 'Valid Until',
'valid_until' => 'Valid Until',
'reset_terms' => 'Reset terms',
'reset_footer' => 'Reset footer',
'invoices_sent' => ':count invoice sent|:count invoices sent',
'status_draft' => 'Draft',
'status_sent' => 'Sent',
'status_viewed' => 'Viewed',
'status_partial' => 'Partial',
'status_paid' => 'Paid',
'show_line_item_tax' => 'Display <b>line item taxes</b> inline',

View File

@ -82,6 +82,7 @@
{!! Former::populate($account) !!}
{!! Former::populateField('hide_quantity', intval($account->hide_quantity)) !!}
{!! Former::populateField('hide_paid_to_date', intval($account->hide_paid_to_date)) !!}
@foreach ($invoiceLabels as $field => $value)
{!! Former::populateField("labels_{$field}", $value) !!}
@endforeach

View File

@ -200,7 +200,7 @@
trans('texts.quote_number'),
trans('texts.quote_date'),
trans('texts.total'),
trans('texts.due_date'),
trans('texts.valid_until'),
trans('texts.status'))
->setUrl(url('api/quotes/'. $client->public_id))
->setOptions('sPaginationType', 'bootstrap')

View File

@ -16,7 +16,10 @@
{!! Former::select('client')->addOption('', '')->addGroupClass('client-select') !!}
{!! Former::text('amount') !!}
{!! Former::text('credit_date')->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT, DEFAULT_DATE_PICKER_FORMAT))->append('<i class="glyphicon glyphicon-calendar"></i>') !!}
{!! Former::text('credit_date')
->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT, DEFAULT_DATE_PICKER_FORMAT))
->addGroupClass('credit_date')
->append('<i class="glyphicon glyphicon-calendar"></i>') !!}
{!! Former::textarea('private_notes') !!}
</div>
@ -61,6 +64,9 @@
$('#amount').focus();
@endif
$('.credit_date .input-group-addon').click(function() {
toggleDatePicker('credit_date');
});
});
</script>

View File

@ -72,7 +72,7 @@
<h3 class="panel-title in-bold-white">
<i class="glyphicon glyphicon-exclamation-sign"></i> {{ trans('texts.notifications') }}
<div class="pull-right" style="font-size:14px;padding-top:4px">
{{ $invoicesSent }} {{ Utils::pluralize('invoice', $invoicesSent) }} {{ trans('texts.sent') }}
{{ trans_choice('texts.invoices_sent', $invoicesSent) }}
</div>
</h3>
</div>

View File

@ -81,7 +81,7 @@
<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))->appendIcon('calendar')->addGroupClass('invoice_date') !!}
{!! Former::text('due_date')->data_bind("datePicker: due_date, valueUpdate: 'afterkeydown'")
{!! Former::text('due_date')->data_bind("datePicker: due_date, valueUpdate: 'afterkeydown'")->label(trans("texts.{$entityType}_due_date"))
->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()')
@ -202,16 +202,24 @@
->label(null)->style('resize: none; min-width: 450px;')->rows(3) !!}
</div>
<div role="tabpanel" class="tab-pane" id="terms">
{!! Former::textarea('terms')->data_bind("value:wrapped_terms, placeholder: default_terms, valueUpdate: 'afterkeydown'")
{!! Former::textarea('terms')->data_bind("value:wrapped_terms, placeholder: terms_placeholder, valueUpdate: 'afterkeydown'")
->label(false)->style('resize: none; min-width: 450px')->rows(3)
->help('<label class="checkbox" style="width: 200px">
<input type="checkbox" style="width: 24px" data-bind="checked: set_default_terms"/>'.trans('texts.save_as_default_terms').'</label>') !!}
->help('<div class="checkbox">
<label>
<input type="checkbox" style="width: 24px" data-bind="checked: set_default_terms"/>'.trans('texts.save_as_default_terms').'
</label>
<div class="pull-right"><a href="#" onclick="return resetTerms()">' . trans("texts.reset_terms") . '</a></div>
</div>') !!}
</div>
<div role="tabpanel" class="tab-pane" id="footer">
{!! Former::textarea('invoice_footer')->data_bind("value:wrapped_footer, placeholder: default_footer, valueUpdate: 'afterkeydown'")
{!! Former::textarea('invoice_footer')->data_bind("value:wrapped_footer, placeholder: footer_placeholder, valueUpdate: 'afterkeydown'")
->label(false)->style('resize: none; min-width: 450px')->rows(3)
->help('<label class="checkbox" style="width: 200px">
<input type="checkbox" style="width: 24px" data-bind="checked: set_default_footer"/>'.trans('texts.save_as_default_footer').'</label>') !!}
->help('<div class="checkbox">
<label>
<input type="checkbox" style="width: 24px" data-bind="checked: set_default_footer"/>'.trans('texts.save_as_default_footer').'
</label>
<div class="pull-right"><a href="#" onclick="return resetFooter()">' . trans("texts.reset_footer") . '</a></div>
</div>') !!}
</div>
</div>
</div>
@ -500,6 +508,8 @@
->label(trans('texts.settings'))->data_bind('checked: $root.invoice_taxes, enable: $root.tax_rates().length > 1') !!}
{!! Former::checkbox('invoice_item_taxes')->text(trans('texts.enable_line_item_tax'))
->label('&nbsp;')->data_bind('checked: $root.invoice_item_taxes, enable: $root.tax_rates().length > 1') !!}
{!! Former::checkbox('show_item_taxes')->text(trans('texts.show_line_item_tax'))
->label('&nbsp;')->data_bind('checked: $root.show_item_taxes, enable: $root.tax_rates().length > 1') !!}
<br/>
@ -546,19 +556,12 @@
$(function() {
$('#country_id').combobox().on('change', function(e) {
var countryId = parseInt($('input[name=country_id]').val(), 10);
var foundMatch = false;
$('#country_id option').each(function() {
var itemId = parseInt($(this).val(), 10);
if (countryId === itemId) {
foundMatch = true;
var country = {id:countryId, name:$(this).text()};
var countryId = $('input[name=country_id]').val();
var country = _.findWhere(countries, {id: countryId});
if (country) {
model.invoice().client().country = country;
model.invoice().client().country_id(countryId);
return;
}
});
if (!foundMatch) {
} else {
model.invoice().client().country = false;
model.invoice().client().country_id(0);
}
@ -706,6 +709,7 @@
invoice.is_pro = {{ Auth::user()->isPro() ? 'true' : 'false' }};
invoice.is_quote = {{ $entityType == ENTITY_QUOTE ? 'true' : 'false' }};
invoice.contact = _.findWhere(invoice.client.contacts, {send_invoice: true});
invoice.account.show_item_taxes = $('#show_item_taxes').is(':checked');
if (invoice.is_recurring) {
invoice.invoice_number = '0000';
@ -752,6 +756,18 @@
}
}
function resetTerms() {
model.invoice().terms(model.invoice().default_terms());
refreshPDF();
return false;
}
function resetFooter() {
model.invoice().invoice_footer(model.invoice().default_footer());
refreshPDF();
return false;
}
function onDownloadClick() {
trackEvent('/activity', '/download_pdf');
var invoice = createInvoiceModel();
@ -952,6 +968,7 @@
self.invoice_taxes = ko.observable({{ Auth::user()->account->invoice_taxes ? 'true' : 'false' }});
self.invoice_item_taxes = ko.observable({{ Auth::user()->account->invoice_item_taxes ? 'true' : 'false' }});
self.show_item_taxes = ko.observable({{ Auth::user()->account->show_item_taxes ? 'true' : 'false' }});
self.mapping = {
'invoice': {
@ -1057,6 +1074,7 @@
self.taxFormComplete = function() {
model.taxBackup = false;
$('#taxModal').modal('hide');
refreshPDF();
}
self.showClientForm = function() {
@ -1143,10 +1161,12 @@
self.is_amount_discount = ko.observable(0);
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.default_terms = ko.observable("{{ str_replace(["\r\n","\r","\n"], '\n', addslashes($account->invoice_terms)) }}");
self.terms_placeholder = ko.observable({{ !$invoice && $account->invoice_terms ? 'true' : 'false' }} ? self.default_terms() : '');
self.set_default_terms = ko.observable(false);
self.invoice_footer = ko.observable('');
self.default_footer = ko.observable({{ !$invoice && $account->invoice_footer ? 'true' : 'false' }} ? wordWrapText('{!! str_replace(["\r\n","\r","\n"], '\n', addslashes($account->invoice_footer)) !!}', 600) : '');
self.default_footer = ko.observable("{{ str_replace(["\r\n","\r","\n"], '\n', addslashes($account->invoice_footer)) }}");
self.footer_placeholder = ko.observable({{ !$invoice && $account->invoice_footer ? 'true' : 'false' }} ? self.default_footer() : '');
self.set_default_footer = ko.observable(false);
self.public_notes = ko.observable('');
self.po_number = ko.observable('');
@ -1786,6 +1806,7 @@
var products = {!! $products !!};
var clients = {!! $clients !!};
var countries = {!! $countries !!};
var clientMap = {};
var $clientSelect = $('select#client');

View File

@ -25,7 +25,7 @@
<div class="pull-right" style="text-align:right">
@if ($invoice->is_quote)
{!! Button::normal(trans('texts.download_pdf'))->withAttributes(['onclick' => 'onDownloadClick()'])->large() !!}&nbsp;&nbsp;
@if (!$isConverted)
@if ($showApprove)
{!! Button::success(trans('texts.approve'))->asLinkTo(URL::to('/approve/' . $invitation->invitation_key))->large() !!}
@endif
@elseif ($invoice->client->account->isGatewayConfigured() && !$invoice->isPaid() && !$invoice->is_recurring)

View File

@ -17,6 +17,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="csrf-token" content="{{ csrf_token() }}">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="msapplication-config" content="none"/>
<link href="//fonts.googleapis.com/css?family=Roboto:400,700,900,100&subset=latin,latin-ext" rel="stylesheet" type="text/css">
<link href="//fonts.googleapis.com/css?family=Roboto+Slab:400,300,700&subset=latin,latin-ext" rel="stylesheet" type="text/css">

View File

@ -32,7 +32,10 @@
->addGroupClass('payment-type-select') !!}
@endif
{!! Former::text('payment_date')->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT))->append('<i class="glyphicon glyphicon-calendar"></i>') !!}
{!! Former::text('payment_date')
->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT))
->addGroupClass('payment_date')
->append('<i class="glyphicon glyphicon-calendar"></i>') !!}
{!! Former::text('transaction_reference') !!}
@if (!$payment)
@ -76,6 +79,10 @@
@elseif (!$payment)
$('#amount').focus();
@endif
$('.payment_date .input-group-addon').click(function() {
toggleDatePicker('payment_date');
});
});
</script>

View File

@ -144,10 +144,6 @@ table.table thead .sorting_desc_disabled:after { content: '' !important }
$('[name="guest_key"]').val(localStorage.getItem('guest_key'));
}
@if (isset($invoiceNow) && $invoiceNow)
getStarted();
@endif
function isStorageSupported() {
if ('localStorage' in window && window['localStorage'] !== null) {
var storage = window.localStorage;

View File

@ -0,0 +1,37 @@
@extends('master')
@section('body')
{!! Form::open(array('url' => 'get_started', 'id' => 'startForm')) !!}
{!! Form::hidden('guest_key') !!}
{!! Form::hidden('sign_up', Input::get('sign_up')) !!}
{!! Form::hidden('redirect_to', Input::get('redirect_to')) !!}
{!! Form::close() !!}
<script>
if (isStorageSupported()) {
$('[name="guest_key"]').val(localStorage.getItem('guest_key'));
}
$(function() {
$('#startForm').submit();
})
function isStorageSupported() {
if ('localStorage' in window && window['localStorage'] !== null) {
var storage = window.localStorage;
} else {
return false;
}
var testKey = 'test';
try {
storage.setItem(testKey, '1');
storage.removeItem(testKey);
return true;
} catch (error) {
return false;
}
}
</script>
@stop

View File

@ -40,8 +40,10 @@
{!! Former::populateField('enable_chart', intval($enableChart)) !!}
{!! Former::text('start_date')->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT))
->addGroupClass('start_date')
->append('<i class="glyphicon glyphicon-calendar" onclick="toggleDatePicker(\'start_date\')"></i>') !!}
{!! Former::text('end_date')->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT))
->addGroupClass('end_date')
->append('<i class="glyphicon glyphicon-calendar" onclick="toggleDatePicker(\'end_date\')"></i>') !!}
<p>&nbsp;</p>
@ -185,6 +187,15 @@
scaleLabel : "<%=value%>",
};
$(function() {
$('.start_date .input-group-addon').click(function() {
toggleDatePicker('start_date');
});
$('.end_date .input-group-addon').click(function() {
toggleDatePicker('end_date');
});
})
new Chart(ctx).{!! $chartType !!}(chart, options);
</script>

View File

@ -4,7 +4,9 @@
<center>
@if (!session(SESSION_USER_ACCOUNTS) || count(session(SESSION_USER_ACCOUNTS)) < 5)
{!! Button::success(trans('texts.add_company'))->asLinkTo('/login?new_company=true') !!}
@endif
</center>
<p>&nbsp;</p>

View File

@ -3,17 +3,12 @@
{
"columns": [
{
"image": "$accountLogo",
"width": 80,
"margin": [60, -40, 0, 0]
},
{
"width": 300,
"width": 380,
"stack": [
{"text":"$yourInvoiceLabelUC", "style": "yourInvoice"},
"$clientDetails"
],
"margin": [-32, 120, 0, 0]
"margin": [60, 100, 0, 10]
},
{
"canvas": [
@ -29,14 +24,14 @@
}
],
"width":10,
"margin":[-10,120,0,0]
"margin":[-10,100,0,10]
},
{
"table": {
"body": "$invoiceDetails"
},
"layout": "noBorders",
"margin": [0, 130, 0, 0]
"margin": [0, 110, 0, 0]
}
]
},
@ -44,7 +39,7 @@
"style": "invoiceLineItemsTable",
"table": {
"headerRows": 1,
"widths": ["15%", "*", "12%", "$quantityWidth", "22%"],
"widths": ["15%", "*", "14%", "$quantityWidth", "22%"],
"body": "$invoiceLineItems"
},
"layout": {
@ -80,32 +75,54 @@
}
],
"footer": [
{"canvas": [{ "type": "line", "x1": 0, "y1": 0, "x2": 600, "y2": 0,"lineWidth": 100,"lineColor":"#2e2b2b"}]},
{"canvas": [{ "type": "line", "x1": 0, "y1": 0, "x2": 600, "y2": 0,"lineWidth": 100,"lineColor":"$secondaryColor:#2e2b2b"}]},
{
"text": "$invoiceFooter",
"margin": [40, -20, 40, 0],
"margin": [40, 0, 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]},
{
"canvas": [
{
"type": "line",
"x1": 0,
"y1": 0,
"x2": 600,
"y2": 0,
"lineWidth": 200,
"lineColor": "$secondaryColor:#2e2b2b"
}
],
"width": 10
},
{
"columns": [
{
"text": " ",
"width": 260
"image": "$accountLogo",
"fit": [120, 80],
"margin": [30, 20, 0, 0]
},
{
"stack": "$accountDetails",
"margin": [0, 16, 0, 0],
"margin": [
0,
16,
0,
0
],
"width": 140
},
{
"stack": "$accountAddress",
"margin": [20, 16, 0, 0]
"margin": [
20,
16,
0,
0
]
}
]
}
@ -120,16 +137,19 @@
},
"accountName": {
"bold": true,
"margin": [4, 2, 4, 2],
"margin": [4, 2, 4, 1],
"color": "$primaryColor:#36a498"
},
"accountDetails": {
"margin": [4, 2, 4, 2],
"color": "#AAA9A9"
"margin": [4, 2, 4, 1],
"color": "#FFFFFF"
},
"accountAddress": {
"margin": [4, 2, 4, 2],
"color": "#AAA9A9"
"margin": [4, 2, 4, 1],
"color": "#FFFFFF"
},
"clientDetails": {
"margin": [0, 2, 0, 1]
},
"odd": {
"fillColor": "#ebebeb",
@ -169,6 +189,9 @@
"qtyTableHeader": {
"alignment": "right"
},
"taxTableHeader": {
"alignment": "right"
},
"lineTotalTableHeader": {
"alignment": "right",
"margin": [0, 0, 40, 0]

View File

@ -156,6 +156,9 @@
"qtyTableHeader": {
"alignment": "right"
},
"taxTableHeader": {
"alignment": "right"
},
"lineTotalTableHeader": {
"alignment": "right"
},

View File

@ -14,7 +14,7 @@
]
},
{
"canvas": [{ "type": "rect", "x": 0, "y": 0, "w": 515, "h": 26, "r":0, "lineWidth": 1, "color":"#403d3d"}],"width":10,"margin":[0,25,0,-30]},
"canvas": [{ "type": "rect", "x": 0, "y": 0, "w": 515, "h": 26, "r":0, "lineWidth": 1, "color":"$secondaryColor:#403d3d"}],"width":10,"margin":[0,25,0,-30]},
{
"style": "invoiceLineItemsTable",
"table": {
@ -63,7 +63,7 @@
"h": 26,
"r": 0,
"lineWidth": 1,
"color": "#403d3d"
"color": "$secondaryColor:#403d3d"
}
],
"width": 10,
@ -183,6 +183,9 @@
"qtyTableHeader": {
"alignment": "right"
},
"taxTableHeader": {
"alignment": "right"
},
"lineTotalTableHeader": {
"alignment": "right"
},