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

Bug fixes

This commit is contained in:
Hillel Coren 2015-09-21 00:05:02 +03:00
parent dfd1ae502f
commit 6b063abe9a
42 changed files with 430 additions and 216 deletions

View File

@ -197,7 +197,7 @@ class CheckData extends Command {
$activityFix = 0;
}
} else if ($activity->activity_type_id == ACTIVITY_TYPE_DELETE_PAYMENT) {
// **Fix for delting payment after deleting invoice**
// **Fix for deleting payment after deleting invoice**
if ($activity->adjustment != 0 && $invoice->is_deleted && $activity->created_at > $invoice->deleted_at) {
$this->info("Incorrect adjustment for deleted payment adjustment:{$activity->adjustment}");
$foundProblem = true;

View File

@ -33,6 +33,7 @@ use App\Models\DateFormat;
use App\Models\DatetimeFormat;
use App\Models\Language;
use App\Models\Size;
use App\Models\Gateway;
use App\Models\Timezone;
use App\Models\Industry;
use App\Models\InvoiceDesign;
@ -150,7 +151,7 @@ class AccountController extends BaseController
public function showSection($section = ACCOUNT_DETAILS, $subSection = false)
{
if ($section == ACCOUNT_DETAILS) {
$primaryUser = Auth::user()->account->users()->orderBy('id')->first();
$primaryUser = Auth::user()->account->getPrimaryUser();
$data = [
'account' => Account::with('users')->findOrFail(Auth::user()->account_id),
'countries' => Cache::get('countries'),
@ -177,7 +178,7 @@ class AccountController extends BaseController
return Redirect::to('gateways/create');
} else {
return View::make('accounts.payments', [
'showAdd' => $count < 3,
'showAdd' => $count < count(Gateway::$paymentTypes),
'title' => trans('texts.online_payments')
]);
}
@ -251,11 +252,16 @@ class AccountController extends BaseController
}
} else if ($subSection == ACCOUNT_TEMPLATES_AND_REMINDERS) {
$data['templates'] = [];
$data['defaultTemplates'] = [];
foreach ([ENTITY_INVOICE, ENTITY_QUOTE, ENTITY_PAYMENT, REMINDER1, REMINDER2, REMINDER3] as $type) {
$data['templates'][$type] = [
'subject' => $account->getEmailSubject($type),
'template' => $account->getEmailTemplate($type),
];
$data['defaultTemplates'][$type] = [
'subject' => $account->getDefaultEmailSubject($type),
'template' => $account->getDefaultEmailTemplate($type),
];
}
$data['emailFooter'] = $account->getEmailFooter();
$data['title'] = trans('texts.email_templates');
@ -321,18 +327,22 @@ class AccountController extends BaseController
foreach ([ENTITY_INVOICE, ENTITY_QUOTE, ENTITY_PAYMENT, REMINDER1, REMINDER2, REMINDER3] as $type) {
$subjectField = "email_subject_{$type}";
$account->$subjectField = Input::get($subjectField, $account->getEmailSubject($type));
$subject = Input::get($subjectField, $account->getEmailSubject($type));
$account->$subjectField = ($subject == $account->getDefaultEmailSubject($type) ? null : $subject);
$bodyField = "email_template_{$type}";
$account->$bodyField = Input::get($bodyField, $account->getEmailTemplate($type));
$body = Input::get($bodyField, $account->getEmailTemplate($type));
$account->$bodyField = ($body == $account->getDefaultEmailTemplate($type) ? null : $body);
}
foreach ([REMINDER1, REMINDER2, REMINDER3] as $type) {
$enableField = "enable_{$type}";
$account->$enableField = Input::get($enableField) ? true : false;
$numDaysField = "num_days_{$type}";
$account->$numDaysField = Input::get($numDaysField);
if ($account->$enableField) {
$numDaysField = "num_days_{$type}";
$account->$numDaysField = Input::get($numDaysField);
}
}
$account->save();
@ -716,6 +726,11 @@ class AccountController extends BaseController
$user->username = trim(Input::get('email'));
$user->email = trim(strtolower(Input::get('email')));
$user->phone = trim(Input::get('phone'));
if (Utils::isNinja()) {
if (Input::get('referral_code')) {
$user->referral_code = $this->accountRepo->getReferralCode();
}
}
if (Utils::isNinjaDev()) {
$user->dark_mode = Input::get('dark_mode') ? true : false;
}

View File

@ -54,6 +54,13 @@ class HomeController extends BaseController
Auth::logout();
}
// Track the referral/campaign code
foreach (['rc', 'utm_campaign'] as $code) {
if (Input::has($code)) {
Session::set(SESSION_REFERRAL_CODE, Input::get($code));
}
}
if (Auth::check()) {
$redirectTo = Input::get('redirect_to', 'invoices/create');
return Redirect::to($redirectTo)->with('sign_up', Input::get('sign_up'));

View File

@ -356,6 +356,10 @@ class InvoiceController extends BaseController
'lastSent' => $lastSent);
$data = array_merge($data, self::getViewModel());
if ($clone) {
$data['formIsChanged'] = true;
}
// Set the invitation link on the client's contacts
if (!$clone) {
$clients = $data['clients'];
@ -526,9 +530,11 @@ class InvoiceController extends BaseController
Utils::trackViewed($client->getDisplayName(), ENTITY_CLIENT, $url);
}
$pdfUpload = Input::get('pdfupload');
if (!empty($pdfUpload) && strpos($pdfUpload, 'data:application/pdf;base64,') === 0) {
$invoice->updateCachedPDF(Input::get('pdfupload'));
if ($invoice->account->pdf_email_attachment) {
$pdfUpload = Input::get('pdfupload');
if (!empty($pdfUpload) && strpos($pdfUpload, 'data:application/pdf;base64,') === 0) {
$invoice->updateCachedPDF(Input::get('pdfupload'));
}
}
if ($action == 'clone') {

View File

@ -218,8 +218,12 @@ class PaymentController extends BaseController
}
Session::put('payment_type', $paymentType);
$accountGateway = $invoice->client->account->getGatewayByType($paymentType);
$gateway = $accountGateway->gateway;
$acceptedCreditCardTypes = $accountGateway->getCreditcardTypes();
// Handle offsite payments
if ($useToken || $paymentType != PAYMENT_TYPE_CREDIT_CARD) {
if ($useToken || $paymentType != PAYMENT_TYPE_CREDIT_CARD || $gateway->id == GATEWAY_EWAY) {
if (Session::has('error')) {
Session::reflash();
return Redirect::to('view/'.$invitationKey);
@ -228,10 +232,6 @@ class PaymentController extends BaseController
}
}
$accountGateway = $invoice->client->account->getGatewayByType($paymentType);
$gateway = $accountGateway->gateway;
$acceptedCreditCardTypes = $accountGateway->getCreditcardTypes();
$data = [
'showBreadcrumbs' => false,
'url' => 'payment/'.$invitationKey,
@ -327,7 +327,8 @@ class PaymentController extends BaseController
if ($validator->fails()) {
return Redirect::to('license')
->withErrors($validator);
->withErrors($validator)
->withInput();
}
$account = $this->accountRepo->getNinjaAccount();
@ -438,7 +439,6 @@ class PaymentController extends BaseController
$validator = Validator::make(Input::all(), $rules);
if ($validator->fails()) {
//Utils::logError('Payment Error [invalid]');
return Redirect::to('payment/'.$invitationKey)
->withErrors($validator)
->withInput();
@ -456,8 +456,16 @@ class PaymentController extends BaseController
}
try {
// For offsite payments send the client's details on file
// If we're using a token then we don't need to send any other data
if (!$onSite || $useToken) {
$data = false;
} else {
$data = Input::all();
}
$gateway = $this->paymentService->createGateway($accountGateway);
$details = $this->paymentService->getPaymentDetails($invitation, ($useToken || !$onSite) ? false : Input::all());
$details = $this->paymentService->getPaymentDetails($invitation, $data);
// check if we're creating/using a billing token
if ($accountGateway->gateway_id == GATEWAY_STRIPE) {
@ -475,7 +483,13 @@ class PaymentController extends BaseController
}
$response = $gateway->purchase($details)->send();
$ref = $response->getTransactionReference();
if ($accountGateway->gateway_id == GATEWAY_EWAY) {
$ref = $response->getData()['AccessCode'];
$token = $response->getCardReference();
} else {
$ref = $response->getTransactionReference();
}
if (!$ref) {
$this->error('No-Ref', $response->getMessage(), $accountGateway);

View File

@ -385,28 +385,4 @@ class UserController extends BaseController
return View::make('users.account_management');
}
public function claimReferralCode($email)
{
$user = User::whereEmail($email)
->whereReferralCode(null)
->whereConfirmed(true)
->first();
if ($user) {
do {
$code = strtoupper(str_random(8));
$match = User::whereReferralCode($code)
->withTrashed()
->first();
} while ($match);
$user->referral_code = $code;
$user->save();
return $code;
}
return Redirect::to('/');
}
}

View File

@ -37,39 +37,6 @@ class StartupCheck
return $next($request);
}
// Check data has been cached
$cachedTables = [
'currencies' => 'App\Models\Currency',
'sizes' => 'App\Models\Size',
'industries' => 'App\Models\Industry',
'timezones' => 'App\Models\Timezone',
'dateFormats' => 'App\Models\DateFormat',
'datetimeFormats' => 'App\Models\DatetimeFormat',
'languages' => 'App\Models\Language',
'paymentTerms' => 'App\Models\PaymentTerm',
'paymentTypes' => 'App\Models\PaymentType',
'countries' => 'App\Models\Country',
'invoiceDesigns' => 'App\Models\InvoiceDesign',
];
if (Input::has('clear_cache')) {
Session::flash('message', 'Cache cleared');
}
foreach ($cachedTables as $name => $class) {
if (Input::has('clear_cache') || !Cache::has($name)) {
if ($name == 'paymentTerms') {
$orderBy = 'num_days';
} elseif (in_array($name, ['currencies', 'sizes', 'industries', 'languages', 'countries'])) {
$orderBy = 'name';
} else {
$orderBy = 'id';
}
$tableData = $class::orderBy($orderBy)->get();
if (count($tableData)) {
Cache::forever($name, $tableData);
}
}
}
// check the application is up to date and for any news feed messages
if (Auth::check()) {
$count = Session::get(SESSION_COUNTER, 0);
@ -122,11 +89,6 @@ class StartupCheck
App::setLocale($locale);
}
// Track the referral code
if (Input::has('rc')) {
Session::set(SESSION_REFERRAL_CODE, Input::get('rc'));
}
// Make sure the account/user localization settings are in the session
if (Auth::check() && !Session::has(SESSION_TIMEZONE)) {
Event::fire(new UserSettingsChanged());
@ -147,10 +109,11 @@ class StartupCheck
$design = new InvoiceDesign();
$design->id = $item->id;
$design->name = $item->name;
$design->javascript = $item->javascript;
$design->pdfmake = $item->pdfmake;
$design->save();
}
Cache::forget('invoiceDesigns');
Session::flash('message', trans('texts.bought_designs'));
}
} elseif ($productId == PRODUCT_WHITE_LABEL) {
@ -164,6 +127,40 @@ class StartupCheck
}
}
}
// Check data has been cached
$cachedTables = [
'currencies' => 'App\Models\Currency',
'sizes' => 'App\Models\Size',
'industries' => 'App\Models\Industry',
'timezones' => 'App\Models\Timezone',
'dateFormats' => 'App\Models\DateFormat',
'datetimeFormats' => 'App\Models\DatetimeFormat',
'languages' => 'App\Models\Language',
'paymentTerms' => 'App\Models\PaymentTerm',
'paymentTypes' => 'App\Models\PaymentType',
'countries' => 'App\Models\Country',
'invoiceDesigns' => 'App\Models\InvoiceDesign',
];
if (Input::has('clear_cache')) {
Session::flash('message', 'Cache cleared');
}
foreach ($cachedTables as $name => $class) {
if (Input::has('clear_cache') || !Cache::has($name)) {
if ($name == 'paymentTerms') {
$orderBy = 'num_days';
} elseif (in_array($name, ['currencies', 'sizes', 'industries', 'languages', 'countries'])) {
$orderBy = 'name';
} else {
$orderBy = 'id';
}
$tableData = $class::orderBy($orderBy)->get();
if (count($tableData)) {
Cache::forever($name, $tableData);
}
}
}
if (isset($_SERVER['HTTP_USER_AGENT']) && preg_match('/(?i)msie [2-8]/', $_SERVER['HTTP_USER_AGENT'])) {
Session::flash('error', trans('texts.old_browser'));

View File

@ -39,7 +39,6 @@ Route::get('terms', 'HomeController@showTerms');
Route::get('log_error', 'HomeController@logError');
Route::get('invoice_now', 'HomeController@invoiceNow');
Route::get('keep_alive', 'HomeController@keepAlive');
Route::get('referral_code/{email}', 'UserController@claimReferralCode');
Route::post('get_started', 'AccountController@getStarted');
// Client visible pages
@ -358,6 +357,7 @@ if (!defined('CONTACT_EMAIL')) {
define('PAYMENT_LIBRARY_PHP_PAYMENTS', 2);
define('GATEWAY_AUTHORIZE_NET', 1);
define('GATEWAY_EWAY', 4);
define('GATEWAY_AUTHORIZE_NET_SIM', 2);
define('GATEWAY_PAYPAL_EXPRESS', 17);
define('GATEWAY_PAYPAL_PRO', 18);
@ -382,7 +382,7 @@ if (!defined('CONTACT_EMAIL')) {
define('NINJA_GATEWAY_CONFIG', 'NINJA_GATEWAY_CONFIG');
define('NINJA_WEB_URL', 'https://www.invoiceninja.com');
define('NINJA_APP_URL', 'https://app.invoiceninja.com');
define('NINJA_VERSION', '2.3.4');
define('NINJA_VERSION', '2.4.0');
define('NINJA_DATE', '2000-01-01');
define('NINJA_FROM_EMAIL', 'maildelivery@invoiceninja.com');
@ -391,6 +391,7 @@ if (!defined('CONTACT_EMAIL')) {
define('OUTDATE_BROWSER_URL', 'http://browsehappy.com/');
define('PDFMAKE_DOCS', 'http://pdfmake.org/playground.html');
define('PHANTOMJS_CLOUD', 'http://api.phantomjscloud.com/single/browser/v1/');
define('REFERRAL_PROGRAM_URL', false);
define('COUNT_FREE_DESIGNS', 4);
define('COUNT_FREE_DESIGNS_SELF_HOST', 5); // include the custom design

View File

@ -412,6 +412,15 @@ class Account extends Eloquent
return $this;
}
public function getDefaultEmailSubject($entityType)
{
if (strpos($entityType, 'reminder') !== false) {
$entityType = 'reminder';
}
return trans("texts.{$entityType}_subject", ['invoice' => '$invoice', 'account' => '$account']);
}
public function getEmailSubject($entityType)
{
$field = "email_subject_{$entityType}";
@ -421,22 +430,11 @@ class Account extends Eloquent
return $value;
}
if (strpos($entityType, 'reminder') !== false) {
$entityType = 'reminder';
}
return trans("texts.{$entityType}_subject", ['invoice' => '$invoice', 'account' => '$account']);
return $this->getDefaultEmailSubject($entityType);
}
public function getEmailTemplate($entityType, $message = false)
public function getDefaultEmailTemplate($entityType, $message = false)
{
$field = "email_template_{$entityType}";
$template = $this->$field;
if ($template) {
return $template;
}
if (strpos($entityType, 'reminder') >= 0) {
$entityType = ENTITY_INVOICE;
}
@ -452,6 +450,18 @@ class Account extends Eloquent
return $template . "\$footer";
}
public function getEmailTemplate($entityType, $message = false)
{
$field = "email_template_{$entityType}";
$template = $this->$field;
if ($template) {
return $template;
}
return $this->getDefaultEmailTemplate($entityType, $message);
}
public function getEmailFooter()
{
if ($this->email_footer) {

View File

@ -397,4 +397,16 @@ class AccountRepository
{
return Account::whereRaw('enable_reminder1 = 1 OR enable_reminder2 = 1 OR enable_reminder3 = 1')->get();
}
public function getReferralCode()
{
do {
$code = strtoupper(str_random(8));
$match = User::whereReferralCode($code)
->withTrashed()
->first();
} while ($match);
return $code;
}
}

View File

@ -289,16 +289,15 @@ class InvoiceRepository
}
if ($invoice->is_recurring) {
if ($invoice->start_date && $invoice->start_date != Utils::toSqlDate($data['start_date'])) {
$invoice->last_sent_date = null;
}
$invoice->frequency_id = $data['frequency_id'] ? $data['frequency_id'] : 0;
$invoice->start_date = Utils::toSqlDate($data['start_date']);
$invoice->end_date = Utils::toSqlDate($data['end_date']);
$invoice->due_date = null;
$invoice->auto_bill = isset($data['auto_bill']) && $data['auto_bill'] ? true : false;
if (isset($data['show_last_sent_date']) && $data['show_last_sent_date']
&& isset($data['last_sent_date']) && $data['last_sent_date']) {
$invoice->last_sent_date = Utils::toSqlDate($data['last_sent_date']);
}
} else {
$invoice->due_date = isset($data['due_date_sql']) ? $data['due_date_sql'] : Utils::toSqlDate($data['due_date']);
$invoice->frequency_id = 0;

View File

@ -68,6 +68,8 @@ class TaskRepository
$timeLog = [];
}
array_multisort($timeLog);
if (isset($data['action'])) {
if ($data['action'] == 'start') {
$task->is_running = true;

View File

@ -62,7 +62,7 @@ class PaymentService {
} elseif (Session::get($key)) {
$data = Session::get($key);
} else {
$data = [];
$data = $this->createDataForClient($invitation);
}
$card = new CreditCard($data);
@ -74,6 +74,8 @@ class PaymentService {
'returnUrl' => URL::to('complete'),
'cancelUrl' => $invitation->getLink(),
'description' => trans('texts.' . $invoice->getEntityType()) . " {$invoice->invoice_number}",
'transactionId' => $invoice->invoice_number,
'transactionType' => 'Purchase',
];
}
@ -110,6 +112,34 @@ class PaymentService {
return $data;
}
public function createDataForClient($invitation)
{
$invoice = $invitation->invoice;
$client = $invoice->client;
$contact = $invitation->contact ?: $client->contacts()->first();
return [
'email' => $contact->email,
'company' => $client->getDisplayName(),
'firstName' => $contact->first_name,
'lastName' => $contact->last_name,
'billingAddress1' => $client->address1,
'billingAddress2' => $client->address2,
'billingCity' => $client->city,
'billingPostcode' => $client->postal_code,
'billingState' => $client->state,
'billingCountry' => $client->country->iso_3166_2,
'billingPhone' => $contact->phone,
'shippingAddress1' => $client->address1,
'shippingAddress2' => $client->address2,
'shippingCity' => $client->city,
'shippingPostcode' => $client->postal_code,
'shippingState' => $client->state,
'shippingCountry' => $client->country->iso_3166_2,
'shippingPhone' => $contact->phone,
];
}
public function createToken($gateway, $details, $accountGateway, $client, $contactId)
{
$tokenResponse = $gateway->createCard($details)->send();

View File

@ -37,7 +37,7 @@
"guzzlehttp/guzzle": "~5.0",
"laravelcollective/html": "~5.0",
"wildbit/laravel-postmark-provider": "dev-master",
"Dwolla/omnipay-dwolla": "dev-master"
"Dwolla/omnipay-dwolla": "dev-master"
},
"require-dev": {
"phpunit/phpunit": "~4.0",

View File

@ -40,10 +40,15 @@ class PaymentLibrariesSeeder extends Seeder
['name' => 'Skrill', 'provider' => 'Skrill', 'payment_library_id' => 1],
['name' => 'BitPay', 'provider' => 'BitPay', 'payment_library_id' => 1],
['name' => 'Dwolla', 'provider' => 'Dwolla', 'payment_library_id' => 1],
['name' => 'Eway Rapid', 'provider' => 'Eway_RapidShared', 'payment_library_id' => 1],
];
foreach ($gateways as $gateway) {
if (!DB::table('gateways')->where('name', '=', $gateway['name'])->get()) {
$record = Gateway::where('name', '=', $gateway['name'])->first();
if ($record) {
$record->provider = $gateway['provider'];
$record->save();
} else {
Gateway::create($gateway);
}
}
@ -86,6 +91,7 @@ class PaymentLibrariesSeeder extends Seeder
['name' => 'Thai baht', 'code' => 'THB', 'symbol' => 'THB ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Nigerian Naira', 'code' => 'NGN', 'symbol' => 'NGN ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Argentine Peso', 'code' => 'ARS', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Bangladeshi Taka', 'code' => 'BDT', 'symbol' => 'Tk', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
];
foreach ($currencies as $currency) {

View File

@ -2404,6 +2404,9 @@ margin-top: 0;
margin-bottom: 0;
padding-top: 10px;
}
.form-control-static {
padding-top: 11px;
}
textarea.form-control {
/*height: auto !important;*/
min-height: 40px;

View File

@ -54,6 +54,9 @@ margin-top: 0;
margin-bottom: 0;
padding-top: 10px;
}
.form-control-static {
padding-top: 11px;
}
textarea.form-control {
/*height: auto !important;*/
min-height: 40px;

View File

@ -31546,6 +31546,14 @@ function doubleDollarSign(str) {
if (!str) return '';
return str.replace(/\$/g, '\$\$\$');
}
function truncate(string, length){
if (string.length > length) {
return string.substring(0, length) + '...';
} else {
return string;
}
};
var NINJA = NINJA || {};
NINJA.TEMPLATES = {
@ -31575,12 +31583,17 @@ function GetPdfMake(invoice, javascript, callback) {
return function (i, node) {
return 0;
};
} else if ((val+'').indexOf('$notFirstAndLastColumn') === 0) {
var parts = val.split(':');
return function (i, node) {
return (i === 0 || i === node.table.widths.length) ? 0 : parseFloat(parts[1]);
};
} else if ((val+'').indexOf('$notFirst') === 0) {
var parts = val.split(':');
return function (i, node) {
return i === 0 ? 0 : parseFloat(parts[1]);
};
} else if ((val+'').indexOf('$amount') === 0) {
} else if ((val+'').indexOf('$amount') === 0) {
var parts = val.split(':');
return function (i, node) {
return parseFloat(parts[1]);
@ -31599,12 +31612,18 @@ function GetPdfMake(invoice, javascript, callback) {
//console.log(javascript);
var dd = JSON.parse(javascript, jsonCallBack);
if (!invoice.is_pro && dd.hasOwnProperty('footer') && dd.footer.hasOwnProperty('columns')) {
dd.footer.columns.push({image: logoImages.imageLogo1, alignment: 'right', width: 130})
var designId = invoice.invoice_design_id;
if (!invoice.is_pro) {
if (designId == NINJA.TEMPLATES.CLEAN || designId == NINJA.TEMPLATES.NORMAL) {
dd.footer.columns.push({image: logoImages.imageLogo1, alignment: 'right', width: 130, margin: [0, 0, 0, 0]})
} else if (designId == NINJA.TEMPLATES.BOLD) {
dd.footer[1].columns.push({image: logoImages.imageLogo2, alignment: 'right', width: 130, margin: [0, -20, 20, 0]})
} else if (designId == NINJA.TEMPLATES.MODERN) {
dd.footer[1].columns[0].stack.push({image: logoImages.imageLogo3, alignment: 'left', width: 130, margin: [40, 6, 0, 0]});
}
}
//console.log(JSON.stringify(dd));
//console.log(JSON.stringify(dd.footer[1].columns));
/*
var fonts = {
@ -31640,6 +31659,7 @@ NINJA.decodeJavascript = function(invoice, javascript)
'invoiceLineItems': NINJA.invoiceLines(invoice),
'invoiceLineItemColumns': NINJA.invoiceColumns(invoice),
'quantityWidth': NINJA.quantityWidth(invoice),
'taxWidth': NINJA.taxWidth(invoice),
'clientDetails': NINJA.clientDetails(invoice),
'notesAndTerms': NINJA.notesAndTerms(invoice),
'subtotals': NINJA.subtotals(invoice),
@ -31647,7 +31667,7 @@ NINJA.decodeJavascript = function(invoice, javascript)
'subtotalsWithoutBalance': NINJA.subtotals(invoice, true),
'subtotalsBalance': NINJA.subtotalsBalance(invoice),
'balanceDue': formatMoney(invoice.balance_amount, invoice.client.currency_id),
'invoiceFooter': invoice.invoice_footer || ' ',
'invoiceFooter': NINJA.invoiceFooter(invoice),
'invoiceNumber': invoice.invoice_number || ' ',
'entityType': invoice.is_quote ? invoiceLabels.quote : invoiceLabels.invoice,
'entityTypeUC': (invoice.is_quote ? invoiceLabels.quote : invoiceLabels.invoice).toUpperCase(),
@ -31658,7 +31678,7 @@ NINJA.decodeJavascript = function(invoice, javascript)
for (var key in json) {
// remove trailing commas for these fields
if (['quantityWidth'].indexOf(key) >= 0) {
if (['quantityWidth', 'taxWidth'].indexOf(key) >= 0) {
var regExp = new RegExp('"\\$'+key+'",', 'g');
val = json[key];
} else {
@ -31754,11 +31774,25 @@ NINJA.invoiceColumns = function(invoice)
return columns;
}
NINJA.invoiceFooter = function(invoice)
{
if (!invoice.is_pro && invoice.invoice_design_id == 3) {
return invoice.invoice_footer ? invoice.invoice_footer.substring(0, 200) : ' ';
} else {
return invoice.invoice_footer || ' ';
}
}
NINJA.quantityWidth = function(invoice)
{
return invoice.account.hide_quantity == '1' ? '' : '"14%", ';
}
NINJA.taxWidth = function(invoice)
{
return invoice.account.show_item_taxes == '1' ? '"14%", ' : '';
}
NINJA.invoiceLines = function(invoice) {
var total = 0;
var shownItem = false;

View File

@ -27,12 +27,17 @@ function GetPdfMake(invoice, javascript, callback) {
return function (i, node) {
return 0;
};
} else if ((val+'').indexOf('$notFirstAndLastColumn') === 0) {
var parts = val.split(':');
return function (i, node) {
return (i === 0 || i === node.table.widths.length) ? 0 : parseFloat(parts[1]);
};
} else if ((val+'').indexOf('$notFirst') === 0) {
var parts = val.split(':');
return function (i, node) {
return i === 0 ? 0 : parseFloat(parts[1]);
};
} else if ((val+'').indexOf('$amount') === 0) {
} else if ((val+'').indexOf('$amount') === 0) {
var parts = val.split(':');
return function (i, node) {
return parseFloat(parts[1]);
@ -51,12 +56,18 @@ function GetPdfMake(invoice, javascript, callback) {
//console.log(javascript);
var dd = JSON.parse(javascript, jsonCallBack);
if (!invoice.is_pro && dd.hasOwnProperty('footer') && dd.footer.hasOwnProperty('columns')) {
dd.footer.columns.push({image: logoImages.imageLogo1, alignment: 'right', width: 130})
var designId = invoice.invoice_design_id;
if (!invoice.is_pro) {
if (designId == NINJA.TEMPLATES.CLEAN || designId == NINJA.TEMPLATES.NORMAL) {
dd.footer.columns.push({image: logoImages.imageLogo1, alignment: 'right', width: 130, margin: [0, 0, 0, 0]})
} else if (designId == NINJA.TEMPLATES.BOLD) {
dd.footer[1].columns.push({image: logoImages.imageLogo2, alignment: 'right', width: 130, margin: [0, -20, 20, 0]})
} else if (designId == NINJA.TEMPLATES.MODERN) {
dd.footer[1].columns[0].stack.push({image: logoImages.imageLogo3, alignment: 'left', width: 130, margin: [40, 6, 0, 0]});
}
}
//console.log(JSON.stringify(dd));
//console.log(JSON.stringify(dd.footer[1].columns));
/*
var fonts = {
@ -92,6 +103,7 @@ NINJA.decodeJavascript = function(invoice, javascript)
'invoiceLineItems': NINJA.invoiceLines(invoice),
'invoiceLineItemColumns': NINJA.invoiceColumns(invoice),
'quantityWidth': NINJA.quantityWidth(invoice),
'taxWidth': NINJA.taxWidth(invoice),
'clientDetails': NINJA.clientDetails(invoice),
'notesAndTerms': NINJA.notesAndTerms(invoice),
'subtotals': NINJA.subtotals(invoice),
@ -99,7 +111,7 @@ NINJA.decodeJavascript = function(invoice, javascript)
'subtotalsWithoutBalance': NINJA.subtotals(invoice, true),
'subtotalsBalance': NINJA.subtotalsBalance(invoice),
'balanceDue': formatMoney(invoice.balance_amount, invoice.client.currency_id),
'invoiceFooter': invoice.invoice_footer || ' ',
'invoiceFooter': NINJA.invoiceFooter(invoice),
'invoiceNumber': invoice.invoice_number || ' ',
'entityType': invoice.is_quote ? invoiceLabels.quote : invoiceLabels.invoice,
'entityTypeUC': (invoice.is_quote ? invoiceLabels.quote : invoiceLabels.invoice).toUpperCase(),
@ -110,7 +122,7 @@ NINJA.decodeJavascript = function(invoice, javascript)
for (var key in json) {
// remove trailing commas for these fields
if (['quantityWidth'].indexOf(key) >= 0) {
if (['quantityWidth', 'taxWidth'].indexOf(key) >= 0) {
var regExp = new RegExp('"\\$'+key+'",', 'g');
val = json[key];
} else {
@ -206,11 +218,25 @@ NINJA.invoiceColumns = function(invoice)
return columns;
}
NINJA.invoiceFooter = function(invoice)
{
if (!invoice.is_pro && invoice.invoice_design_id == 3) {
return invoice.invoice_footer ? invoice.invoice_footer.substring(0, 200) : ' ';
} else {
return invoice.invoice_footer || ' ';
}
}
NINJA.quantityWidth = function(invoice)
{
return invoice.account.hide_quantity == '1' ? '' : '"14%", ';
}
NINJA.taxWidth = function(invoice)
{
return invoice.account.show_item_taxes == '1' ? '"14%", ' : '';
}
NINJA.invoiceLines = function(invoice) {
var total = 0;
var shownItem = false;

View File

@ -1667,4 +1667,12 @@ function getDescendantProp(obj, desc) {
function doubleDollarSign(str) {
if (!str) return '';
return str.replace(/\$/g, '\$\$\$');
}
}
function truncate(string, length){
if (string.length > length) {
return string.substring(0, length) + '...';
} else {
return string;
}
};

View File

@ -185,7 +185,7 @@
'users' => 'Brugere',
'localization' => 'Lokalisering',
'remove_logo' => 'Fjern logo',
'logo_help' => 'Understøttede filtyper: JPEG, GIF og PNG. Anbefalet størrelse: 200px bredde og 120px højde',
'logo_help' => 'Understøttede filtyper: JPEG, GIF og PNG',
'payment_gateway' => 'Betalingsløsning',
'gateway_id' => 'Kort betalings udbyder',
'email_notifications' => 'Notifikation via e-mail',
@ -788,6 +788,9 @@
'reset' => 'Reset',
'invoice_not_found' => 'The requested invoice is not available',
'referral_program' => 'Referral Program',
'referral_code' => 'Referral Code',
'last_sent_on' => 'Last sent on :date',
);

View File

@ -185,7 +185,7 @@ return array(
'users' => 'Benutzer',
'localization' => 'Lokalisierung',
'remove_logo' => 'Logo entfernen',
'logo_help' => 'Unterstützt: JPEG, GIF und PNG. Empfohlene Höhe: 120px',
'logo_help' => 'Unterstützt: JPEG, GIF und PNG',
'payment_gateway' => 'Zahlungseingang',
'gateway_id' => 'Provider',
'email_notifications' => 'E-Mail Benachrichtigungen',
@ -787,6 +787,9 @@ return array(
'reset' => 'Reset',
'invoice_not_found' => 'The requested invoice is not available',
'referral_program' => 'Referral Program',
'referral_code' => 'Referral Code',
'last_sent_on' => 'Last sent on :date',
);

View File

@ -185,7 +185,7 @@ return array(
'users' => 'Users',
'localization' => 'Localization',
'remove_logo' => 'Remove logo',
'logo_help' => 'Supported: JPEG, GIF and PNG. Recommended size: 200px width by 120px height',
'logo_help' => 'Supported: JPEG, GIF and PNG',
'payment_gateway' => 'Payment Gateway',
'gateway_id' => 'Gateway',
'email_notifications' => 'Email Notifications',
@ -672,7 +672,7 @@ return array(
'counter' => 'Counter',
'payment_type_dwolla' => 'Dwolla',
'gateway_help_43' => ':link to sign up for Dwolla.',
'gateway_help_43' => ':link to sign up for Dwolla.<br/>Note: remove dashes from the Destination/Dwolla Id',
'partial_value' => 'Must be greater than zero and less than the total',
'more_actions' => 'More Actions',
@ -765,7 +765,7 @@ return array(
'status_viewed' => 'Viewed',
'status_partial' => 'Partial',
'status_paid' => 'Paid',
'show_line_item_tax' => 'Display <b>line item taxes</b> inline',
'show_line_item_tax' => 'Display <b>line item taxes inline</b>',
'iframe_url' => 'Website',
'iframe_url_help1' => 'Copy the following code to a page on your site.',
@ -787,6 +787,9 @@ return array(
'reset' => 'Reset',
'invoice_not_found' => 'The requested invoice is not available',
'referral_program' => 'Referral Program',
'referral_code' => 'Referral Code',
'last_sent_on' => 'Last sent on :date',
);

View File

@ -184,7 +184,7 @@ return array(
'users' => 'Usuarios',
'localization' => 'Localización',
'remove_logo' => 'Eliminar logo',
'logo_help' => 'Formatos aceptados: JPEG, GIF y PNG. Altura recomendada: 120px',
'logo_help' => 'Formatos aceptados: JPEG, GIF y PNG',
'payment_gateway' => 'Pasarela de pago',
'gateway_id' => 'Proveedor',
'email_notifications' => 'Notificaciones de email',
@ -765,6 +765,9 @@ return array(
'reset' => 'Reset',
'invoice_not_found' => 'The requested invoice is not available',
'referral_program' => 'Referral Program',
'referral_code' => 'Referral Code',
'last_sent_on' => 'Last sent on :date',
);

View File

@ -196,7 +196,7 @@ return array(
'users' => 'Usuarios',
'localization' => 'Localización',
'remove_logo' => 'Eliminar logo',
'logo_help' => 'Formatos aceptados: JPEG, GIF y PNG. Altura recomendada: 120px',
'logo_help' => 'Formatos aceptados: JPEG, GIF y PNG',
'payment_gateway' => 'Pasarela de pago',
'gateway_id' => 'Proveedor',
'email_notifications' => 'Notificaciones de email',
@ -787,6 +787,9 @@ return array(
'reset' => 'Reset',
'invoice_not_found' => 'The requested invoice is not available',
'referral_program' => 'Referral Program',
'referral_code' => 'Referral Code',
'last_sent_on' => 'Last sent on :date',
);

View File

@ -185,7 +185,7 @@ return array(
'users' => 'Utilisateurs',
'localization' => 'Localisation',
'remove_logo' => 'Supprimer le logo',
'logo_help' => 'Formats supportés: JPEG, GIF et PNG. Hauteur recommandé: 120px',
'logo_help' => 'Formats supportés: JPEG, GIF et PNG',
'payment_gateway' => 'Passerelle de paiement',
'gateway_id' => 'Fournisseur',
'email_notifications' => 'Notifications par courriel',
@ -779,6 +779,9 @@ return array(
'reset' => 'Reset',
'invoice_not_found' => 'The requested invoice is not available',
'referral_program' => 'Referral Program',
'referral_code' => 'Referral Code',
'last_sent_on' => 'Last sent on :date',
);

View File

@ -185,7 +185,7 @@ return array(
'users' => 'Utilisateurs',
'localization' => 'Localisation',
'remove_logo' => 'Supprimer le logo',
'logo_help' => 'Formats supportés: JPEG, GIF et PNG. Hauteur recommandé: 120px',
'logo_help' => 'Formats supportés: JPEG, GIF et PNG',
'payment_gateway' => 'Passerelle de paiement',
'gateway_id' => 'Fournisseur',
'email_notifications' => 'Notifications par courriel',
@ -780,6 +780,9 @@ return array(
'reset' => 'Reset',
'invoice_not_found' => 'The requested invoice is not available',
'referral_program' => 'Referral Program',
'referral_code' => 'Referral Code',
'last_sent_on' => 'Last sent on :date',
);

View File

@ -185,7 +185,7 @@ return array(
'users' => 'Utenti',
'localization' => 'Localizzazione',
'remove_logo' => 'Rimuovi logo',
'logo_help' => 'Supportati: JPEG, GIF e PNG. Altezza raccomandata: 120px',
'logo_help' => 'Supportati: JPEG, GIF e PNG',
'payment_gateway' => 'Servizi di Pagamento',
'gateway_id' => 'Piattaforma',
'email_notifications' => 'Notifiche Email',
@ -782,5 +782,8 @@ return array(
'reset' => 'Reset',
'invoice_not_found' => 'The requested invoice is not available',
'referral_program' => 'Referral Program',
'referral_code' => 'Referral Code',
'last_sent_on' => 'Last sent on :date',
);

View File

@ -185,7 +185,7 @@ return array(
'users' => 'Users',
'localization' => 'Localization',
'remove_logo' => 'Remove logo',
'logo_help' => 'Supported: JPEG, GIF and PNG. Recommended size: 200px width by 120px height',
'logo_help' => 'Supported: JPEG, GIF and PNG',
'payment_gateway' => 'Payment Gateway',
'gateway_id' => 'Provider',
'email_notifications' => 'Email Notifications',
@ -790,6 +790,9 @@ return array(
'invoice_not_found' => 'The requested invoice is not available',
'referral_program' => 'Referral Program',
'referral_code' => 'Referral Code',
'last_sent_on' => 'Last sent on :date',
);

View File

@ -185,7 +185,7 @@ return array(
'users' => 'Brukere',
'localization' => 'Lokaliseing',
'remove_logo' => 'Fjern logo',
'logo_help' => 'St&#248;ttedefiltyper: JPEG, GIF og PNG. Anbefalt st&#248;rrelse: 200px bredde by 120px h&#248;yde',
'logo_help' => 'St&#248;ttedefiltyper: JPEG, GIF og PNG',
'payment_gateway' => 'Betalingsl&#248;sning',
'gateway_id' => 'Tilbyder',
'email_notifications' => 'Varsel via email',
@ -787,6 +787,9 @@ return array(
'reset' => 'Reset',
'invoice_not_found' => 'The requested invoice is not available',
'referral_program' => 'Referral Program',
'referral_code' => 'Referral Code',
'last_sent_on' => 'Last sent on :date',
);

View File

@ -184,7 +184,7 @@ return array(
'users' => 'Gebruikers',
'localization' => 'Localisatie',
'remove_logo' => 'Verwijder logo',
'logo_help' => 'Ondersteund: JPEG, GIF en PNG. Aangeraden hoogte: 120px',
'logo_help' => 'Ondersteund: JPEG, GIF en PNG',
'payment_gateway' => 'Betalingsmiddel',
'gateway_id' => 'Leverancier',
'email_notifications' => 'E-mail meldingen',
@ -782,5 +782,8 @@ return array(
'reset' => 'Reset',
'invoice_not_found' => 'The requested invoice is not available',
'referral_program' => 'Referral Program',
'referral_code' => 'Referral Code',
'last_sent_on' => 'Last sent on :date',
);

View File

@ -183,7 +183,7 @@ return array(
'users' => 'Usuários',
'localization' => 'Localização',
'remove_logo' => 'Remover logo',
'logo_help' => 'Suportados: JPEG, GIF and PNG. Altura recomendada: 120px',
'logo_help' => 'Suportados: JPEG, GIF and PNG',
'payment_gateway' => 'Provedor de Pagamento',
'gateway_id' => 'Provedor',
'email_notifications' => 'Notificações por Email',
@ -782,5 +782,8 @@ return array(
'reset' => 'Reset',
'invoice_not_found' => 'The requested invoice is not available',
'referral_program' => 'Referral Program',
'referral_code' => 'Referral Code',
'last_sent_on' => 'Last sent on :date',
);

View File

@ -185,7 +185,7 @@ return array(
'users' => 'Användare',
'localization' => 'Språkanpassning',
'remove_logo' => 'Ta bort logga',
'logo_help' => 'Giltiga format: JPEG, GIF och PNG. Rekommenderad storlek: 200 x 120 pixlar (BxH)',
'logo_help' => 'Giltiga format: JPEG, GIF och PNG',
'payment_gateway' => 'Betalningstjänst',
'gateway_id' => 'Tjänst',
'email_notifications' => 'Notifieringar',
@ -785,6 +785,9 @@ return array(
'reset' => 'Reset',
'invoice_not_found' => 'The requested invoice is not available',
'referral_program' => 'Referral Program',
'referral_code' => 'Referral Code',
'last_sent_on' => 'Last sent on :date',
);

View File

@ -86,14 +86,25 @@
{!! Former::text('last_name') !!}
{!! Former::text('email') !!}
{!! Former::text('phone') !!}
@if (Utils::isNinjaDev())
{!! Former::checkbox('dark_mode')->text(trans('texts.dark_mode_help')) !!}
@if (Utils::isNinja() && $primaryUser->confirmed)
@if ($primaryUser->referral_code)
{!! Former::plaintext('referral_code')
->value($primaryUser->referral_code . ' <a href="'.REFERRAL_PROGRAM_URL.'" target="_blank" title="'.trans('texts.learn_more').'">' . Icon::create('question-sign') . '</a>') !!}
@else
{!! Former::checkbox('referral_code')
->text(trans('texts.enable') . ' <a href="'.REFERRAL_PROGRAM_URL.'" target="_blank" title="'.trans('texts.learn_more').'">' . Icon::create('question-sign') . '</a>') !!}
@endif
@endif
@if (false && Utils::isNinjaDev())
{!! Former::checkbox('dark_mode')->text(trans('texts.dark_mode_help')) !!}
@endif
@if (Auth::user()->confirmed)
{!! Former::actions( Button::primary(trans('texts.change_password'))->small()->withAttributes(['onclick'=>'showChangePassword()'])) !!}
@elseif (Auth::user()->registered)
{!! Former::actions( Button::primary(trans('texts.resend_confirmation'))->asLinkTo(URL::to('/resend_confirmation'))->small() ) !!}
@if (Utils::isNinja())
@if (Auth::user()->confirmed)
{!! Former::actions( Button::primary(trans('texts.change_password'))->small()->withAttributes(['onclick'=>'showChangePassword()'])) !!}
@elseif (Auth::user()->registered)
{!! Former::actions( Button::primary(trans('texts.resend_confirmation'))->asLinkTo(URL::to('/resend_confirmation'))->small() ) !!}
@endif
@endif
</div>
</div>

View File

@ -72,10 +72,12 @@
<h3 class="panel-title">{!! trans('texts.email_settings') !!}</h3>
</div>
<div class="panel-body">
{{ Former::setOption('capitalize_translations', false) }}
{!! Former::text('subdomain')->placeholder(trans('texts.www'))->onchange('onSubdomainChange()') !!}
{!! Former::text('iframe_url')->placeholder('http://invoices.example.com/')
->onchange('onDomainChange()')->appendIcon('question-sign')->addGroupClass('iframe_url') !!}
@if (Utils::isNinja())
{{ Former::setOption('capitalize_translations', false) }}
{!! Former::text('subdomain')->placeholder(trans('texts.www'))->onchange('onSubdomainChange()') !!}
{!! Former::text('iframe_url')->placeholder('http://invoices.example.com/')
->onchange('onDomainChange()')->appendIcon('question-sign')->addGroupClass('iframe_url') !!}
@endif
{!! Former::checkbox('pdf_email_attachment')->text(trans('texts.enable')) !!}
</div>
</div>
@ -130,9 +132,9 @@
<div class="modal-body">
<p>{{ trans('texts.iframe_url_help1') }}</p>
<pre>&lt;iframe id="iFrame" width="800" height="1000"&gt;&lt;/iframe&gt;
<pre>&lt;iframe id="invoiceIFrame" width="800" height="1000"&gt;&lt;/iframe&gt;
&lt;script language="javascript"&gt;
var iframe = document.getElementById('iFrame');
var iframe = document.getElementById('invoiceIFrame');
iframe.src = '{{ SITE_URL }}/view/'
+ window.location.search.substring(1);
&lt;/script&gt;</pre>

View File

@ -3,14 +3,19 @@
@if (isset($isReminder) && $isReminder)
<div class="row">
<div class="col-md-6">
{!! Former::checkbox('enable_' . $field)->text(trans('texts.enable'))->label('') !!}
{!! Former::input('num_days_' . $field)->label(trans('texts.num_days_reminder')) !!}
{!! Former::checkbox('enable_' . $field)
->text(trans('texts.enable'))->label('') !!}
{!! Former::input('num_days_' . $field)
->label(trans('texts.num_days_reminder'))
->addClass('enable-' . $field) !!}
</div>
</div>
@endif
<div class="row">
<div class="col-md-6">
{!! Former::text('email_subject_' . $field)->label(trans('texts.subject')) !!}
{!! Former::text('email_subject_' . $field)
->label(trans('texts.subject'))
->addClass('enable-' . $field) !!}
<div class="pull-right"><a href="#" onclick="return resetText('{{ 'subject' }}', '{{ $field }}')">{{ trans("texts.reset") }}</a></div>
</div>
<div class="col-md-6">
@ -20,7 +25,9 @@
</div>
<div class="row">
<div class="col-md-6">
{!! Former::textarea('email_template_' . $field)->label(trans('texts.body')) !!}
{!! Former::textarea('email_template_' . $field)
->label(trans('texts.body'))
->addClass('enable-' . $field) !!}
<div class="pull-right"><a href="#" onclick="return resetText('{{ 'template' }}', '{{ $field }}')">{{ trans("texts.reset") }}</a></div>
</div>
<div class="col-md-6">

View File

@ -93,7 +93,7 @@
var entityTypes = ['invoice', 'quote', 'payment', 'reminder1', 'reminder2', 'reminder3'];
var stringTypes = ['subject', 'template'];
var templates = {!! json_encode($templates) !!};
var templates = {!! json_encode($defaultTemplates) !!};
function refreshPreview() {
for (var i=0; i<entityTypes.length; i++) {
@ -109,7 +109,6 @@
}
$(function() {
for (var i=0; i<entityTypes.length; i++) {
var entityType = entityTypes[i];
for (var j=0; j<stringTypes.length; j++) {
@ -118,9 +117,22 @@
$(idName).keyup(refreshPreview);
}
}
for (var i=1; i<=3; i++) {
$('#enable_reminder' + i).bind('click', {id: i}, function(event) {
enableReminder(event.data.id)
});
enableReminder(i);
}
refreshPreview();
});
function enableReminder(id) {
var checked = $('#enable_reminder' + id).is(':checked');
$('.enable-reminder' + id).attr('disabled', !checked)
}
function processVariables(str) {
if (!str) {
return '';

View File

@ -101,20 +101,8 @@
{!! trans('texts.created_by_invoice', ['invoice' => link_to('/invoices/'.$invoice->recurring_invoice->public_id, trans('texts.recurring_invoice'))]) !!}
</div>
@elseif ($invoice && isset($lastSent) && $lastSent)
<div class="form-group" data-bind="visible: !show_last_sent_date()" >
<label for="client" class="control-label col-lg-4 col-sm-4">{{ trans('texts.last_sent') }}</label>
<div class="col-lg-8 col-sm-8">
<div style="padding-top:10px">
<a href="#" data-bind="click: $root.clickLastSentDate">{{ Utils::dateToString($invoice->last_sent_date) }}</a> -
{!! link_to('/invoices/'.$lastSent->public_id, trans('texts.view_invoice'), ['id' => 'lastInvoiceSent']) !!}
</div>
</div>
</div>
<div data-bind="visible: show_last_sent_date()" style="display:none">
{!! Former::text('last_sent_date')->data_bind("datePicker: last_sent_date, valueUpdate: 'afterkeydown', visible: show_last_sent_date()")
->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT, DEFAULT_DATE_PICKER_FORMAT))
->label(trans('texts.last_sent'))
->appendIcon('calendar')->addGroupClass('last_sent_date') !!}
<div class="pull-right" style="padding-top: 6px">
{!! trans('texts.last_sent_on', ['date' => link_to('/invoices/'.$lastSent->public_id, Utils::dateToString($invoice->last_sent_date))]) !!}
</div>
@endif
@endif
@ -192,8 +180,8 @@
<td style="text-align:right;padding-top:9px !important">
<div class="line-total" data-bind="text: totals.total"></div>
</td>
<td style="cursor:pointer" class="hide-border td-icon"> &nbsp;
<i style="display:none" data-bind="click: $parent.removeItem, visible: actionsVisible() &amp;&amp;
<td style="cursor:pointer" class="hide-border td-icon">
<i style="display:none;padding-left:4px" data-bind="click: $parent.removeItem, visible: actionsVisible() &amp;&amp;
$index() < ($parent.invoice_items().length - 1) &amp;&amp;
$parent.invoice_items().length > 1" class="fa fa-minus-circle redlink" title="Remove item"/>
</td>
@ -966,10 +954,6 @@
self.invoice = ko.observable(data ? false : new InvoiceModel());
self.tax_rates = ko.observableArray();
self.clickLastSentDate = function() {
self.invoice().show_last_sent_date(true);
}
self.loadClient = function(client) {
ko.mapping.fromJS(client, model.invoice().client().mapping, model.invoice().client);
@if (!$invoice)
@ -1217,7 +1201,6 @@
self.invoice_design_id = ko.observable({{ $account->invoice_design_id }});
self.partial = ko.observable(0);
self.has_tasks = ko.observable(false);
self.show_last_sent_date = ko.observable(false);
self.custom_value1 = ko.observable(0);
self.custom_value2 = ko.observable(0);
@ -1641,7 +1624,7 @@
this.prettyRate = ko.computed({
read: function () {
return this.rate() ? this.rate() : '';
return this.rate() ? roundToTwo(this.rate()) : '';
},
write: function (value) {
this.rate(value);

View File

@ -112,10 +112,10 @@
@yield('body')
<script type="text/javascript">
NINJA.formIsChanged = false;
NINJA.formIsChanged = {{ isset($formIsChanged) && $formIsChanged ? 'true' : 'false' }};
$(function() {
$('form.warn-on-exit input, form.warn-on-exit textarea, form.warn-on-exit select').change(function() {
NINJA.formIsChanged = true;
NINJA.formIsChanged = true;
});
@if (Session::has('trackEventCategory') && Session::has('trackEventAction'))

View File

@ -39,7 +39,7 @@
"style": "invoiceLineItemsTable",
"table": {
"headerRows": 1,
"widths": ["15%", "*", "14%", "$quantityWidth", "22%"],
"widths": ["22%", "*", "14%", "$quantityWidth", "$taxWidth", "22%"],
"body": "$invoiceLineItems"
},
"layout": {
@ -74,13 +74,19 @@
}]
}
],
"footer": [
{"canvas": [{ "type": "line", "x1": 0, "y1": 0, "x2": 600, "y2": 0,"lineWidth": 100,"lineColor":"$secondaryColor:#2e2b2b"}]},
"footer":
[
{"canvas": [{ "type": "line", "x1": 0, "y1": 0, "x2": 600, "y2": 0,"lineWidth": 100,"lineColor":"$secondaryColor:#292526"}]},
{
"text": "$invoiceFooter",
"margin": [40, 0, 40, 0],
"alignment": "left",
"color": "#FFFFFF"
"columns":
[
{
"text": "$invoiceFooter",
"margin": [40, -40, 40, 0],
"alignment": "left",
"color": "#FFFFFF"
}
]
}
],
"header": [
@ -93,7 +99,7 @@
"x2": 600,
"y2": 0,
"lineWidth": 200,
"lineColor": "$secondaryColor:#2e2b2b"
"lineColor": "$secondaryColor:#292526"
}
],
"width": 10
@ -209,7 +215,7 @@
},
"invoiceLineItemsTable": {
"margin": [0, 26, 0, 16]
},
},
"clientName": {
"bold": true
},
@ -229,11 +235,11 @@
"subtotals": {
"alignment": "right",
"margin": [0,0,40,0]
},
},
"termsLabel": {
"bold": true,
"margin": [0, 0, 0, 4]
}
}
},
"pageMargins": [0, 80, 0, 40]
}

View File

@ -30,7 +30,7 @@
"table": {
"body": "$invoiceDetails"
},
"margin": [0, 0, 12, 4],
"margin": [0, 0, 12, 0],
"layout": "noBorders"
},
{
@ -49,7 +49,7 @@
"paddingLeft": "$amount:8",
"paddingRight": "$amount:8",
"paddingTop": "$amount:6",
"paddingBottom": "$amount:2"
"paddingBottom": "$amount:6"
}
},
{

View File

@ -1,20 +1,18 @@
{
"content": [
{
"columns": [
{
"image": "$accountLogo",
"fit": [120, 80],
"margin": [0, 60, 0, 30]
"columns": [
{
"image": "$accountLogo",
"fit": [120, 80],
"margin": [0, 60, 0, 30]
},
{
"stack": "$clientDetails",
"margin": [260, 80, 0, 0]
}
]
},
{
"stack": "$clientDetails",
"margin": [260, 80, 0, 0]
}
]
},
{
"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": {
@ -24,8 +22,9 @@
},
"layout": {
"hLineWidth": "$notFirst:.5",
"vLineWidth": "$none",
"vLineWidth": "$notFirstAndLastColumn:.5",
"hLineColor": "#888888",
"vLineColor": "#FFFFFF",
"paddingLeft": "$amount:8",
"paddingRight": "$amount:8",
"paddingTop": "$amount:8",
@ -92,17 +91,22 @@
"canvas": [
{
"type": "line", "x1": 0, "y1": 0, "x2": 600, "y2": 0,"lineWidth": 100,"lineColor":"$primaryColor:#f26621"
}]
,"width":10
},
{
}]
,"width":10
},
{
"columns": [
{
"text": "$invoiceFooter",
"margin": [40, -30, 40, 0],
"alignment": "left",
"color": "#FFFFFF",
"width": 350
{
"width": 350,
"stack": [
{
"text": "$invoiceFooter",
"margin": [40, -40, 40, 0],
"alignment": "left",
"color": "#FFFFFF"
}
]
},
{
"stack": "$accountDetails",
@ -175,7 +179,8 @@
"tableHeader": {
"bold": true,
"color": "#FFFFFF",
"fontSize": "$fontSizeLargest"
"fontSize": "$fontSizeLargest",
"fillColor": "$secondaryColor:#403d3d"
},
"costTableHeader": {
"alignment": "right"