diff --git a/app/Console/Commands/CheckData.php b/app/Console/Commands/CheckData.php index 501f95b43e4f..297431612473 100644 --- a/app/Console/Commands/CheckData.php +++ b/app/Console/Commands/CheckData.php @@ -1,5 +1,8 @@ groupBy('clients.id', 'clients.balance', 'clients.created_at') ->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'); 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; $lastBalance = 0; + $lastAdjustment = 0; + $lastCreatedAt = null; $clientFix = false; $activities = DB::table('activities') ->where('client_id', '=', $client->id) @@ -195,6 +200,11 @@ class CheckData extends Command { $foundProblem = true; $clientFix -= $activity->adjustment; $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) { // **Fix for updating balance when updating a quote** @@ -231,18 +241,32 @@ class CheckData extends Command { } $lastBalance = $activity->balance; + $lastAdjustment = $activity->adjustment; + $lastCreatedAt = $activity->created_at; } - if ($clientFix !== false) { - $balance = $activity->balance + $clientFix; - $data = ['balance' => $balance]; - $this->info("Corrected balance:{$balance}"); + if ($activity->balance + $clientFix != $client->actual_balance) { + $this->info("** Creating 'recovered update' activity **"); if ($this->option('fix') == 'true') { - DB::table('clients') - ->where('id', $client->id) - ->update($data); + 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 [details]', + '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') { + DB::table('clients') + ->where('id', $client->id) + ->update($data); + } } $this->info('Done'); diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php index 55cc619d81d5..bf128d6afb35 100644 --- a/app/Http/Controllers/DashboardController.php +++ b/app/Http/Controllers/DashboardController.php @@ -51,6 +51,7 @@ class DashboardController extends BaseController $activities = Activity::where('activities.account_id', '=', Auth::user()->account_id) + ->where('activity_type_id', '>', 0) ->orderBy('created_at', 'desc')->take(6)->get(); $pastDue = Invoice::scope() diff --git a/app/Http/Controllers/ReportController.php b/app/Http/Controllers/ReportController.php index cf4e4cce8104..96b3e7b28746 100644 --- a/app/Http/Controllers/ReportController.php +++ b/app/Http/Controllers/ReportController.php @@ -59,8 +59,6 @@ class ReportController extends BaseController $enableChart = true; } - $padding = $groupBy == 'DAYOFYEAR' ? 'day' : ($groupBy == 'WEEK' ? 'week' : 'month'); - $endDate->modify('+1 '.$padding); $datasets = []; $labels = []; $maxTotals = 0; @@ -155,7 +153,7 @@ class ReportController extends BaseController if ($enableChart) { foreach ([ENTITY_INVOICE, ENTITY_PAYMENT, ENTITY_CREDIT] as $entityType) { $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($entityType.'s.is_deleted', '=', false) ->where($entityType.'s.'.$entityType.'_date', '>=', $startDate->format('Y-m-d')) @@ -171,23 +169,26 @@ class ReportController extends BaseController $dates = $records->lists($groupBy); $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)); $period = new DatePeriod($startDate, $interval, $endDate); + $endDate->modify('-1 '.$padding); $totals = []; foreach ($period as $d) { $dateFormat = $groupBy == 'DAYOFYEAR' ? 'z' : ($groupBy == 'WEEK' ? 'W' : 'n'); - $date = $d->format($dateFormat); + $date = $d->format('Y'.$dateFormat); $totals[] = isset($data[$date]) ? $data[$date] : 0; - + if ($entityType == ENTITY_INVOICE) { $labelFormat = $groupBy == 'DAYOFYEAR' ? 'j' : ($groupBy == 'WEEK' ? 'W' : 'F'); $label = $d->format($labelFormat); $labels[] = $label; } } - + $max = max($totals); if ($max > 0) { @@ -228,7 +229,7 @@ class ReportController extends BaseController 'chartTypes' => $chartTypes, 'chartType' => $chartType, '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, 'feature' => ACCOUNT_CHART_BUILDER, 'displayData' => $displayData, diff --git a/app/Http/Middleware/StartupCheck.php b/app/Http/Middleware/StartupCheck.php index a5f93b432fa1..696df9a5889c 100644 --- a/app/Http/Middleware/StartupCheck.php +++ b/app/Http/Middleware/StartupCheck.php @@ -66,8 +66,7 @@ class StartupCheck $count = Session::get(SESSION_COUNTER, 0); Session::put(SESSION_COUNTER, ++$count); - //if (!Utils::startsWith($_SERVER['REQUEST_URI'], '/news_feed') && !Session::has('news_feed_id')) { - if (true) { + if (!Utils::startsWith($_SERVER['REQUEST_URI'], '/news_feed') && !Session::has('news_feed_id')) { $data = false; if (Utils::isNinja()) { $data = Utils::getNewsFeedResponse(); diff --git a/app/Libraries/Utils.php b/app/Libraries/Utils.php index 726d0bc6fc67..45ca2ac27c87 100644 --- a/app/Libraries/Utils.php +++ b/app/Libraries/Utils.php @@ -236,9 +236,13 @@ class Utils $currencyId = Session::get(SESSION_CURRENCY); } - $currency = Currency::find($currencyId); - - if(!$currency){ + foreach (Cache::get('currencies') as $currency) { + if ($currency->id == $currencyId) { + break; + } + } + + if (!$currency) { $currency = Currency::find(1); } @@ -486,7 +490,7 @@ class Utils public static function encodeActivity($person = null, $action, $entity = null, $otherPerson = null) { $person = $person ? $person->getDisplayName() : 'System'; - $entity = $entity ? '['.$entity->getActivityKey().']' : ''; + $entity = $entity ? $entity->getActivityKey() : ''; $otherPerson = $otherPerson ? 'to '.$otherPerson->getDisplayName() : ''; $token = Session::get('token_id') ? ' ('.trans('texts.token').')' : ''; diff --git a/app/Models/EntityModel.php b/app/Models/EntityModel.php index 739f7d6a02c5..018622c7e982 100644 --- a/app/Models/EntityModel.php +++ b/app/Models/EntityModel.php @@ -44,7 +44,7 @@ class EntityModel extends Eloquent public function getActivityKey() { - return $this->getEntityType().':'.$this->public_id.':'.$this->getName(); + return '[' . $this->getEntityType().':'.$this->public_id.':'.$this->getName() . ']'; } /* diff --git a/app/Ninja/Repositories/AccountRepository.php b/app/Ninja/Repositories/AccountRepository.php index 56e6d8d933fc..695b79918e9e 100644 --- a/app/Ninja/Repositories/AccountRepository.php +++ b/app/Ninja/Repositories/AccountRepository.php @@ -44,7 +44,7 @@ class AccountRepository } $user->confirmed = !Utils::isNinja(); - $user->registered = !Utils::isNinja(); + $user->registered = !Utils::isNinja() && $user->email; if (!$user->confirmed) { $user->confirmation_code = str_random(RANDOM_KEY_LENGTH); diff --git a/app/Ninja/Repositories/InvoiceRepository.php b/app/Ninja/Repositories/InvoiceRepository.php index b77ea725c0fd..fa67b6270e1a 100644 --- a/app/Ninja/Repositories/InvoiceRepository.php +++ b/app/Ninja/Repositories/InvoiceRepository.php @@ -270,9 +270,12 @@ class InvoiceRepository $invoice->is_amount_discount = $data['is_amount_discount'] ? true : false; $invoice->invoice_number = trim($data['invoice_number']); $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']); + if (!$publicId) { + $invoice->is_recurring = $data['is_recurring'] && !Utils::isDemo() ? true : false; + } + if ($invoice->is_recurring) { $invoice->frequency_id = $data['frequency_id'] ? $data['frequency_id'] : 0; $invoice->start_date = Utils::toSqlDate($data['start_date']); diff --git a/database/migrations/2015_04_16_122647_add_partial_amount_to_invoices.php b/database/migrations/2015_04_16_122647_add_partial_amount_to_invoices.php index 8104a95b6f3b..ab25209e8915 100644 --- a/database/migrations/2015_04_16_122647_add_partial_amount_to_invoices.php +++ b/database/migrations/2015_04_16_122647_add_partial_amount_to_invoices.php @@ -20,7 +20,7 @@ class AddPartialAmountToInvoices extends Migration { Schema::table('accounts', function($table) { $table->boolean('utf8_invoices')->default(false); - $table->boolean('auto_wrap')->default(true); + $table->boolean('auto_wrap')->default(false); $table->string('subdomain')->nullable(); }); } diff --git a/public/css/built.css b/public/css/built.css index a9c4a4d36b28..01bb59406ae3 100644 --- a/public/css/built.css +++ b/public/css/built.css @@ -2421,7 +2421,7 @@ display: block; width: 100%; height: 40px; padding: 9px 12px; -font-size: 14px; +font-size: 16px; line-height: 1.42857143; color: #000 !important; background: #f9f9f9 !important; diff --git a/public/css/style.css b/public/css/style.css index 78f2acf99255..8c138b7b2d69 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -37,7 +37,7 @@ display: block; width: 100%; height: 40px; padding: 9px 12px; -font-size: 14px; +font-size: 16px; line-height: 1.42857143; color: #000 !important; background: #f9f9f9 !important; diff --git a/public/js/built.js b/public/js/built.js index 40369ca9c69c..b8859bfc75df 100644 --- a/public/js/built.js +++ b/public/js/built.js @@ -33091,168 +33091,219 @@ function truncate(str, length) { return (str && str.length > length) ? (str.substr(0, length-1) + '...') : str; } function GetPdfMake(invoice, javascript, callback) { - var account = invoice.account; - eval(javascript); + var account = invoice.account; + eval(javascript); - /* - var fonts = { - Roboto: { - normal: 'Roboto-Regular.ttf', - bold: 'Roboto-Medium.ttf', - italics: 'Roboto-Italic.ttf', - bolditalics: 'Roboto-Italic.ttf' - }, - }; - */ - - doc = pdfMake.createPdf(dd); - doc.save = function(fileName) { +/* +var fonts = { +Roboto: { +normal: 'Roboto-Regular.ttf', +bold: 'Roboto-Medium.ttf', +italics: 'Roboto-Italic.ttf', +bolditalics: 'Roboto-Italic.ttf' +}, +}; +*/ + +doc = pdfMake.createPdf(dd); +doc.save = function(fileName) { this.download(fileName); - }; - return doc; +}; +return doc; } function notesAndTerms(invoice) { - var text = []; - if (invoice.public_notes) { - text.push({text:invoice.public_notes, style:'notes'}); - } + var text = []; + if (invoice.public_notes) { + text.push({text:invoice.public_notes, style:'notes'}); + } - if (invoice.terms) { - text.push({text:invoiceLabels.terms, style:'termsLabel'}); - text.push({text:invoice.terms, style:'terms'}); - } + if (invoice.terms) { + text.push({text:invoiceLabels.terms, style:'termsLabel'}); + text.push({text:invoice.terms, style:'terms'}); + } - return text; + return text; } function invoiceLines(invoice) { - var grid = - [[{text: invoiceLabels.item, style: 'tableHeader'}, - {text: invoiceLabels.description, style: 'tableHeader'}, - {text: invoiceLabels.unit_cost, style: 'tableHeader'}, - {text: invoiceLabels.quantity, style: 'tableHeader'}, - {text: invoice.has_taxes?invoiceLabels.tax:'', style: 'tableHeader'}, - {text: invoiceLabels.line_total, style: 'tableHeader'}]]; - var total = 0; - var shownItem = false; - var currencyId = invoice && invoice.client ? invoice.client.currency_id : 1; - var hideQuantity = invoice.account.hide_quantity == '1'; + var grid = + [[{text: invoiceLabels.item, style: 'tableHeader'}, + {text: invoiceLabels.description, style: 'tableHeader'}, + {text: invoiceLabels.unit_cost, style: 'tableHeader'}, + {text: invoiceLabels.quantity, style: 'tableHeader'}, + {text: invoice.has_taxes?invoiceLabels.tax:'', style: 'tableHeader'}, + {text: invoiceLabels.line_total, style: 'tableHeader'}]]; + var total = 0; + var shownItem = false; + var currencyId = invoice && invoice.client ? invoice.client.currency_id : 1; + var hideQuantity = invoice.account.hide_quantity == '1'; - for (var i = 0; i < invoice.invoice_items.length; i++) { - var row = []; - var item = invoice.invoice_items[i]; - var cost = formatMoney(item.cost, currencyId, true); - var qty = NINJA.parseFloat(item.qty) ? roundToTwo(NINJA.parseFloat(item.qty)) + '' : ''; - var notes = item.notes; - var productKey = item.product_key; - var tax = ""; - 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); - } + for (var i = 0; i < invoice.invoice_items.length; i++) { + var row = []; + var item = invoice.invoice_items[i]; + var cost = formatMoney(item.cost, currencyId, true); + var qty = NINJA.parseFloat(item.qty) ? roundToTwo(NINJA.parseFloat(item.qty)) + '' : ''; + var notes = item.notes; + var productKey = item.product_key; + var tax = ""; + 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) { - continue; - } - shownItem = true; +// show at most one blank line +if (shownItem && (!cost || cost == '0.00') && !notes && !productKey) { + continue; +} +shownItem = true; - // process date variables - if (invoice.is_recurring) { - notes = processVariables(notes); - productKey = processVariables(productKey); - } +// process date variables +if (invoice.is_recurring) { + notes = processVariables(notes); + productKey = processVariables(productKey); +} - var lineTotal = roundToTwo(NINJA.parseFloat(item.cost)) * roundToTwo(NINJA.parseFloat(item.qty)); - if (tax) { - lineTotal += lineTotal * tax / 100; - } - if (lineTotal) { - total += lineTotal; - } - lineTotal = formatMoney(lineTotal, currencyId); - - rowStyle = i%2===0?'odd':'even'; - - row[0] = {style:["productKey", rowStyle], text:productKey}; - row[1] = {style:["notes", rowStyle], text:notes}; - row[2] = {style:["cost", rowStyle], text:cost}; - row[3] = {style:["quantity", rowStyle], text:qty}; - row[4] = {style:["tax", rowStyle], text:""+tax}; - row[5] = {style:["lineTotal", rowStyle], text:lineTotal}; - - grid.push(row); - } - return grid; +var lineTotal = roundToTwo(NINJA.parseFloat(item.cost)) * roundToTwo(NINJA.parseFloat(item.qty)); +if (tax) { + lineTotal += lineTotal * tax / 100; +} +if (lineTotal) { + total += lineTotal; +} +lineTotal = formatMoney(lineTotal, currencyId); + +rowStyle = i%2===0?'odd':'even'; + +row[0] = {style:["productKey", rowStyle], text:productKey}; +row[1] = {style:["notes", rowStyle], text:notes}; +row[2] = {style:["cost", rowStyle], text:cost}; +row[3] = {style:["quantity", rowStyle], text:qty}; +row[4] = {style:["tax", rowStyle], text:""+tax}; +row[5] = {style:["lineTotal", rowStyle], text:lineTotal}; + +grid.push(row); +} +return grid; } function subtotals(invoice) { - if (!invoice) { - return; - } + if (!invoice) { + return; + } - var data = [ + var data = [ [invoiceLabels.subtotal, formatMoney(invoice.subtotal_amount, invoice.client.currency_id)], - ]; - if(invoice.discount_amount != 0) { - data.push([invoiceLabels.discount, formatMoney(invoice.discount_amount, invoice.client.currency_id)]); - } + ]; + if(invoice.discount_amount != 0) { + data.push([invoiceLabels.discount, formatMoney(invoice.discount_amount, invoice.client.currency_id)]); + } - if (NINJA.parseFloat(invoice.custom_value1) && invoice.custom_taxes1 == '1') { - data.push([invoiceLabels.custom_invoice_label1, formatMoney(invoice.custom_value1, invoice.client.currency_id)]); - } - if (NINJA.parseFloat(invoice.custom_value2) && invoice.custom_taxes2 == '1') { - data.push([invoiceLabels.custom_invoice_label2, formatMoney(invoice.custom_value2, invoice.client.currency_id)]); - } + if (NINJA.parseFloat(invoice.custom_value1) && invoice.custom_taxes1 == '1') { + data.push([invoiceLabels.custom_invoice_label1, formatMoney(invoice.custom_value1, invoice.client.currency_id)]); + } + if (NINJA.parseFloat(invoice.custom_value2) && invoice.custom_taxes2 == '1') { + data.push([invoiceLabels.custom_invoice_label2, formatMoney(invoice.custom_value2, invoice.client.currency_id)]); + } - if(invoice.tax && invoice.tax.name || invoice.tax_name) { - data.push([invoiceLabels.tax, formatMoney(invoice.tax_amount, invoice.client.currency_id)]); - } + if(invoice.tax && invoice.tax.name || invoice.tax_name) { + data.push([invoiceLabels.tax, formatMoney(invoice.tax_amount, invoice.client.currency_id)]); + } - if (NINJA.parseFloat(invoice.custom_value1) && invoice.custom_taxes1 != '1') { - data.push([invoiceLabels.custom_invoice_label1, formatMoney(invoice.custom_value1, invoice.client.currency_id)]); - } - if (NINJA.parseFloat(invoice.custom_value2) && invoice.custom_taxes2 != '1') { - data.push([invoiceLabels.custom_invoice_label2, formatMoney(invoice.custom_value2, invoice.client.currency_id)]); - } + if (NINJA.parseFloat(invoice.custom_value1) && invoice.custom_taxes1 != '1') { + data.push([invoiceLabels.custom_invoice_label1, formatMoney(invoice.custom_value1, invoice.client.currency_id)]); + } + if (NINJA.parseFloat(invoice.custom_value2) && invoice.custom_taxes2 != '1') { + data.push([invoiceLabels.custom_invoice_label2, formatMoney(invoice.custom_value2, invoice.client.currency_id)]); + } - var paid = invoice.amount - invoice.balance; - if (invoice.account.hide_paid_to_date != '1' || paid) { - data.push([invoiceLabels.paid_to_date, formatMoney(paid, invoice.client.currency_id)]); - } + var paid = invoice.amount - invoice.balance; + if (invoice.account.hide_paid_to_date != '1' || paid) { + data.push([invoiceLabels.paid_to_date, formatMoney(paid, invoice.client.currency_id)]); + } - data.push([{text:invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due, style:'balanceDueLabel'}, - {text:formatMoney(invoice.balance_amount, invoice.client.currency_id), style:'balanceDueValue'}]); - return data; - } - - function accountDetails(account) { - var data = []; - if(account.name) data.push({text:account.name, 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.work_email) data.push({text:account.work_email, style:'accountDetails'}); - if(account.work_phone) data.push({text:account.work_phone, style:'accountDetails'}); - return data; + data.push([{text:invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due, style:'balanceDueLabel'}, + {text:formatMoney(invoice.balance_amount, invoice.client.currency_id), style:'balanceDueValue'}]); + return data; +} + +function accountDetails(account) { + var data = []; + if(account.name) data.push({text:account.name, style:'accountName'}); + if(account.id_number) data.push({text:account.id_number, style:'accountDetails'}); + if(account.vat_number) data.push({text:account.vat_number, style:'accountDetails'}); + if(account.work_email) data.push({text:account.work_email, style:'accountDetails'}); + if(account.work_phone) data.push({text:account.work_phone, style:'accountDetails'}); + return data; } function accountAddress(account) { - var data = []; - if(account.address1) data.push({text:account.address1, style:'accountDetails'}); - if(account.address2) data.push({text:account.address2, style:'accountDetails'}); - if(account.city) data.push({text:account.city, style:'accountDetails'}); - if(account.state) data.push({text:account.state, style:'accountDetails'}); - if(account.postal_code) data.push({text:account.postal_code, style:'accountDetails'}); - return data; + var address = ''; + if (account.city || account.state || account.postal_code) { + address = ((account.city ? account.city + ', ' : '') + account.state + ' ' + account.postal_code).trim(); + } + var data = []; + if(account.address1) data.push({text:account.address1, style:'accountDetails'}); + if(account.address2) data.push({text:account.address2, style:'accountDetails'}); + if(address) data.push({text:address, style:'accountDetails'}); + if(account.country) data.push({text:account.country.name, style: 'accountDetails'}); + 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 'Export', 'documentation' => 'Documentation', 'zapier' => 'Zapier Beta', + 'recurring' => 'Recurring', + 'last_invoice_sent' => 'Last invoice sent :date', + + ); diff --git a/resources/views/accounts/invoice_settings.blade.php b/resources/views/accounts/invoice_settings.blade.php index d470ade4a168..097cd1e0d02f 100644 --- a/resources/views/accounts/invoice_settings.blade.php +++ b/resources/views/accounts/invoice_settings.blade.php @@ -98,8 +98,10 @@
{!! 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('auto_wrap')->text(trans('texts.enable')) !!} +
diff --git a/resources/views/accounts/token_management.blade.php b/resources/views/accounts/token_management.blade.php index 66f6901bad37..8bd620e163ed 100644 --- a/resources/views/accounts/token_management.blade.php +++ b/resources/views/accounts/token_management.blade.php @@ -14,7 +14,9 @@
{!! Button::normal(trans('texts.documentation'))->asLinkTo(NINJA_WEB_URL.'/knowledgebase/api-documentation/')->withAttributes(['target' => '_blank']) !!} - {!! Button::normal(trans('texts.zapier'))->asLinkTo(ZAPIER_URL)->withAttributes(['target' => '_blank']) !!} + @if (Utils::isNinja()) + {!! Button::normal(trans('texts.zapier'))->asLinkTo(ZAPIER_URL)->withAttributes(['target' => '_blank']) !!} + @endif @if (Utils::isPro()) {!! Button::primary(trans('texts.add_token'))->asLinkTo('/tokens/create')->appendIcon(Icon::create('plus-sign')) !!} @endif diff --git a/resources/views/dashboard.blade.php b/resources/views/dashboard.blade.php index b53a288d01b2..db77a4c96adf 100644 --- a/resources/views/dashboard.blade.php +++ b/resources/views/dashboard.blade.php @@ -90,7 +90,7 @@ @foreach ($pastDue as $invoice) @if (!$invoice->client->trashed()) - {{ $invoice->getLink() }} + {!! $invoice->getLink() !!} {{ $invoice->client->getDisplayName() }} {{ Utils::fromSqlDate($invoice->due_date) }} {{ Utils::formatMoney($invoice->balance, $invoice->client->currency_id) }} diff --git a/resources/views/header.blade.php b/resources/views/header.blade.php index 70bb49687c9e..0530613307de 100644 --- a/resources/views/header.blade.php +++ b/resources/views/header.blade.php @@ -19,6 +19,12 @@ } } + @media screen and (max-width: 768px) { + body { + padding-top: 56px; + } + } + @include('script') diff --git a/resources/views/invoices/edit.blade.php b/resources/views/invoices/edit.blade.php index fe2a9868ddff..56ed502111c6 100644 --- a/resources/views/invoices/edit.blade.php +++ b/resources/views/invoices/edit.blade.php @@ -11,14 +11,6 @@ @endif - @stop @section('content') @@ -86,9 +78,7 @@ {!! 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('') !!} - {!! Former::text('partial')->data_bind("value: partial, valueUpdate: 'afterkeydown', enable: is_partial") - ->onchange('onPartialChange()')->addGroupClass('partial')->append(Former::checkbox('is_partial')->raw() - ->data_bind('checked: is_partial')->onclick('onPartialEnabled()') . ' ' . (trans('texts.enable'))) !!} + {!! Former::text('partial')->data_bind("value: partial, valueUpdate: 'afterkeydown'")->onchange('onPartialChange()') !!}
@if ($entityType == ENTITY_INVOICE)
@@ -104,8 +94,24 @@
@else
- {!! Former::checkbox('recurring')->onclick('onRecurringEnabled()')->text(trans('texts.enable').'    '.trans('texts.learn_more').'')->data_bind("checked: is_recurring") - ->inlineHelp($invoice && $invoice->last_sent_date ? 'Last invoice sent ' . Utils::dateToString($invoice->last_sent_date) : '') !!} +
+ +
+
+ +
+
+
+ @if ($invoice && $invoice->last_sent_date) +
+ {{ trans('texts.last_invoice_sent', ['date' => Utils::dateToString($invoice->last_sent_date)]) }} +
+ @endif
@endif @endif @@ -1130,7 +1136,6 @@ self.balance = ko.observable(0); self.invoice_design_id = ko.observable({{ $account->utf8_invoices ? 1 : $account->invoice_design_id }}); self.partial = ko.observable(0); - self.is_partial = ko.observable(false); self.custom_value1 = ko.observable(0); self.custom_value2 = ko.observable(0); @@ -1336,7 +1341,7 @@ }); 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) { @@ -1647,19 +1652,7 @@ { var val = NINJA.parseFloat($('#partial').val()); val = Math.max(Math.min(val, model.invoice().totals.rawTotal()), 0); - $('#partial').val(val); - } - - function onPartialEnabled() - { - model.invoice().partial(''); - refreshPDF(); - - if ($('#is_partial').prop('checked')) { - setTimeout(function() { - $('#partial').focus(); - }, 1); - } + $('#partial').val(val || ''); } function onRecurringEnabled() @@ -1702,9 +1695,6 @@ @if ($invoice) var invoice = {!! $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 client = clientMap[invoice.client.public_id]; if (client) { // in case it's deleted