mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Bug fixes
This commit is contained in:
parent
5a28ff2612
commit
b368e5589c
@ -1,5 +1,8 @@
|
|||||||
<?php namespace App\Console\Commands;
|
<?php namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use DB;
|
||||||
|
use DateTime;
|
||||||
|
use Carbon;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
@ -10,7 +13,7 @@ use Symfony\Component\Console\Input\InputArgument;
|
|||||||
WARNING: Please backup your database before running this script
|
WARNING: Please backup your database before running this script
|
||||||
##################################################################
|
##################################################################
|
||||||
|
|
||||||
Since the application was released a number of bugs have (inevitably) been found.
|
Since the application was released a number of bugs have inevitably been found.
|
||||||
Although the bugs have always been fixed in some cases they've caused the client's
|
Although the bugs have always been fixed in some cases they've caused the client's
|
||||||
balance, paid to date and/or activity records to become inaccurate. This script will
|
balance, paid to date and/or activity records to become inaccurate. This script will
|
||||||
check for errors and correct the data.
|
check for errors and correct the data.
|
||||||
@ -100,13 +103,15 @@ class CheckData extends Command {
|
|||||||
|
|
||||||
$clients = $clients->groupBy('clients.id', 'clients.balance', 'clients.created_at')
|
$clients = $clients->groupBy('clients.id', 'clients.balance', 'clients.created_at')
|
||||||
->orderBy('clients.id', 'DESC')
|
->orderBy('clients.id', 'DESC')
|
||||||
->get(['clients.id', 'clients.balance', 'clients.paid_to_date']);
|
->get(['clients.account_id', 'clients.id', 'clients.balance', 'clients.paid_to_date', DB::raw('sum(invoices.balance) actual_balance')]);
|
||||||
$this->info(count($clients) . ' clients with incorrect balance/activities');
|
$this->info(count($clients) . ' clients with incorrect balance/activities');
|
||||||
|
|
||||||
foreach ($clients as $client) {
|
foreach ($clients as $client) {
|
||||||
$this->info("=== Client:{$client->id} Balance:{$client->balance} ===");
|
$this->info("=== Client:{$client->id} Balance:{$client->balance} Actual Balance:{$client->actual_balance} ===");
|
||||||
$foundProblem = false;
|
$foundProblem = false;
|
||||||
$lastBalance = 0;
|
$lastBalance = 0;
|
||||||
|
$lastAdjustment = 0;
|
||||||
|
$lastCreatedAt = null;
|
||||||
$clientFix = false;
|
$clientFix = false;
|
||||||
$activities = DB::table('activities')
|
$activities = DB::table('activities')
|
||||||
->where('client_id', '=', $client->id)
|
->where('client_id', '=', $client->id)
|
||||||
@ -195,6 +200,11 @@ class CheckData extends Command {
|
|||||||
$foundProblem = true;
|
$foundProblem = true;
|
||||||
$clientFix -= $activity->adjustment;
|
$clientFix -= $activity->adjustment;
|
||||||
$activityFix = 0;
|
$activityFix = 0;
|
||||||
|
} else if ((strtotime($activity->created_at) - strtotime($lastCreatedAt) <= 1) && $activity->adjustment > 0 && $activity->adjustment == $lastAdjustment) {
|
||||||
|
$this->info("Duplicate adjustment for updated invoice adjustment:{$activity->adjustment}");
|
||||||
|
$foundProblem = true;
|
||||||
|
$clientFix -= $activity->adjustment;
|
||||||
|
$activityFix = 0;
|
||||||
}
|
}
|
||||||
} elseif ($activity->activity_type_id == ACTIVITY_TYPE_UPDATE_QUOTE) {
|
} elseif ($activity->activity_type_id == ACTIVITY_TYPE_UPDATE_QUOTE) {
|
||||||
// **Fix for updating balance when updating a quote**
|
// **Fix for updating balance when updating a quote**
|
||||||
@ -231,19 +241,33 @@ class CheckData extends Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$lastBalance = $activity->balance;
|
$lastBalance = $activity->balance;
|
||||||
|
$lastAdjustment = $activity->adjustment;
|
||||||
|
$lastCreatedAt = $activity->created_at;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($clientFix !== false) {
|
if ($activity->balance + $clientFix != $client->actual_balance) {
|
||||||
$balance = $activity->balance + $clientFix;
|
$this->info("** Creating 'recovered update' activity **");
|
||||||
$data = ['balance' => $balance];
|
if ($this->option('fix') == 'true') {
|
||||||
$this->info("Corrected balance:{$balance}");
|
DB::table('activities')->insert([
|
||||||
|
'created_at' => new Carbon,
|
||||||
|
'updated_at' => new Carbon,
|
||||||
|
'account_id' => $client->account_id,
|
||||||
|
'client_id' => $client->id,
|
||||||
|
'message' => 'Recovered update to invoice [<a href="https://github.com/hillelcoren/invoice-ninja/releases/tag/v1.7.1" target="_blank">details</a>]',
|
||||||
|
'adjustment' => $client->actual_balance - $activity->balance,
|
||||||
|
'balance' => $client->actual_balance,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = ['balance' => $client->actual_balance];
|
||||||
|
$this->info("Corrected balance:{$client->actual_balance}");
|
||||||
if ($this->option('fix') == 'true') {
|
if ($this->option('fix') == 'true') {
|
||||||
DB::table('clients')
|
DB::table('clients')
|
||||||
->where('id', $client->id)
|
->where('id', $client->id)
|
||||||
->update($data);
|
->update($data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
$this->info('Done');
|
$this->info('Done');
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,7 @@ class DashboardController extends BaseController
|
|||||||
|
|
||||||
|
|
||||||
$activities = Activity::where('activities.account_id', '=', Auth::user()->account_id)
|
$activities = Activity::where('activities.account_id', '=', Auth::user()->account_id)
|
||||||
|
->where('activity_type_id', '>', 0)
|
||||||
->orderBy('created_at', 'desc')->take(6)->get();
|
->orderBy('created_at', 'desc')->take(6)->get();
|
||||||
|
|
||||||
$pastDue = Invoice::scope()
|
$pastDue = Invoice::scope()
|
||||||
|
@ -59,8 +59,6 @@ class ReportController extends BaseController
|
|||||||
$enableChart = true;
|
$enableChart = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$padding = $groupBy == 'DAYOFYEAR' ? 'day' : ($groupBy == 'WEEK' ? 'week' : 'month');
|
|
||||||
$endDate->modify('+1 '.$padding);
|
|
||||||
$datasets = [];
|
$datasets = [];
|
||||||
$labels = [];
|
$labels = [];
|
||||||
$maxTotals = 0;
|
$maxTotals = 0;
|
||||||
@ -155,7 +153,7 @@ class ReportController extends BaseController
|
|||||||
if ($enableChart) {
|
if ($enableChart) {
|
||||||
foreach ([ENTITY_INVOICE, ENTITY_PAYMENT, ENTITY_CREDIT] as $entityType) {
|
foreach ([ENTITY_INVOICE, ENTITY_PAYMENT, ENTITY_CREDIT] as $entityType) {
|
||||||
$records = DB::table($entityType.'s')
|
$records = DB::table($entityType.'s')
|
||||||
->select(DB::raw('sum(amount) as total, '.$groupBy.'('.$entityType.'_date) as '.$groupBy))
|
->select(DB::raw('sum(amount) as total, concat(YEAR('.$entityType.'_date), '.$groupBy.'('.$entityType.'_date)) as '.$groupBy))
|
||||||
->where('account_id', '=', Auth::user()->account_id)
|
->where('account_id', '=', Auth::user()->account_id)
|
||||||
->where($entityType.'s.is_deleted', '=', false)
|
->where($entityType.'s.is_deleted', '=', false)
|
||||||
->where($entityType.'s.'.$entityType.'_date', '>=', $startDate->format('Y-m-d'))
|
->where($entityType.'s.'.$entityType.'_date', '>=', $startDate->format('Y-m-d'))
|
||||||
@ -171,14 +169,17 @@ class ReportController extends BaseController
|
|||||||
$dates = $records->lists($groupBy);
|
$dates = $records->lists($groupBy);
|
||||||
$data = array_combine($dates, $totals);
|
$data = array_combine($dates, $totals);
|
||||||
|
|
||||||
|
$padding = $groupBy == 'DAYOFYEAR' ? 'day' : ($groupBy == 'WEEK' ? 'week' : 'month');
|
||||||
|
$endDate->modify('+1 '.$padding);
|
||||||
$interval = new DateInterval('P1'.substr($groupBy, 0, 1));
|
$interval = new DateInterval('P1'.substr($groupBy, 0, 1));
|
||||||
$period = new DatePeriod($startDate, $interval, $endDate);
|
$period = new DatePeriod($startDate, $interval, $endDate);
|
||||||
|
$endDate->modify('-1 '.$padding);
|
||||||
|
|
||||||
$totals = [];
|
$totals = [];
|
||||||
|
|
||||||
foreach ($period as $d) {
|
foreach ($period as $d) {
|
||||||
$dateFormat = $groupBy == 'DAYOFYEAR' ? 'z' : ($groupBy == 'WEEK' ? 'W' : 'n');
|
$dateFormat = $groupBy == 'DAYOFYEAR' ? 'z' : ($groupBy == 'WEEK' ? 'W' : 'n');
|
||||||
$date = $d->format($dateFormat);
|
$date = $d->format('Y'.$dateFormat);
|
||||||
$totals[] = isset($data[$date]) ? $data[$date] : 0;
|
$totals[] = isset($data[$date]) ? $data[$date] : 0;
|
||||||
|
|
||||||
if ($entityType == ENTITY_INVOICE) {
|
if ($entityType == ENTITY_INVOICE) {
|
||||||
@ -228,7 +229,7 @@ class ReportController extends BaseController
|
|||||||
'chartTypes' => $chartTypes,
|
'chartTypes' => $chartTypes,
|
||||||
'chartType' => $chartType,
|
'chartType' => $chartType,
|
||||||
'startDate' => $startDate->format(Session::get(SESSION_DATE_FORMAT)),
|
'startDate' => $startDate->format(Session::get(SESSION_DATE_FORMAT)),
|
||||||
'endDate' => $endDate->modify('-1'.$padding)->format(Session::get(SESSION_DATE_FORMAT)),
|
'endDate' => $endDate->format(Session::get(SESSION_DATE_FORMAT)),
|
||||||
'groupBy' => $groupBy,
|
'groupBy' => $groupBy,
|
||||||
'feature' => ACCOUNT_CHART_BUILDER,
|
'feature' => ACCOUNT_CHART_BUILDER,
|
||||||
'displayData' => $displayData,
|
'displayData' => $displayData,
|
||||||
|
@ -66,8 +66,7 @@ class StartupCheck
|
|||||||
$count = Session::get(SESSION_COUNTER, 0);
|
$count = Session::get(SESSION_COUNTER, 0);
|
||||||
Session::put(SESSION_COUNTER, ++$count);
|
Session::put(SESSION_COUNTER, ++$count);
|
||||||
|
|
||||||
//if (!Utils::startsWith($_SERVER['REQUEST_URI'], '/news_feed') && !Session::has('news_feed_id')) {
|
if (!Utils::startsWith($_SERVER['REQUEST_URI'], '/news_feed') && !Session::has('news_feed_id')) {
|
||||||
if (true) {
|
|
||||||
$data = false;
|
$data = false;
|
||||||
if (Utils::isNinja()) {
|
if (Utils::isNinja()) {
|
||||||
$data = Utils::getNewsFeedResponse();
|
$data = Utils::getNewsFeedResponse();
|
||||||
|
@ -236,9 +236,13 @@ class Utils
|
|||||||
$currencyId = Session::get(SESSION_CURRENCY);
|
$currencyId = Session::get(SESSION_CURRENCY);
|
||||||
}
|
}
|
||||||
|
|
||||||
$currency = Currency::find($currencyId);
|
foreach (Cache::get('currencies') as $currency) {
|
||||||
|
if ($currency->id == $currencyId) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(!$currency){
|
if (!$currency) {
|
||||||
$currency = Currency::find(1);
|
$currency = Currency::find(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -486,7 +490,7 @@ class Utils
|
|||||||
public static function encodeActivity($person = null, $action, $entity = null, $otherPerson = null)
|
public static function encodeActivity($person = null, $action, $entity = null, $otherPerson = null)
|
||||||
{
|
{
|
||||||
$person = $person ? $person->getDisplayName() : '<i>System</i>';
|
$person = $person ? $person->getDisplayName() : '<i>System</i>';
|
||||||
$entity = $entity ? '['.$entity->getActivityKey().']' : '';
|
$entity = $entity ? $entity->getActivityKey() : '';
|
||||||
$otherPerson = $otherPerson ? 'to '.$otherPerson->getDisplayName() : '';
|
$otherPerson = $otherPerson ? 'to '.$otherPerson->getDisplayName() : '';
|
||||||
$token = Session::get('token_id') ? ' ('.trans('texts.token').')' : '';
|
$token = Session::get('token_id') ? ' ('.trans('texts.token').')' : '';
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ class EntityModel extends Eloquent
|
|||||||
|
|
||||||
public function getActivityKey()
|
public function getActivityKey()
|
||||||
{
|
{
|
||||||
return $this->getEntityType().':'.$this->public_id.':'.$this->getName();
|
return '[' . $this->getEntityType().':'.$this->public_id.':'.$this->getName() . ']';
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -44,7 +44,7 @@ class AccountRepository
|
|||||||
}
|
}
|
||||||
|
|
||||||
$user->confirmed = !Utils::isNinja();
|
$user->confirmed = !Utils::isNinja();
|
||||||
$user->registered = !Utils::isNinja();
|
$user->registered = !Utils::isNinja() && $user->email;
|
||||||
|
|
||||||
if (!$user->confirmed) {
|
if (!$user->confirmed) {
|
||||||
$user->confirmation_code = str_random(RANDOM_KEY_LENGTH);
|
$user->confirmation_code = str_random(RANDOM_KEY_LENGTH);
|
||||||
|
@ -270,9 +270,12 @@ class InvoiceRepository
|
|||||||
$invoice->is_amount_discount = $data['is_amount_discount'] ? true : false;
|
$invoice->is_amount_discount = $data['is_amount_discount'] ? true : false;
|
||||||
$invoice->invoice_number = trim($data['invoice_number']);
|
$invoice->invoice_number = trim($data['invoice_number']);
|
||||||
$invoice->partial = round(Utils::parseFloat($data['partial']), 2);
|
$invoice->partial = round(Utils::parseFloat($data['partial']), 2);
|
||||||
$invoice->is_recurring = $data['is_recurring'] && !Utils::isDemo() ? true : false;
|
|
||||||
$invoice->invoice_date = isset($data['invoice_date_sql']) ? $data['invoice_date_sql'] : Utils::toSqlDate($data['invoice_date']);
|
$invoice->invoice_date = isset($data['invoice_date_sql']) ? $data['invoice_date_sql'] : Utils::toSqlDate($data['invoice_date']);
|
||||||
|
|
||||||
|
if (!$publicId) {
|
||||||
|
$invoice->is_recurring = $data['is_recurring'] && !Utils::isDemo() ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
if ($invoice->is_recurring) {
|
if ($invoice->is_recurring) {
|
||||||
$invoice->frequency_id = $data['frequency_id'] ? $data['frequency_id'] : 0;
|
$invoice->frequency_id = $data['frequency_id'] ? $data['frequency_id'] : 0;
|
||||||
$invoice->start_date = Utils::toSqlDate($data['start_date']);
|
$invoice->start_date = Utils::toSqlDate($data['start_date']);
|
||||||
|
@ -20,7 +20,7 @@ class AddPartialAmountToInvoices extends Migration {
|
|||||||
Schema::table('accounts', function($table)
|
Schema::table('accounts', function($table)
|
||||||
{
|
{
|
||||||
$table->boolean('utf8_invoices')->default(false);
|
$table->boolean('utf8_invoices')->default(false);
|
||||||
$table->boolean('auto_wrap')->default(true);
|
$table->boolean('auto_wrap')->default(false);
|
||||||
$table->string('subdomain')->nullable();
|
$table->string('subdomain')->nullable();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
2
public/css/built.css
vendored
2
public/css/built.css
vendored
@ -2421,7 +2421,7 @@ display: block;
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
padding: 9px 12px;
|
padding: 9px 12px;
|
||||||
font-size: 14px;
|
font-size: 16px;
|
||||||
line-height: 1.42857143;
|
line-height: 1.42857143;
|
||||||
color: #000 !important;
|
color: #000 !important;
|
||||||
background: #f9f9f9 !important;
|
background: #f9f9f9 !important;
|
||||||
|
2
public/css/style.css
vendored
2
public/css/style.css
vendored
@ -37,7 +37,7 @@ display: block;
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
padding: 9px 12px;
|
padding: 9px 12px;
|
||||||
font-size: 14px;
|
font-size: 16px;
|
||||||
line-height: 1.42857143;
|
line-height: 1.42857143;
|
||||||
color: #000 !important;
|
color: #000 !important;
|
||||||
background: #f9f9f9 !important;
|
background: #f9f9f9 !important;
|
||||||
|
@ -33094,22 +33094,22 @@ function GetPdfMake(invoice, javascript, callback) {
|
|||||||
var account = invoice.account;
|
var account = invoice.account;
|
||||||
eval(javascript);
|
eval(javascript);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
var fonts = {
|
var fonts = {
|
||||||
Roboto: {
|
Roboto: {
|
||||||
normal: 'Roboto-Regular.ttf',
|
normal: 'Roboto-Regular.ttf',
|
||||||
bold: 'Roboto-Medium.ttf',
|
bold: 'Roboto-Medium.ttf',
|
||||||
italics: 'Roboto-Italic.ttf',
|
italics: 'Roboto-Italic.ttf',
|
||||||
bolditalics: 'Roboto-Italic.ttf'
|
bolditalics: 'Roboto-Italic.ttf'
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
*/
|
*/
|
||||||
|
|
||||||
doc = pdfMake.createPdf(dd);
|
doc = pdfMake.createPdf(dd);
|
||||||
doc.save = function(fileName) {
|
doc.save = function(fileName) {
|
||||||
this.download(fileName);
|
this.download(fileName);
|
||||||
};
|
};
|
||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
function notesAndTerms(invoice)
|
function notesAndTerms(invoice)
|
||||||
{
|
{
|
||||||
@ -33153,39 +33153,39 @@ function invoiceLines(invoice) {
|
|||||||
tax = parseFloat(item.tax_rate);
|
tax = parseFloat(item.tax_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// show at most one blank line
|
// show at most one blank line
|
||||||
if (shownItem && (!cost || cost == '0.00') && !notes && !productKey) {
|
if (shownItem && (!cost || cost == '0.00') && !notes && !productKey) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
shownItem = true;
|
shownItem = true;
|
||||||
|
|
||||||
// process date variables
|
// process date variables
|
||||||
if (invoice.is_recurring) {
|
if (invoice.is_recurring) {
|
||||||
notes = processVariables(notes);
|
notes = processVariables(notes);
|
||||||
productKey = processVariables(productKey);
|
productKey = processVariables(productKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
var lineTotal = roundToTwo(NINJA.parseFloat(item.cost)) * roundToTwo(NINJA.parseFloat(item.qty));
|
var lineTotal = roundToTwo(NINJA.parseFloat(item.cost)) * roundToTwo(NINJA.parseFloat(item.qty));
|
||||||
if (tax) {
|
if (tax) {
|
||||||
lineTotal += lineTotal * tax / 100;
|
lineTotal += lineTotal * tax / 100;
|
||||||
}
|
}
|
||||||
if (lineTotal) {
|
if (lineTotal) {
|
||||||
total += lineTotal;
|
total += lineTotal;
|
||||||
}
|
}
|
||||||
lineTotal = formatMoney(lineTotal, currencyId);
|
lineTotal = formatMoney(lineTotal, currencyId);
|
||||||
|
|
||||||
rowStyle = i%2===0?'odd':'even';
|
rowStyle = i%2===0?'odd':'even';
|
||||||
|
|
||||||
row[0] = {style:["productKey", rowStyle], text:productKey};
|
row[0] = {style:["productKey", rowStyle], text:productKey};
|
||||||
row[1] = {style:["notes", rowStyle], text:notes};
|
row[1] = {style:["notes", rowStyle], text:notes};
|
||||||
row[2] = {style:["cost", rowStyle], text:cost};
|
row[2] = {style:["cost", rowStyle], text:cost};
|
||||||
row[3] = {style:["quantity", rowStyle], text:qty};
|
row[3] = {style:["quantity", rowStyle], text:qty};
|
||||||
row[4] = {style:["tax", rowStyle], text:""+tax};
|
row[4] = {style:["tax", rowStyle], text:""+tax};
|
||||||
row[5] = {style:["lineTotal", rowStyle], text:lineTotal};
|
row[5] = {style:["lineTotal", rowStyle], text:lineTotal};
|
||||||
|
|
||||||
grid.push(row);
|
grid.push(row);
|
||||||
}
|
}
|
||||||
return grid;
|
return grid;
|
||||||
}
|
}
|
||||||
|
|
||||||
function subtotals(invoice)
|
function subtotals(invoice)
|
||||||
@ -33227,11 +33227,11 @@ function subtotals(invoice)
|
|||||||
data.push([{text:invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due, style:'balanceDueLabel'},
|
data.push([{text:invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due, style:'balanceDueLabel'},
|
||||||
{text:formatMoney(invoice.balance_amount, invoice.client.currency_id), style:'balanceDueValue'}]);
|
{text:formatMoney(invoice.balance_amount, invoice.client.currency_id), style:'balanceDueValue'}]);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
function accountDetails(account) {
|
function accountDetails(account) {
|
||||||
var data = [];
|
var data = [];
|
||||||
if(account.name) data.push({text:account.name, style:'accountDetails'});
|
if(account.name) data.push({text:account.name, style:'accountName'});
|
||||||
if(account.id_number) data.push({text:account.id_number, style:'accountDetails'});
|
if(account.id_number) data.push({text:account.id_number, style:'accountDetails'});
|
||||||
if(account.vat_number) data.push({text:account.vat_number, style:'accountDetails'});
|
if(account.vat_number) data.push({text:account.vat_number, style:'accountDetails'});
|
||||||
if(account.work_email) data.push({text:account.work_email, style:'accountDetails'});
|
if(account.work_email) data.push({text:account.work_email, style:'accountDetails'});
|
||||||
@ -33240,15 +33240,66 @@ function subtotals(invoice)
|
|||||||
}
|
}
|
||||||
|
|
||||||
function accountAddress(account) {
|
function accountAddress(account) {
|
||||||
|
var address = '';
|
||||||
|
if (account.city || account.state || account.postal_code) {
|
||||||
|
address = ((account.city ? account.city + ', ' : '') + account.state + ' ' + account.postal_code).trim();
|
||||||
|
}
|
||||||
var data = [];
|
var data = [];
|
||||||
if(account.address1) data.push({text:account.address1, style:'accountDetails'});
|
if(account.address1) data.push({text:account.address1, style:'accountDetails'});
|
||||||
if(account.address2) data.push({text:account.address2, style:'accountDetails'});
|
if(account.address2) data.push({text:account.address2, style:'accountDetails'});
|
||||||
if(account.city) data.push({text:account.city, style:'accountDetails'});
|
if(address) data.push({text:address, style:'accountDetails'});
|
||||||
if(account.state) data.push({text:account.state, style:'accountDetails'});
|
if(account.country) data.push({text:account.country.name, style: 'accountDetails'});
|
||||||
if(account.postal_code) data.push({text:account.postal_code, style:'accountDetails'});
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function invoiceDetails(invoice) {
|
||||||
|
var data = [
|
||||||
|
[
|
||||||
|
invoice.is_quote ? invoiceLabels.quote_number : invoiceLabels.invoice_number,
|
||||||
|
{style: 'bold', text: invoice.invoice_number},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
invoice.is_quote ? invoiceLabels.quote_date : invoiceLabels.invoice_date,
|
||||||
|
invoice.invoice_date,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due,
|
||||||
|
formatMoney(invoice.balance_amount, invoice.client.currency_id),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function clientDetails(invoice) {
|
||||||
|
var client = invoice.client;
|
||||||
|
if (!client) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var fields = [
|
||||||
|
getClientDisplayName(client),
|
||||||
|
client.id_number,
|
||||||
|
client.vat_number,
|
||||||
|
concatStrings(client.address1, client.address2),
|
||||||
|
concatStrings(client.city, client.state, client.postal_code),
|
||||||
|
client.country ? client.country.name : false,
|
||||||
|
invoice.contact && getClientDisplayName(client) != invoice.contact.email ? invoice.contact.email : false,
|
||||||
|
invoice.client.custom_value1 ? invoice.account['custom_client_label1'] + ' ' + invoice.client.custom_value1 : false,
|
||||||
|
invoice.client.custom_value2 ? invoice.account['custom_client_label2'] + ' ' + invoice.client.custom_value2 : false,
|
||||||
|
];
|
||||||
|
|
||||||
|
var data = [];
|
||||||
|
for (var i=0; i<fields.length; i++) {
|
||||||
|
var field = fields[i];
|
||||||
|
if (!field) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
data.push(field);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function primaryColor( defaultColor) {
|
function primaryColor( defaultColor) {
|
||||||
return NINJA.primaryColor?NINJA.primaryColor:defaultColor;
|
return NINJA.primaryColor?NINJA.primaryColor:defaultColor;
|
||||||
}
|
}
|
||||||
|
@ -2,22 +2,22 @@ function GetPdfMake(invoice, javascript, callback) {
|
|||||||
var account = invoice.account;
|
var account = invoice.account;
|
||||||
eval(javascript);
|
eval(javascript);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
var fonts = {
|
var fonts = {
|
||||||
Roboto: {
|
Roboto: {
|
||||||
normal: 'Roboto-Regular.ttf',
|
normal: 'Roboto-Regular.ttf',
|
||||||
bold: 'Roboto-Medium.ttf',
|
bold: 'Roboto-Medium.ttf',
|
||||||
italics: 'Roboto-Italic.ttf',
|
italics: 'Roboto-Italic.ttf',
|
||||||
bolditalics: 'Roboto-Italic.ttf'
|
bolditalics: 'Roboto-Italic.ttf'
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
*/
|
*/
|
||||||
|
|
||||||
doc = pdfMake.createPdf(dd);
|
doc = pdfMake.createPdf(dd);
|
||||||
doc.save = function(fileName) {
|
doc.save = function(fileName) {
|
||||||
this.download(fileName);
|
this.download(fileName);
|
||||||
};
|
};
|
||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
function notesAndTerms(invoice)
|
function notesAndTerms(invoice)
|
||||||
{
|
{
|
||||||
@ -61,39 +61,39 @@ function invoiceLines(invoice) {
|
|||||||
tax = parseFloat(item.tax_rate);
|
tax = parseFloat(item.tax_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// show at most one blank line
|
// show at most one blank line
|
||||||
if (shownItem && (!cost || cost == '0.00') && !notes && !productKey) {
|
if (shownItem && (!cost || cost == '0.00') && !notes && !productKey) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
shownItem = true;
|
shownItem = true;
|
||||||
|
|
||||||
// process date variables
|
// process date variables
|
||||||
if (invoice.is_recurring) {
|
if (invoice.is_recurring) {
|
||||||
notes = processVariables(notes);
|
notes = processVariables(notes);
|
||||||
productKey = processVariables(productKey);
|
productKey = processVariables(productKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
var lineTotal = roundToTwo(NINJA.parseFloat(item.cost)) * roundToTwo(NINJA.parseFloat(item.qty));
|
var lineTotal = roundToTwo(NINJA.parseFloat(item.cost)) * roundToTwo(NINJA.parseFloat(item.qty));
|
||||||
if (tax) {
|
if (tax) {
|
||||||
lineTotal += lineTotal * tax / 100;
|
lineTotal += lineTotal * tax / 100;
|
||||||
}
|
}
|
||||||
if (lineTotal) {
|
if (lineTotal) {
|
||||||
total += lineTotal;
|
total += lineTotal;
|
||||||
}
|
}
|
||||||
lineTotal = formatMoney(lineTotal, currencyId);
|
lineTotal = formatMoney(lineTotal, currencyId);
|
||||||
|
|
||||||
rowStyle = i%2===0?'odd':'even';
|
rowStyle = i%2===0?'odd':'even';
|
||||||
|
|
||||||
row[0] = {style:["productKey", rowStyle], text:productKey};
|
row[0] = {style:["productKey", rowStyle], text:productKey};
|
||||||
row[1] = {style:["notes", rowStyle], text:notes};
|
row[1] = {style:["notes", rowStyle], text:notes};
|
||||||
row[2] = {style:["cost", rowStyle], text:cost};
|
row[2] = {style:["cost", rowStyle], text:cost};
|
||||||
row[3] = {style:["quantity", rowStyle], text:qty};
|
row[3] = {style:["quantity", rowStyle], text:qty};
|
||||||
row[4] = {style:["tax", rowStyle], text:""+tax};
|
row[4] = {style:["tax", rowStyle], text:""+tax};
|
||||||
row[5] = {style:["lineTotal", rowStyle], text:lineTotal};
|
row[5] = {style:["lineTotal", rowStyle], text:lineTotal};
|
||||||
|
|
||||||
grid.push(row);
|
grid.push(row);
|
||||||
}
|
}
|
||||||
return grid;
|
return grid;
|
||||||
}
|
}
|
||||||
|
|
||||||
function subtotals(invoice)
|
function subtotals(invoice)
|
||||||
@ -135,11 +135,11 @@ function subtotals(invoice)
|
|||||||
data.push([{text:invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due, style:'balanceDueLabel'},
|
data.push([{text:invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due, style:'balanceDueLabel'},
|
||||||
{text:formatMoney(invoice.balance_amount, invoice.client.currency_id), style:'balanceDueValue'}]);
|
{text:formatMoney(invoice.balance_amount, invoice.client.currency_id), style:'balanceDueValue'}]);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
function accountDetails(account) {
|
function accountDetails(account) {
|
||||||
var data = [];
|
var data = [];
|
||||||
if(account.name) data.push({text:account.name, style:'accountDetails'});
|
if(account.name) data.push({text:account.name, style:'accountName'});
|
||||||
if(account.id_number) data.push({text:account.id_number, style:'accountDetails'});
|
if(account.id_number) data.push({text:account.id_number, style:'accountDetails'});
|
||||||
if(account.vat_number) data.push({text:account.vat_number, style:'accountDetails'});
|
if(account.vat_number) data.push({text:account.vat_number, style:'accountDetails'});
|
||||||
if(account.work_email) data.push({text:account.work_email, style:'accountDetails'});
|
if(account.work_email) data.push({text:account.work_email, style:'accountDetails'});
|
||||||
@ -148,15 +148,66 @@ function subtotals(invoice)
|
|||||||
}
|
}
|
||||||
|
|
||||||
function accountAddress(account) {
|
function accountAddress(account) {
|
||||||
|
var address = '';
|
||||||
|
if (account.city || account.state || account.postal_code) {
|
||||||
|
address = ((account.city ? account.city + ', ' : '') + account.state + ' ' + account.postal_code).trim();
|
||||||
|
}
|
||||||
var data = [];
|
var data = [];
|
||||||
if(account.address1) data.push({text:account.address1, style:'accountDetails'});
|
if(account.address1) data.push({text:account.address1, style:'accountDetails'});
|
||||||
if(account.address2) data.push({text:account.address2, style:'accountDetails'});
|
if(account.address2) data.push({text:account.address2, style:'accountDetails'});
|
||||||
if(account.city) data.push({text:account.city, style:'accountDetails'});
|
if(address) data.push({text:address, style:'accountDetails'});
|
||||||
if(account.state) data.push({text:account.state, style:'accountDetails'});
|
if(account.country) data.push({text:account.country.name, style: 'accountDetails'});
|
||||||
if(account.postal_code) data.push({text:account.postal_code, style:'accountDetails'});
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function invoiceDetails(invoice) {
|
||||||
|
var data = [
|
||||||
|
[
|
||||||
|
invoice.is_quote ? invoiceLabels.quote_number : invoiceLabels.invoice_number,
|
||||||
|
{style: 'bold', text: invoice.invoice_number},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
invoice.is_quote ? invoiceLabels.quote_date : invoiceLabels.invoice_date,
|
||||||
|
invoice.invoice_date,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due,
|
||||||
|
formatMoney(invoice.balance_amount, invoice.client.currency_id),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function clientDetails(invoice) {
|
||||||
|
var client = invoice.client;
|
||||||
|
if (!client) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var fields = [
|
||||||
|
getClientDisplayName(client),
|
||||||
|
client.id_number,
|
||||||
|
client.vat_number,
|
||||||
|
concatStrings(client.address1, client.address2),
|
||||||
|
concatStrings(client.city, client.state, client.postal_code),
|
||||||
|
client.country ? client.country.name : false,
|
||||||
|
invoice.contact && getClientDisplayName(client) != invoice.contact.email ? invoice.contact.email : false,
|
||||||
|
invoice.client.custom_value1 ? invoice.account['custom_client_label1'] + ' ' + invoice.client.custom_value1 : false,
|
||||||
|
invoice.client.custom_value2 ? invoice.account['custom_client_label2'] + ' ' + invoice.client.custom_value2 : false,
|
||||||
|
];
|
||||||
|
|
||||||
|
var data = [];
|
||||||
|
for (var i=0; i<fields.length; i++) {
|
||||||
|
var field = fields[i];
|
||||||
|
if (!field) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
data.push(field);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function primaryColor( defaultColor) {
|
function primaryColor( defaultColor) {
|
||||||
return NINJA.primaryColor?NINJA.primaryColor:defaultColor;
|
return NINJA.primaryColor?NINJA.primaryColor:defaultColor;
|
||||||
}
|
}
|
||||||
|
@ -20,23 +20,29 @@ var dd = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
text:(invoice.is_quote ? invoiceLabels.quote : invoiceLabels.invoice).toUpperCase(),
|
text:(invoice.is_quote ? invoiceLabels.quote : invoiceLabels.invoice).toUpperCase(),
|
||||||
margin: [8, 16, 8, 16],
|
margin: [8, 70, 8, 16],
|
||||||
style: 'primaryColor'
|
style: 'primaryColor',
|
||||||
|
fontSize: 11
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
style: 'tableExample',
|
style: 'tableExample',
|
||||||
table: {
|
table: {
|
||||||
headerRows: 1,
|
headerRows: 1,
|
||||||
widths: ['auto', 'auto', '*'],
|
widths: ['auto', 'auto', '*'],
|
||||||
body: [
|
body: [[
|
||||||
[invoice.is_quote ? invoiceLabels.quote_number:invoiceLabels.invoice_number, {style: 'bold', text: invoice.invoice_number}, ""],
|
{
|
||||||
[invoice.is_quote ? invoiceLabels.quote_date:invoiceLabels.invoice_date, invoice.invoice_date, ""],
|
table: {
|
||||||
[invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due, formatMoney(invoice.balance_amount, invoice.client.currency_id), ""],
|
body: invoiceDetails(invoice),
|
||||||
]
|
},
|
||||||
|
layout: 'noBorders',
|
||||||
|
},
|
||||||
|
clientDetails(invoice),
|
||||||
|
''
|
||||||
|
]]
|
||||||
},
|
},
|
||||||
layout: {
|
layout: {
|
||||||
hLineWidth: function (i, node) {
|
hLineWidth: function (i, node) {
|
||||||
return (i === 0 || i === node.table.body.length) ? 1 : 0;
|
return (i === 0 || i === node.table.body.length) ? .5 : 0;
|
||||||
},
|
},
|
||||||
vLineWidth: function (i, node) {
|
vLineWidth: function (i, node) {
|
||||||
return 0;//(i === 0 || i === node.table.widths.length) ? 2 : 1;
|
return 0;//(i === 0 || i === node.table.widths.length) ? 2 : 1;
|
||||||
@ -57,12 +63,12 @@ var dd = {
|
|||||||
{
|
{
|
||||||
table: {
|
table: {
|
||||||
headerRows: 1,
|
headerRows: 1,
|
||||||
widths: ['auto', '*', 'auto', 'auto', 'auto', 'auto'],
|
widths: ['15%', '*', 'auto', 'auto', 'auto', 'auto'],
|
||||||
body:invoiceLines(invoice),
|
body:invoiceLines(invoice),
|
||||||
},
|
},
|
||||||
layout: {
|
layout: {
|
||||||
hLineWidth: function (i, node) {
|
hLineWidth: function (i, node) {
|
||||||
return i === 0 ? 0 : 1;
|
return i === 0 ? 0 : .5;
|
||||||
},
|
},
|
||||||
vLineWidth: function (i, node) {
|
vLineWidth: function (i, node) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -104,12 +110,12 @@ var dd = {
|
|||||||
],
|
],
|
||||||
|
|
||||||
footer: function(){
|
footer: function(){
|
||||||
f = [{ text:invoice.invoice_footer?invoice.invoice_footer:"", margin: [72, 0]}]
|
f = [{ text:invoice.invoice_footer?invoice.invoice_footer:"", margin: [40, 0]}]
|
||||||
if (!invoice.is_pro && logoImages.imageLogo1) {
|
if (!invoice.is_pro && logoImages.imageLogo1) {
|
||||||
f.push({
|
f.push({
|
||||||
image: logoImages.imageLogo1,
|
image: logoImages.imageLogo1,
|
||||||
width: 150,
|
width: 150,
|
||||||
margin: [72,0]
|
margin: [40,0]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return f;
|
return f;
|
||||||
@ -124,6 +130,10 @@ var dd = {
|
|||||||
primaryColor:{
|
primaryColor:{
|
||||||
color: primaryColor('#299CC2')
|
color: primaryColor('#299CC2')
|
||||||
},
|
},
|
||||||
|
accountName: {
|
||||||
|
margin: [4, 2, 4, 2],
|
||||||
|
color:primaryColor('#299CC2')
|
||||||
|
},
|
||||||
accountDetails: {
|
accountDetails: {
|
||||||
margin: [4, 2, 4, 2],
|
margin: [4, 2, 4, 2],
|
||||||
color: '#AAA9A9'
|
color: '#AAA9A9'
|
||||||
@ -178,5 +188,5 @@ var dd = {
|
|||||||
margin: [0, 10, 0, 4]
|
margin: [0, 10, 0, 4]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
pageMargins: [72, 40, 40, 80]
|
pageMargins: [40, 40, 40, 40]
|
||||||
};
|
};
|
@ -650,5 +650,9 @@ return array(
|
|||||||
'export' => 'Export',
|
'export' => 'Export',
|
||||||
'documentation' => 'Documentation',
|
'documentation' => 'Documentation',
|
||||||
'zapier' => 'Zapier <sup>Beta</sup>',
|
'zapier' => 'Zapier <sup>Beta</sup>',
|
||||||
|
'recurring' => 'Recurring',
|
||||||
|
'last_invoice_sent' => 'Last invoice sent :date',
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
);
|
);
|
||||||
|
@ -98,8 +98,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
{!! Former::checkbox('pdf_email_attachment')->text(trans('texts.enable')) !!}
|
{!! Former::checkbox('pdf_email_attachment')->text(trans('texts.enable')) !!}
|
||||||
{!! Former::checkbox('auto_wrap')->text(trans('texts.enable')) !!}
|
|
||||||
{!! Former::checkbox('utf8_invoices')->text(trans('texts.enable')) !!}
|
{!! Former::checkbox('utf8_invoices')->text(trans('texts.enable')) !!}
|
||||||
|
<div style="display:none">
|
||||||
|
{!! Former::checkbox('auto_wrap')->text(trans('texts.enable')) !!}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -14,7 +14,9 @@
|
|||||||
|
|
||||||
<div class="pull-right">
|
<div class="pull-right">
|
||||||
{!! Button::normal(trans('texts.documentation'))->asLinkTo(NINJA_WEB_URL.'/knowledgebase/api-documentation/')->withAttributes(['target' => '_blank']) !!}
|
{!! Button::normal(trans('texts.documentation'))->asLinkTo(NINJA_WEB_URL.'/knowledgebase/api-documentation/')->withAttributes(['target' => '_blank']) !!}
|
||||||
|
@if (Utils::isNinja())
|
||||||
{!! Button::normal(trans('texts.zapier'))->asLinkTo(ZAPIER_URL)->withAttributes(['target' => '_blank']) !!}
|
{!! Button::normal(trans('texts.zapier'))->asLinkTo(ZAPIER_URL)->withAttributes(['target' => '_blank']) !!}
|
||||||
|
@endif
|
||||||
@if (Utils::isPro())
|
@if (Utils::isPro())
|
||||||
{!! Button::primary(trans('texts.add_token'))->asLinkTo('/tokens/create')->appendIcon(Icon::create('plus-sign')) !!}
|
{!! Button::primary(trans('texts.add_token'))->asLinkTo('/tokens/create')->appendIcon(Icon::create('plus-sign')) !!}
|
||||||
@endif
|
@endif
|
||||||
|
@ -90,7 +90,7 @@
|
|||||||
@foreach ($pastDue as $invoice)
|
@foreach ($pastDue as $invoice)
|
||||||
@if (!$invoice->client->trashed())
|
@if (!$invoice->client->trashed())
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ $invoice->getLink() }}</td>
|
<td>{!! $invoice->getLink() !!}</td>
|
||||||
<td>{{ $invoice->client->getDisplayName() }}</td>
|
<td>{{ $invoice->client->getDisplayName() }}</td>
|
||||||
<td>{{ Utils::fromSqlDate($invoice->due_date) }}</td>
|
<td>{{ Utils::fromSqlDate($invoice->due_date) }}</td>
|
||||||
<td>{{ Utils::formatMoney($invoice->balance, $invoice->client->currency_id) }}</td>
|
<td>{{ Utils::formatMoney($invoice->balance, $invoice->client->currency_id) }}</td>
|
||||||
|
@ -19,6 +19,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 768px) {
|
||||||
|
body {
|
||||||
|
padding-top: 56px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
@include('script')
|
@include('script')
|
||||||
|
@ -11,14 +11,6 @@
|
|||||||
<script src="{{ asset('js/vfs_fonts.js') }}" type="text/javascript"></script>
|
<script src="{{ asset('js/vfs_fonts.js') }}" type="text/javascript"></script>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<style type="text/css">
|
|
||||||
.partial div.checkbox {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
.partial span.input-group-addon {
|
|
||||||
padding-right: 30px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@stop
|
@stop
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
@ -86,9 +78,7 @@
|
|||||||
{!! Former::text('due_date')->data_bind("datePicker: due_date, valueUpdate: 'afterkeydown'")
|
{!! Former::text('due_date')->data_bind("datePicker: due_date, valueUpdate: 'afterkeydown'")
|
||||||
->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT, DEFAULT_DATE_PICKER_FORMAT))->append('<i class="glyphicon glyphicon-calendar" onclick="toggleDatePicker(\'due_date\')"></i>') !!}
|
->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT, DEFAULT_DATE_PICKER_FORMAT))->append('<i class="glyphicon glyphicon-calendar" onclick="toggleDatePicker(\'due_date\')"></i>') !!}
|
||||||
|
|
||||||
{!! Former::text('partial')->data_bind("value: partial, valueUpdate: 'afterkeydown', enable: is_partial")
|
{!! Former::text('partial')->data_bind("value: partial, valueUpdate: 'afterkeydown'")->onchange('onPartialChange()') !!}
|
||||||
->onchange('onPartialChange()')->addGroupClass('partial')->append(Former::checkbox('is_partial')->raw()
|
|
||||||
->data_bind('checked: is_partial')->onclick('onPartialEnabled()') . ' ' . (trans('texts.enable'))) !!}
|
|
||||||
</div>
|
</div>
|
||||||
@if ($entityType == ENTITY_INVOICE)
|
@if ($entityType == ENTITY_INVOICE)
|
||||||
<div data-bind="visible: is_recurring" style="display: none">
|
<div data-bind="visible: is_recurring" style="display: none">
|
||||||
@ -104,8 +94,24 @@
|
|||||||
</div>
|
</div>
|
||||||
@else
|
@else
|
||||||
<div data-bind="visible: invoice_status_id() === 0">
|
<div data-bind="visible: invoice_status_id() === 0">
|
||||||
{!! Former::checkbox('recurring')->onclick('onRecurringEnabled()')->text(trans('texts.enable').' <a href="#" onclick="showLearnMore()"><i class="glyphicon glyphicon-question-sign"></i> '.trans('texts.learn_more').'</a>')->data_bind("checked: is_recurring")
|
<div class="form-group">
|
||||||
->inlineHelp($invoice && $invoice->last_sent_date ? 'Last invoice sent ' . Utils::dateToString($invoice->last_sent_date) : '') !!}
|
<label for="" class="control-label col-lg-4 col-sm-4">
|
||||||
|
{{ trans('texts.recurring') }}
|
||||||
|
</label>
|
||||||
|
<div class="col-lg-8 col-sm-8">
|
||||||
|
<div class="checkbox">
|
||||||
|
<label for="recurring" class="">
|
||||||
|
<input onclick="onRecurringEnabled()" data-bind="checked: is_recurring" id="recurring" type="checkbox" name="recurring" value="1">{{ trans('texts.enable') }}
|
||||||
|
<a href="#" onclick="showLearnMore()"><i class="glyphicon glyphicon-question-sign"></i> {{ trans('texts.learn_more') }}</a>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@if ($invoice && $invoice->last_sent_date)
|
||||||
|
<div class="pull-right">
|
||||||
|
{{ trans('texts.last_invoice_sent', ['date' => Utils::dateToString($invoice->last_sent_date)]) }}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@endif
|
@endif
|
||||||
@ -1130,7 +1136,6 @@
|
|||||||
self.balance = ko.observable(0);
|
self.balance = ko.observable(0);
|
||||||
self.invoice_design_id = ko.observable({{ $account->utf8_invoices ? 1 : $account->invoice_design_id }});
|
self.invoice_design_id = ko.observable({{ $account->utf8_invoices ? 1 : $account->invoice_design_id }});
|
||||||
self.partial = ko.observable(0);
|
self.partial = ko.observable(0);
|
||||||
self.is_partial = ko.observable(false);
|
|
||||||
|
|
||||||
self.custom_value1 = ko.observable(0);
|
self.custom_value1 = ko.observable(0);
|
||||||
self.custom_value2 = ko.observable(0);
|
self.custom_value2 = ko.observable(0);
|
||||||
@ -1336,7 +1341,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
self.totals.total = ko.computed(function() {
|
self.totals.total = ko.computed(function() {
|
||||||
return formatMoney(self.is_partial() ? self.partial() : self.totals.rawTotal(), self.client().currency_id());
|
return formatMoney(self.partial() ? self.partial() : self.totals.rawTotal(), self.client().currency_id());
|
||||||
});
|
});
|
||||||
|
|
||||||
self.onDragged = function(item) {
|
self.onDragged = function(item) {
|
||||||
@ -1647,19 +1652,7 @@
|
|||||||
{
|
{
|
||||||
var val = NINJA.parseFloat($('#partial').val());
|
var val = NINJA.parseFloat($('#partial').val());
|
||||||
val = Math.max(Math.min(val, model.invoice().totals.rawTotal()), 0);
|
val = Math.max(Math.min(val, model.invoice().totals.rawTotal()), 0);
|
||||||
$('#partial').val(val);
|
$('#partial').val(val || '');
|
||||||
}
|
|
||||||
|
|
||||||
function onPartialEnabled()
|
|
||||||
{
|
|
||||||
model.invoice().partial('');
|
|
||||||
refreshPDF();
|
|
||||||
|
|
||||||
if ($('#is_partial').prop('checked')) {
|
|
||||||
setTimeout(function() {
|
|
||||||
$('#partial').focus();
|
|
||||||
}, 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onRecurringEnabled()
|
function onRecurringEnabled()
|
||||||
@ -1702,9 +1695,6 @@
|
|||||||
@if ($invoice)
|
@if ($invoice)
|
||||||
var invoice = {!! $invoice !!};
|
var invoice = {!! $invoice !!};
|
||||||
ko.mapping.fromJS(invoice, model.invoice().mapping, model.invoice);
|
ko.mapping.fromJS(invoice, model.invoice().mapping, model.invoice);
|
||||||
if (NINJA.parseFloat(model.invoice().partial())) {
|
|
||||||
model.invoice().is_partial(true);
|
|
||||||
}
|
|
||||||
var invitationContactIds = {!! json_encode($invitationContactIds) !!};
|
var invitationContactIds = {!! json_encode($invitationContactIds) !!};
|
||||||
var client = clientMap[invoice.client.public_id];
|
var client = clientMap[invoice.client.public_id];
|
||||||
if (client) { // in case it's deleted
|
if (client) { // in case it's deleted
|
||||||
|
Loading…
x
Reference in New Issue
Block a user