Add quotes to the dashboard and a map to the client page

This commit is contained in:
Hillel Coren 2015-10-06 20:55:55 +03:00
parent 746952f972
commit a1cef22a48
35 changed files with 365 additions and 157 deletions

View File

@ -41,6 +41,7 @@ class SendReminders extends Command
foreach ($invoices as $invoice) {
if ($reminder = $invoice->getReminder()) {
$this->info('Send to' . $invoice->id);
$this->mailer->sendInvoice($invoice, $reminder);
}
}

View File

@ -77,9 +77,10 @@ class DashboardController extends BaseController
//->where('invoices.is_quote', '=', false)
->where('invoices.balance', '>', 0)
->where('invoices.is_deleted', '=', false)
->where('invoices.deleted_at', '=', null)
->where('contacts.is_primary', '=', true)
->where('invoices.due_date', '<', date('Y-m-d'))
->select(['invoices.due_date', 'invoices.balance', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id'])
->select(['invoices.due_date', 'invoices.balance', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id', 'is_quote'])
->orderBy('invoices.due_date', 'asc')
->take(50)
->get();
@ -90,6 +91,7 @@ class DashboardController extends BaseController
->where('invoices.account_id', '=', Auth::user()->account_id)
->where('clients.deleted_at', '=', null)
->where('contacts.deleted_at', '=', null)
->where('invoices.deleted_at', '=', null)
->where('invoices.is_recurring', '=', false)
//->where('invoices.is_quote', '=', false)
->where('invoices.balance', '>', 0)
@ -98,7 +100,7 @@ class DashboardController extends BaseController
->where('invoices.due_date', '>=', date('Y-m-d'))
->orderBy('invoices.due_date', 'asc')
->take(50)
->select(['invoices.due_date', 'invoices.balance', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id'])
->select(['invoices.due_date', 'invoices.balance', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id', 'is_quote'])
->get();
$payments = DB::table('payments')
@ -114,6 +116,14 @@ class DashboardController extends BaseController
->take(50)
->get();
$hasQuotes = false;
foreach ([$upcoming, $pastDue] as $data) {
foreach ($data as $invoice) {
if ($invoice->is_quote) {
$hasQuotes = true;
}
}
}
$data = [
'account' => Auth::user()->account,
@ -127,6 +137,7 @@ class DashboardController extends BaseController
'upcoming' => $upcoming,
'payments' => $payments,
'title' => trans('texts.dashboard'),
'hasQuotes' => $hasQuotes,
];
return View::make('dashboard', $data);

View File

@ -258,6 +258,7 @@ class InvoiceController extends BaseController
'showApprove' => $showApprove,
'showBreadcrumbs' => false,
'hideLogo' => $account->isWhiteLabel(),
'hideHeader' => $account->isNinjaAccount(),
'invoice' => $invoice->hidePrivateFields(),
'invitation' => $invitation,
'invoiceLabels' => $account->getInvoiceLabels(),

View File

@ -246,6 +246,7 @@ class PaymentController extends BaseController
'currencyCode' => $client->currency ? $client->currency->code : ($account->currency ? $account->currency->code : 'USD'),
'account' => $client->account,
'hideLogo' => $account->isWhiteLabel(),
'hideHeader' => $account->isNinjaAccount(),
'showAddress' => $accountGateway->show_address,
];

View File

@ -348,6 +348,7 @@ if (!defined('CONTACT_EMAIL')) {
define('DEFAULT_DATETIME_MOMENT_FORMAT', 'MMM D, YYYY h:mm:ss a');
define('DEFAULT_QUERY_CACHE', 120); // minutes
define('DEFAULT_LOCALE', 'en');
define('DEFAULT_MAP_ZOOM', 10);
define('RESULT_SUCCESS', 'success');
define('RESULT_FAILURE', 'failure');
@ -387,7 +388,7 @@ if (!defined('CONTACT_EMAIL')) {
define('NINJA_FROM_EMAIL', 'maildelivery@invoiceninja.com');
define('RELEASES_URL', 'https://github.com/hillelcoren/invoice-ninja/releases/');
define('ZAPIER_URL', 'https://zapier.com/developer/invite/11276/85cf0ee4beae8e802c6c579eb4e351f1/');
define('ZAPIER_URL', 'https://zapier.com/zapbook/invoice-ninja');
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/');

View File

@ -203,49 +203,6 @@ class Utils
return floatval($value);
}
public static function formatPhoneNumber($phoneNumber)
{
$phoneNumber = preg_replace('/[^0-9a-zA-Z]/', '', $phoneNumber);
if (!$phoneNumber) {
return '';
}
if (strlen($phoneNumber) > 10) {
$countryCode = substr($phoneNumber, 0, strlen($phoneNumber)-10);
$areaCode = substr($phoneNumber, -10, 3);
$nextThree = substr($phoneNumber, -7, 3);
$lastFour = substr($phoneNumber, -4, 4);
$phoneNumber = '+'.$countryCode.' ('.$areaCode.') '.$nextThree.'-'.$lastFour;
} elseif (strlen($phoneNumber) == 10 && in_array(substr($phoneNumber, 0, 3), array(653, 656, 658, 659))) {
/**
* SG country code are 653, 656, 658, 659
* US area code consist of 650, 651 and 657
* @see http://en.wikipedia.org/wiki/Telephone_numbers_in_Singapore#Numbering_plan
* @see http://www.bennetyee.org/ucsd-pages/area.html
*/
$countryCode = substr($phoneNumber, 0, 2);
$nextFour = substr($phoneNumber, 2, 4);
$lastFour = substr($phoneNumber, 6, 4);
$phoneNumber = '+'.$countryCode.' '.$nextFour.' '.$lastFour;
} elseif (strlen($phoneNumber) == 10) {
$areaCode = substr($phoneNumber, 0, 3);
$nextThree = substr($phoneNumber, 3, 3);
$lastFour = substr($phoneNumber, 6, 4);
$phoneNumber = '('.$areaCode.') '.$nextThree.'-'.$lastFour;
} elseif (strlen($phoneNumber) == 7) {
$nextThree = substr($phoneNumber, 0, 3);
$lastFour = substr($phoneNumber, 3, 4);
$phoneNumber = $nextThree.'-'.$lastFour;
}
return $phoneNumber;
}
public static function formatMoney($value, $currencyId = false)
{
if (!$currencyId) {

View File

@ -321,13 +321,18 @@ class Account extends Eloquent
return $data;
}
public function isNinjaAccount()
{
return $this->account_key === NINJA_ACCOUNT_KEY;
}
public function isPro()
{
if (!Utils::isNinjaProd()) {
return true;
}
if ($this->account_key == NINJA_ACCOUNT_KEY) {
if ($this->isNinjaAccount()) {
return true;
}
@ -348,6 +353,10 @@ class Account extends Eloquent
public function isWhiteLabel()
{
if ($this->isNinjaAccount()) {
return false;
}
if (Utils::isNinjaProd()) {
return self::isPro() && $this->pro_plan_paid != NINJA_DATE;
} else {

View File

@ -61,7 +61,7 @@ class Activity extends Eloquent
public static function updateClient($client)
{
if ($client->is_deleted && !$client->getOriginal('is_deleted')) {
if ($client->isBeingDeleted()) {
$activity = Activity::getBlank();
$activity->client_id = $client->id;
$activity->activity_type_id = ACTIVITY_TYPE_DELETE_CLIENT;
@ -166,7 +166,7 @@ class Activity extends Eloquent
{
$client = $invoice->client;
if ($invoice->is_deleted && !$invoice->getOriginal('is_deleted')) {
if ($invoice->isBeingDeleted()) {
$adjustment = 0;
if (!$invoice->is_quote && !$invoice->is_recurring) {
$adjustment = $invoice->balance * -1;
@ -315,7 +315,7 @@ class Activity extends Eloquent
public static function updatePayment($payment)
{
if ($payment->is_deleted && !$payment->getOriginal('is_deleted')) {
if ($payment->isBeingDeleted()) {
$client = $payment->client;
$client->balance = $client->balance + $payment->amount;
$client->paid_to_date = $client->paid_to_date - $payment->amount;
@ -422,7 +422,7 @@ class Activity extends Eloquent
public static function updateCredit($credit)
{
if ($credit->is_deleted && !$credit->getOriginal('is_deleted')) {
if ($credit->isBeingDeleted()) {
$activity = Activity::getBlank();
$activity->credit_id = $credit->id;
$activity->client_id = $credit->client_id;

View File

@ -93,6 +93,26 @@ class Client extends EntityModel
return ENTITY_CLIENT;
}
public function hasAddress()
{
$fields = [
'address1',
'address2',
'city',
'state',
'postal_code',
'country_id',
];
foreach ($fields as $field) {
if ($this->$field) {
return true;
}
}
return false;
}
public function getWebsite()
{
if (!$this->website) {

View File

@ -112,4 +112,8 @@ class EntityModel extends Eloquent
return $data;
}
public function isBeingDeleted()
{
return $this->is_deleted && !$this->getOriginal('is_deleted');
}
}

View File

@ -27,6 +27,10 @@ class ContactMailer extends Mailer
$account->loadLocalizationSettings($client);
if ($account->pdf_email_attachment) {
$invoice->updateCachedPDF();
}
$view = 'invoice';
$accountName = $invoice->account->getDisplayName();
$emailTemplate = $invoice->account->getEmailTemplate($reminder ?: $entityType);

View File

@ -677,7 +677,7 @@ class InvoiceRepository
$invoices = Invoice::whereAccountId($account->id)
->where('balance', '>', 0)
->whereRaw($sql)
->whereRaw('(' . $sql . ')')
->get();
return $invoices;

View File

@ -93,6 +93,7 @@ class PaymentLibrariesSeeder extends Seeder
['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' => '.'],
['name' => 'United Arab Emirates Dirham', 'code' => 'AED', 'symbol' => 'DH ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Hong Kong Dollar', 'code' => 'HKD', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
];
foreach ($currencies as $currency) {

View File

@ -30404,14 +30404,11 @@ if (window.ko) {
function getContactDisplayName(contact)
{
var str = '';
if (contact.first_name || contact.last_name) {
str += contact.first_name + ' ' + contact.last_name;
return contact.first_name + ' ' + contact.last_name;
} else {
return contact.email;
}
if (str && contact.email) {
str += ' - ';
}
return str + contact.email;
}
function getClientDisplayName(client)
@ -31739,12 +31736,10 @@ NINJA.decodeJavascript = function(invoice, javascript)
var match = matches[i];
field = match.substring(2, match.indexOf('Value'));
field = toSnakeCase(field);
var value = getDescendantProp(invoice, field) || ' ';
value = doubleDollarSign(value);
if (field.toLowerCase().indexOf('date') >= 0 && value != ' ') {
value = moment(value, 'YYYY-MM-DD').format('MMM D YYYY');
}
javascript = javascript.replace(match, '"'+value+'"');
}
}

View File

@ -183,12 +183,10 @@ NINJA.decodeJavascript = function(invoice, javascript)
var match = matches[i];
field = match.substring(2, match.indexOf('Value'));
field = toSnakeCase(field);
var value = getDescendantProp(invoice, field) || ' ';
value = doubleDollarSign(value);
if (field.toLowerCase().indexOf('date') >= 0 && value != ' ') {
value = moment(value, 'YYYY-MM-DD').format('MMM D YYYY');
}
javascript = javascript.replace(match, '"'+value+'"');
}
}

View File

@ -526,14 +526,11 @@ if (window.ko) {
function getContactDisplayName(contact)
{
var str = '';
if (contact.first_name || contact.last_name) {
str += contact.first_name + ' ' + contact.last_name;
return contact.first_name + ' ' + contact.last_name;
} else {
return contact.email;
}
if (str && contact.email) {
str += ' - ';
}
return str + contact.email;
}
function getClientDisplayName(client)

View File

@ -621,7 +621,7 @@
'run' => 'Kør',
'export' => 'Eksport',
'documentation' => 'Dokumentation',
'zapier' => 'Zapier <sup>Beta</sup>',
'zapier' => 'Zapier',
'recurring' => 'Gentagne',
'last_invoice_sent' => 'Sidste faktura sendt :date',
@ -793,6 +793,8 @@
'last_sent_on' => 'Last sent on :date',
'page_expire' => 'This page will expire soon, :click_here to keep working',
'upcoming_quotes' => 'Upcoming Quotes',
'expired_quotes' => 'Expired Quotes',
);

View File

@ -621,7 +621,7 @@ return array(
'run' => 'Ausführen',
'export' => 'Exportieren',
'documentation' => 'Dokumentation',
'zapier' => 'Zapier <sup>Beta</sup>',
'zapier' => 'Zapier',
'recurring' => 'Wiederkehrend',
'last_invoice_sent' => 'Letzte Rechnung verschickt am :date',
@ -792,6 +792,8 @@ return array(
'last_sent_on' => 'Zuletzt versendet am :date',
'page_expire' => 'Diese Seite wird bald ablaufen, :click_here um weiter zu arbeiten',
'upcoming_quotes' => 'Upcoming Quotes',
'expired_quotes' => 'Expired Quotes',
);

View File

@ -621,7 +621,7 @@ return array(
'run' => 'Run',
'export' => 'Export',
'documentation' => 'Documentation',
'zapier' => 'Zapier <sup>Beta</sup>',
'zapier' => 'Zapier',
'recurring' => 'Recurring',
'last_invoice_sent' => 'Last invoice sent :date',
@ -792,6 +792,9 @@ return array(
'last_sent_on' => 'Last sent on :date',
'page_expire' => 'This page will expire soon, :click_here to keep working',
'upcoming_quotes' => 'Upcoming Quotes',
'expired_quotes' => 'Expired Quotes',
);

View File

@ -592,7 +592,7 @@ return array(
'run' => 'Ejecutar',
'export' => 'Exportar',
'documentation' => 'Documentación',
'zapier' => 'Zapier <sup>Beta</sup>',
'zapier' => 'Zapier',
'recurring' => 'Recurrente',
'last_invoice_sent' => 'Ultima factura enviada en :date',
@ -770,6 +770,8 @@ return array(
'last_sent_on' => 'ültimo enviado en :date',
'page_expire' => 'Esta página expirará pronto, :click_here para que siga funcionando',
'upcoming_quotes' => 'Upcoming Quotes',
'expired_quotes' => 'Expired Quotes',
);

View File

@ -621,7 +621,7 @@ return array(
'run' => 'Run',
'export' => 'Export',
'documentation' => 'Documentation',
'zapier' => 'Zapier <sup>Beta</sup>',
'zapier' => 'Zapier',
'recurring' => 'Recurring',
'last_invoice_sent' => 'Last invoice sent :date',
@ -792,6 +792,8 @@ return array(
'last_sent_on' => 'Last sent on :date',
'page_expire' => 'This page will expire soon, :click_here to keep working',
'upcoming_quotes' => 'Upcoming Quotes',
'expired_quotes' => 'Expired Quotes',
);

View File

@ -613,7 +613,7 @@ return array(
'run' => 'Run',
'export' => 'Exporter',
'documentation' => 'Documentation',
'zapier' => 'Zapier <sup>Beta</sup>',
'zapier' => 'Zapier',
'recurring' => 'Récurrent',
'last_invoice_sent' => 'Dernière facture envoyée le :date',
@ -784,6 +784,8 @@ return array(
'last_sent_on' => 'Last sent on :date',
'page_expire' => 'This page will expire soon, :click_here to keep working',
'upcoming_quotes' => 'Upcoming Quotes',
'expired_quotes' => 'Expired Quotes',
);

View File

@ -613,7 +613,7 @@ return array(
'run' => 'Run',
'export' => 'Export',
'documentation' => 'Documentation',
'zapier' => 'Zapier <sup>Beta</sup>',
'zapier' => 'Zapier',
'recurring' => 'Recurring',
'last_invoice_sent' => 'Last invoice sent :date',
@ -785,6 +785,8 @@ return array(
'last_sent_on' => 'Last sent on :date',
'page_expire' => 'This page will expire soon, :click_here to keep working',
'upcoming_quotes' => 'Upcoming Quotes',
'expired_quotes' => 'Expired Quotes',
);

View File

@ -615,7 +615,7 @@ return array(
'run' => 'Run',
'export' => 'Export',
'documentation' => 'Documentation',
'zapier' => 'Zapier <sup>Beta</sup>',
'zapier' => 'Zapier',
'recurring' => 'Recurring',
'last_invoice_sent' => 'Last invoice sent :date',
@ -787,5 +787,7 @@ return array(
'last_sent_on' => 'Last sent on :date',
'page_expire' => 'This page will expire soon, :click_here to keep working',
'upcoming_quotes' => 'Upcoming Quotes',
'expired_quotes' => 'Expired Quotes',
);

View File

@ -623,7 +623,7 @@ return array(
'run' => 'Run',
'export' => 'Export',
'documentation' => 'Documentation',
'zapier' => 'Zapier <sup>Beta</sup>',
'zapier' => 'Zapier',
'recurring' => 'Recurring',
'last_invoice_sent' => 'Last invoice sent :date',
@ -795,6 +795,8 @@ return array(
'last_sent_on' => 'Last sent on :date',
'page_expire' => 'This page will expire soon, :click_here to keep working',
'upcoming_quotes' => 'Upcoming Quotes',
'expired_quotes' => 'Expired Quotes',
);

View File

@ -621,7 +621,7 @@ return array(
'run' => 'Run',
'export' => 'Export',
'documentation' => 'Documentation',
'zapier' => 'Zapier <sup>Beta</sup>',
'zapier' => 'Zapier',
'recurring' => 'Recurring',
'last_invoice_sent' => 'Last invoice sent :date',
@ -792,5 +792,7 @@ return array(
'last_sent_on' => 'Last sent on :date',
'page_expire' => 'This page will expire soon, :click_here to keep working',
'upcoming_quotes' => 'Upcoming Quotes',
'expired_quotes' => 'Expired Quotes',
);

View File

@ -616,7 +616,7 @@ return array(
'run' => 'Uitvoeren',
'export' => 'Exporteer',
'documentation' => 'Documentatie',
'zapier' => 'Zapier <sup>Beta</sup>',
'zapier' => 'Zapier',
'recurring' => 'Terugkerend',
'last_invoice_sent' => 'Laatste factuur verzonden :date',
@ -787,5 +787,7 @@ return array(
'last_sent_on' => 'Last sent on :date',
'page_expire' => 'This page will expire soon, :click_here to keep working',
'upcoming_quotes' => 'Upcoming Quotes',
'expired_quotes' => 'Expired Quotes',
);

View File

@ -616,7 +616,7 @@ return array(
'run' => 'Run',
'export' => 'Export',
'documentation' => 'Documentation',
'zapier' => 'Zapier <sup>Beta</sup>',
'zapier' => 'Zapier',
'recurring' => 'Recurring',
'last_invoice_sent' => 'Last invoice sent :date',
@ -787,5 +787,7 @@ return array(
'last_sent_on' => 'Last sent on :date',
'page_expire' => 'This page will expire soon, :click_here to keep working',
'upcoming_quotes' => 'Upcoming Quotes',
'expired_quotes' => 'Expired Quotes',
);

View File

@ -619,7 +619,7 @@ return array(
'run' => 'Run',
'export' => 'Export',
'documentation' => 'Documentation',
'zapier' => 'Zapier <sup>Beta</sup>',
'zapier' => 'Zapier',
'recurring' => 'Recurring',
'last_invoice_sent' => 'Last invoice sent :date',
@ -790,5 +790,7 @@ return array(
'last_sent_on' => 'Last sent on :date',
'page_expire' => 'This page will expire soon, :click_here to keep working',
'upcoming_quotes' => 'Upcoming Quotes',
'expired_quotes' => 'Expired Quotes',
);

View File

@ -1,7 +1,25 @@
@extends('header')
@section('content')
@section('head')
@parent
@if ($client->hasAddress())
<style>
#map {
width: 100%;
height: 200px;
border-width: 1px;
border-style: solid;
border-color: #ddd;
}
</style>
<script src="https://maps.googleapis.com/maps/api/js"></script>
@endif
@stop
@section('content')
<div class="pull-right">
{!! Former::open('clients/bulk')->addClass('mainForm') !!}
@ -81,7 +99,7 @@
@endif
@if ($client->work_phone)
<i class="fa fa-phone" style="width: 20px"></i>{{ Utils::formatPhoneNumber($client->work_phone) }}
<i class="fa fa-phone" style="width: 20px"></i>{{ $client->work_phone }}
@endif
@if ($client->private_notes)
@ -116,14 +134,14 @@
<i class="fa fa-envelope" style="width: 20px"></i>{!! HTML::mailto($contact->email, $contact->email) !!}<br/>
@endif
@if ($contact->phone)
<i class="fa fa-phone" style="width: 20px"></i>{!! Utils::formatPhoneNumber($contact->phone) !!}<br/>
<i class="fa fa-phone" style="width: 20px"></i>{{ $contact->phone }}<br/>
@endif
@endforeach
</div>
<div class="col-md-6">
<div class="col-md-4">
<h3>{{ trans('texts.standing') }}
<table class="table" style="width:300px">
<table class="table" style="width:100%">
<tr>
<td><small>{{ trans('texts.paid_to_date') }}</small></td>
<td style="text-align: right">{{ Utils::formatMoney($client->paid_to_date, $client->getCurrencyId()) }}</td>
@ -140,12 +158,16 @@
@endif
</table>
</h3>
</div>
</div>
</div>
</div>
@if ($client->hasAddress())
<div id="map"></div>
<br/>
@endif
<ul class="nav nav-tabs nav-justified">
{!! HTML::tab_link('#activity', trans('texts.activity'), true) !!}
@if ($hasTasks)
@ -307,6 +329,50 @@
}
}
@if ($client->hasAddress())
function initialize() {
var mapCanvas = document.getElementById('map');
var mapOptions = {
zoom: {{ DEFAULT_MAP_ZOOM }},
mapTypeId: google.maps.MapTypeId.ROADMAP,
zoomControl: true,
};
var map = new google.maps.Map(mapCanvas, mapOptions)
var address = "{{ "{$client->address1} {$client->address2} {$client->city} {$client->state} {$client->postal_code} " . ($client->country ? $client->country->name : '') }}";
geocoder = new google.maps.Geocoder();
geocoder.geocode( { 'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (status != google.maps.GeocoderStatus.ZERO_RESULTS) {
var result = results[0];
map.setCenter(result.geometry.location);
var infowindow = new google.maps.InfoWindow(
{ content: '<b>'+result.formatted_address+'</b>',
size: new google.maps.Size(150, 50)
});
var marker = new google.maps.Marker({
position: result.geometry.location,
map: map,
title:address,
});
google.maps.event.addListener(marker, 'click', function() {
infowindow.open(map, marker);
});
} else {
$('#map').hide();
}
} else {
$('#map').hide();
}
});
}
google.maps.event.addDomListener(window, 'load', initialize);
@endif
</script>
@stop

View File

@ -12,11 +12,11 @@
</div>
<div class="in-bold">
@if (count($paidToDate))
@foreach ($paidToDate as $item)
{{ Utils::formatMoney($item->value, $item->currency_id) }}<br/>
@endforeach
@foreach ($paidToDate as $item)
{{ Utils::formatMoney($item->value, $item->currency_id) }}<br/>
@endforeach
@else
{{ Utils::formatMoney(0) }}
{{ Utils::formatMoney(0) }}
@endif
</div>
</div>
@ -31,11 +31,11 @@
</div>
<div class="in-bold">
@if (count($averageInvoice))
@foreach ($averageInvoice as $item)
{{ Utils::formatMoney($item->invoice_avg, $item->currency_id) }}<br/>
@endforeach
@foreach ($averageInvoice as $item)
{{ Utils::formatMoney($item->invoice_avg, $item->currency_id) }}<br/>
@endforeach
@else
{{ Utils::formatMoney(0) }}
{{ Utils::formatMoney(0) }}
@endif
</div>
</div>
@ -50,11 +50,11 @@
</div>
<div class="in-bold">
@if (count($balances))
@foreach ($balances as $item)
{{ Utils::formatMoney($item->value, $item->currency_id) }}<br/>
@endforeach
@foreach ($balances as $item)
{{ Utils::formatMoney($item->value, $item->currency_id) }}<br/>
@endforeach
@else
{{ Utils::formatMoney(0) }}
{{ Utils::formatMoney(0) }}
@endif
</div>
</div>
@ -66,7 +66,7 @@
<p>&nbsp;</p>
<div class="row">
<div class="col-md-6">
<div class="col-md-6">
<div class="panel panel-default dashboard" style="height:320px">
<div class="panel-heading" style="background-color:#0b4d78 !important">
<h3 class="panel-title in-bold-white">
@ -85,6 +85,9 @@
@endforeach
</ul>
</div>
</div>
<div class="col-md-6">
<div class="panel panel-default dashboard" style="height:320px;">
<div class="panel-heading" style="margin:0; background-color: #f5f5f5 !important;">
<h3 class="panel-title" style="color: black !important">
@ -112,7 +115,40 @@
</table>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="panel panel-default dashboard" style="height:320px;">
<div class="panel-heading" style="margin:0; background-color: #f5f5f5 !important;">
<h3 class="panel-title" style="color: black !important">
<i class="glyphicon glyphicon-time"></i> {{ trans('texts.upcoming_invoices') }}
</h3>
</div>
<div class="panel-body" style="height:274px;overflow-y:auto;">
<table class="table table-striped">
<thead>
<th>{{ trans('texts.invoice_number_short') }}</th>
<th>{{ trans('texts.client') }}</th>
<th>{{ trans('texts.due_date') }}</th>
<th>{{ trans('texts.balance_due') }}</th>
</thead>
<tbody>
@foreach ($upcoming as $invoice)
@if (!$invoice->is_quote)
<tr>
<td>{!! \App\Models\Invoice::calcLink($invoice) !!}</td>
<td>{!! link_to('/clients/'.$invoice->client_public_id, trim($invoice->client_name) ?: (trim($invoice->first_name . ' ' . $invoice->last_name) ?: $invoice->email)) !!}</td>
<td>{{ Utils::fromSqlDate($invoice->due_date) }}</td>
<td>{{ Utils::formatMoney($invoice->balance, $invoice->currency_id ?: ($account->currency_id ?: DEFAULT_CURRENCY)) }}</td>
</tr>
@endif
@endforeach
</tbody>
</table>
</div>
</div>
</div>
<div class="col-md-6">
<div class="panel panel-default dashboard" style="height:320px">
@ -131,48 +167,90 @@
</thead>
<tbody>
@foreach ($pastDue as $invoice)
<tr>
<td>{!! \App\Models\Invoice::calcLink($invoice) !!}</td>
<td>{!! link_to('/clients/'.$invoice->client_public_id, trim($invoice->client_name) ?: (trim($invoice->first_name . ' ' . $invoice->last_name) ?: $invoice->email)) !!}</td>
<td>{{ Utils::fromSqlDate($invoice->due_date) }}</td>
<td>{{ Utils::formatMoney($invoice->balance, $invoice->currency_id ?: ($account->currency_id ?: DEFAULT_CURRENCY)) }}</td>
</tr>
@if (!$invoice->is_quote)
<tr>
<td>{!! \App\Models\Invoice::calcLink($invoice) !!}</td>
<td>{!! link_to('/clients/'.$invoice->client_public_id, trim($invoice->client_name) ?: (trim($invoice->first_name . ' ' . $invoice->last_name) ?: $invoice->email)) !!}</td>
<td>{{ Utils::fromSqlDate($invoice->due_date) }}</td>
<td>{{ Utils::formatMoney($invoice->balance, $invoice->currency_id ?: ($account->currency_id ?: DEFAULT_CURRENCY)) }}</td>
</tr>
@endif
@endforeach
</tbody>
</table>
</div>
</div>
<div class="panel panel-default dashboard" style="height:320px;">
<div class="panel-heading" style="margin:0; background-color: #f5f5f5 !important;">
<h3 class="panel-title" style="color: black !important">
<i class="glyphicon glyphicon-time"></i> {{ trans('texts.upcoming_invoices') }}
</h3>
</div>
<div class="panel-body" style="height:274px;overflow-y:auto;">
<table class="table table-striped">
<thead>
<th>{{ trans('texts.invoice_number_short') }}</th>
<th>{{ trans('texts.client') }}</th>
<th>{{ trans('texts.due_date') }}</th>
<th>{{ trans('texts.balance_due') }}</th>
</thead>
<tbody>
@foreach ($upcoming as $invoice)
<tr>
<td>{!! \App\Models\Invoice::calcLink($invoice) !!}</td>
<td>{!! link_to('/clients/'.$invoice->client_public_id, trim($invoice->client_name) ?: (trim($invoice->first_name . ' ' . $invoice->last_name) ?: $invoice->email)) !!}</td>
<td>{{ Utils::fromSqlDate($invoice->due_date) }}</td>
<td>{{ Utils::formatMoney($invoice->balance, $invoice->currency_id ?: ($account->currency_id ?: DEFAULT_CURRENCY)) }}</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div>
</div>
@if ($hasQuotes)
<div class="row">
<div class="col-md-6">
<div class="panel panel-default dashboard" style="height:320px;">
<div class="panel-heading" style="margin:0; background-color: #f5f5f5 !important;">
<h3 class="panel-title" style="color: black !important">
<i class="glyphicon glyphicon-time"></i> {{ trans('texts.upcoming_quotes') }}
</h3>
</div>
<div class="panel-body" style="height:274px;overflow-y:auto;">
<table class="table table-striped">
<thead>
<th>{{ trans('texts.quote_number_short') }}</th>
<th>{{ trans('texts.client') }}</th>
<th>{{ trans('texts.due_date') }}</th>
<th>{{ trans('texts.balance_due') }}</th>
</thead>
<tbody>
@foreach ($upcoming as $invoice)
@if ($invoice->is_quote)
<tr>
<td>{!! \App\Models\Invoice::calcLink($invoice) !!}</td>
<td>{!! link_to('/clients/'.$invoice->client_public_id, trim($invoice->client_name) ?: (trim($invoice->first_name . ' ' . $invoice->last_name) ?: $invoice->email)) !!}</td>
<td>{{ Utils::fromSqlDate($invoice->due_date) }}</td>
<td>{{ Utils::formatMoney($invoice->balance, $invoice->currency_id ?: ($account->currency_id ?: DEFAULT_CURRENCY)) }}</td>
</tr>
@endif
@endforeach
</tbody>
</table>
</div>
</div>
</div>
<div class="col-md-6">
<div class="panel panel-default dashboard" style="height:320px">
<div class="panel-heading" style="background-color:#e37329 !important">
<h3 class="panel-title in-bold-white">
<i class="glyphicon glyphicon-time"></i> {{ trans('texts.expired_quotes') }}
</h3>
</div>
<div class="panel-body" style="height:274px;overflow-y:auto;">
<table class="table table-striped">
<thead>
<th>{{ trans('texts.quote_number_short') }}</th>
<th>{{ trans('texts.client') }}</th>
<th>{{ trans('texts.due_date') }}</th>
<th>{{ trans('texts.balance_due') }}</th>
</thead>
<tbody>
@foreach ($pastDue as $invoice)
@if ($invoice->is_quote)
<tr>
<td>{!! \App\Models\Invoice::calcLink($invoice) !!}</td>
<td>{!! link_to('/clients/'.$invoice->client_public_id, trim($invoice->client_name) ?: (trim($invoice->first_name . ' ' . $invoice->last_name) ?: $invoice->email)) !!}</td>
<td>{{ Utils::fromSqlDate($invoice->due_date) }}</td>
<td>{{ Utils::formatMoney($invoice->balance, $invoice->currency_id ?: ($account->currency_id ?: DEFAULT_CURRENCY)) }}</td>
</tr>
@endif
@endforeach
</tbody>
</table>
</div>
</div>
</div>
</div>
@endif
<div class="row">
<div class="col-md-6">
</div>

View File

@ -124,6 +124,7 @@
if (result) {
localStorage.setItem('guest_key', '');
fbq('track', 'CompleteRegistration');
window._fbq.push(['track', '{{ env('FACEBOOK_PIXEL_SIGN_UP') }}', {'value':'0.00','currency':'USD'}]);
trackEvent('/account', '/signed_up');
NINJA.isRegistered = true;
$('#signUpButton').hide();

View File

@ -793,6 +793,11 @@
}
function onEmailClick() {
if (!isEmailValid()) {
alert("{!! trans('texts.provide_email') !!}");
return;
}
if (!NINJA.isRegistered) {
alert("{!! trans('texts.registration_required') !!}");
return;
@ -866,7 +871,7 @@
function isEmailValid() {
var isValid = false;
var sendTo = false;
var client = self.invoice().client();
var client = model.invoice().client();
for (var i=0; i<client.contacts().length; i++) {
var contact = client.contacts()[i];
if (isValidEmailAddress(contact.email())) {
@ -1171,14 +1176,10 @@
self.is_amount_discount = ko.observable(0);
self.frequency_id = ko.observable(4); // default to monthly
self.terms = ko.observable('');
//self.default_terms = ko.observable("{{ str_replace(["\r\n","\r","\n"], '\n', addslashes($account->invoice_terms)) }}");
//self.terms_placeholder = ko.observable({{ !$invoice && $account->invoice_terms ? 'true' : 'false' }} ? self.default_terms() : '');
self.default_terms = ko.observable(account.invoice_terms);
self.terms_placeholder = ko.observable({{ !$invoice && $account->invoice_terms ? 'account.invoice_terms' : false}});
self.set_default_terms = ko.observable(false);
self.invoice_footer = ko.observable('');
//self.default_footer = ko.observable("{{ str_replace(["\r\n","\r","\n"], '\n', addslashes($account->invoice_footer)) }}");
//self.footer_placeholder = ko.observable({{ !$invoice && $account->invoice_footer ? 'true' : 'false' }} ? self.default_footer() : '');
self.default_footer = ko.observable(account.invoice_footer);
self.footer_placeholder = ko.observable({{ !$invoice && $account->invoice_footer ? 'account.invoice_footer' : false}});
self.set_default_footer = ko.observable(false);

View File

@ -61,22 +61,39 @@
});
*/
@if (env('FACEBOOK_PIXEL'))
<!-- Facebook Pixel Code -->
!function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;
n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0;
t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window,
document,'script','//connect.facebook.net/en_US/fbevents.js');
fbq('init', '{{ env('FACEBOOK_PIXEL') }}');
fbq('track', "PageView");
(function() {
var _fbq = window._fbq || (window._fbq = []);
if (!_fbq.loaded) {
var fbds = document.createElement('script');
fbds.async = true;
fbds.src = '//connect.facebook.net/en_US/fbds.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(fbds, s);
_fbq.loaded = true;
}
})();
@else
function fbq() {
// do nothing
};
@endif
window._fbq = window._fbq || [];
</script>
<!-- Facebook Pixel Code -->
<script>
!function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;
n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0;
t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window,
document,'script','//connect.facebook.net/en_US/fbevents.js');
fbq('init', '{{ env('FACEBOOK_PIXEL') }}');
fbq('track', "PageView");</script>
<noscript><img height="1" width="1" style="display:none"
src="https://www.facebook.com/tr?id=770151509796760&ev=PageView&noscript=1"
/></noscript>
<!-- End Facebook Pixel Code -->
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
@ -135,7 +152,10 @@
});
@if (Session::has('trackEventCategory') && Session::has('trackEventAction'))
trackEvent('{{ session('trackEventCategory') }}', '{{ session('trackEventAction') }}');
trackEvent('{{ session('trackEventCategory') }}', '{{ session('trackEventAction') }}');
@if (Session::get('trackEventAction') === '/buy_pro_plan'))
window._fbq.push(['track', '{{ env('FACEBOOK_PIXEL_BUY_PRO') }}', {'value':'{{ PRO_PLAN_PRICE }}.00','currency':'USD'}]);
@endif
@endif
});
$('form').submit(function() {

View File

@ -0,0 +1,15 @@
<!-- Facebook Conversion Code for Checkouts -->
<script>(function() {
var _fbq = window._fbq || (window._fbq = []);
if (!_fbq.loaded) {
var fbds = document.createElement('script');
fbds.async = true;
fbds.src = '//connect.facebook.net/en_US/fbds.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(fbds, s);
_fbq.loaded = true;
}
})();
window._fbq = window._fbq || [];
window._fbq.push(['track', '{{ $pixelId }}', {'value':'{{ $price }}','currency':'USD'}]);
</script>