Added support for additional invoice designs
@ -31,8 +31,7 @@ module.exports = function(grunt) {
|
||||
'public/vendor/spectrum/spectrum.js',
|
||||
'public/js/bootstrap-combobox.js',
|
||||
'public/vendor/jspdf/dist/jspdf.min.js',
|
||||
//'public/js/jspdf.source.js',
|
||||
//'public/js/jspdf.plugin.split_text_to_size.js',
|
||||
'public/vendor/lightbox2/js/lightbox.min.js',
|
||||
'public/js/script.js',
|
||||
],
|
||||
dest: 'public/built.js',
|
||||
@ -58,6 +57,7 @@ module.exports = function(grunt) {
|
||||
'public/vendor/spectrum/spectrum.css',
|
||||
'public/css/bootstrap-combobox.css',
|
||||
'public/css/typeahead.js-bootstrap.css',
|
||||
'public/vendor/lightbox2/css/lightbox.css',
|
||||
'public/css/style.css',
|
||||
],
|
||||
dest: 'public/built.css',
|
||||
|
@ -283,7 +283,7 @@ class AccountController extends \BaseController {
|
||||
|
||||
$invoice->invoice_number = Auth::user()->account->getNextInvoiceNumber();
|
||||
$invoice->invoice_date = date_create()->format('Y-m-d');
|
||||
$invoice->account = Auth::user()->account;
|
||||
$invoice->account = json_decode(Auth::user()->account->toJson());
|
||||
$invoice->amount = $invoice->balance = 100;
|
||||
|
||||
$invoiceItem->cost = 100;
|
||||
@ -295,7 +295,7 @@ class AccountController extends \BaseController {
|
||||
$invoice->invoice_items = [$invoiceItem];
|
||||
|
||||
$data['invoice'] = $invoice;
|
||||
$data['invoiceDesigns'] = InvoiceDesign::remember(DEFAULT_QUERY_CACHE)->orderBy('id')->get();
|
||||
$data['invoiceDesigns'] = InvoiceDesign::remember(DEFAULT_QUERY_CACHE, 'invoice_designs_cache')->where('id', '<=', Auth::user()->maxInvoiceDesignId())->orderBy('id')->get();
|
||||
}
|
||||
|
||||
return View::make("accounts.{$subSection}", $data);
|
||||
|
@ -243,7 +243,7 @@ class InvoiceController extends \BaseController {
|
||||
'sizes' => Size::remember(DEFAULT_QUERY_CACHE)->orderBy('id')->get(),
|
||||
'paymentTerms' => PaymentTerm::remember(DEFAULT_QUERY_CACHE)->orderBy('num_days')->get(['name', 'num_days']),
|
||||
'industries' => Industry::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get(),
|
||||
'invoiceDesigns' => InvoiceDesign::remember(DEFAULT_QUERY_CACHE)->orderBy('id')->get(),
|
||||
'invoiceDesigns' => InvoiceDesign::remember(DEFAULT_QUERY_CACHE, 'invoice_designs_cache')->where('id', '<=', Auth::user()->maxInvoiceDesignId())->orderBy('id')->get(),
|
||||
'frequencies' => array(
|
||||
1 => 'Weekly',
|
||||
2 => 'Two weeks',
|
||||
|
@ -132,13 +132,13 @@ class PaymentController extends \BaseController
|
||||
return $gateway;
|
||||
}
|
||||
|
||||
private function getLicensePaymentDetails($input)
|
||||
private function getLicensePaymentDetails($input, $affiliate)
|
||||
{
|
||||
$data = self::convertInputForOmnipay($input);
|
||||
$card = new CreditCard($data);
|
||||
|
||||
return [
|
||||
'amount' => LICENSE_PRICE,
|
||||
'amount' => $affiliate->price,
|
||||
'card' => $card,
|
||||
'currency' => 'USD',
|
||||
'returnUrl' => URL::to('license_complete'),
|
||||
@ -310,12 +310,14 @@ class PaymentController extends \BaseController
|
||||
}
|
||||
}
|
||||
|
||||
Session::set('product_id', Input::get('product_id', PRODUCT_ONE_CLICK_INSTALL));
|
||||
|
||||
if (!Session::get('affiliate_id'))
|
||||
{
|
||||
return Utils::fatalError();
|
||||
}
|
||||
|
||||
if (Input::has('test_mode'))
|
||||
if (Utils::isNinjaDev() && Input::has('test_mode'))
|
||||
{
|
||||
Session::set('test_mode', Input::get('test_mode'));
|
||||
}
|
||||
@ -334,7 +336,7 @@ class PaymentController extends \BaseController
|
||||
'showBreadcrumbs' => false,
|
||||
'hideHeader' => true,
|
||||
'url' => 'license',
|
||||
'amount' => LICENSE_PRICE,
|
||||
'amount' => $affiliate->price,
|
||||
'client' => false,
|
||||
'contact' => false,
|
||||
'paymentLibrary' => $paymentLibrary,
|
||||
@ -380,6 +382,8 @@ class PaymentController extends \BaseController
|
||||
|
||||
try
|
||||
{
|
||||
$affiliate = Affiliate::find(Session::get('affiliate_id'));
|
||||
|
||||
if ($testMode)
|
||||
{
|
||||
$ref = 'TEST_MODE';
|
||||
@ -387,7 +391,7 @@ class PaymentController extends \BaseController
|
||||
else
|
||||
{
|
||||
$gateway = self::createGateway($accountGateway);
|
||||
$details = self::getLicensePaymentDetails(Input::all());
|
||||
$details = self::getLicensePaymentDetails(Input::all(), $affiliate);
|
||||
$response = $gateway->purchase($details)->send();
|
||||
$ref = $response->getTransactionReference();
|
||||
|
||||
@ -415,10 +419,9 @@ class PaymentController extends \BaseController
|
||||
$license->transaction_reference = $ref;
|
||||
$license->license_key = $licenseKey;
|
||||
$license->affiliate_id = Session::get('affiliate_id');
|
||||
$license->product_id = Session::get('product_id');
|
||||
$license->save();
|
||||
|
||||
$affiliate = Affiliate::find(Session::get('affiliate_id'));
|
||||
|
||||
$data = [
|
||||
'message' => $affiliate->payment_subtitle,
|
||||
'license' => $licenseKey,
|
||||
@ -426,11 +429,16 @@ class PaymentController extends \BaseController
|
||||
];
|
||||
|
||||
$name = "{$license->first_name} {$license->last_name}";
|
||||
$this->contactMailer->sendLicensePaymentConfirmation($name, $license->email, LICENSE_PRICE, $license->license_key);
|
||||
$this->contactMailer->sendLicensePaymentConfirmation($name, $license->email, $affiliate->price, $license->license_key, $license->product_id);
|
||||
|
||||
if (Session::has('return_url'))
|
||||
{
|
||||
return Redirect::away(Session::get('return_url') . "?license_key={$license->license_key}&product_id=" . Session::get('product_id'));
|
||||
}
|
||||
else
|
||||
{
|
||||
return View::make('public.license', $data);
|
||||
|
||||
//return Redirect::away(Session::get('return_url') . "?license_key={$license->license_key}");
|
||||
}
|
||||
}
|
||||
catch (\Exception $e)
|
||||
{
|
||||
@ -443,8 +451,13 @@ class PaymentController extends \BaseController
|
||||
|
||||
public function claim_license()
|
||||
{
|
||||
$license = License::where('license_key', '=', Input::get('license_key'))
|
||||
->where('is_claimed', '=', false)->first();
|
||||
$licenseKey = Input::get('license_key');
|
||||
$productId = Input::get('product_id', PRODUCT_ONE_CLICK_INSTALL);
|
||||
|
||||
$license = License::where('license_key', '=', $licenseKey)
|
||||
->where('is_claimed', '=', false)
|
||||
->where('product_id', '=', $productId)
|
||||
->first();
|
||||
|
||||
if ($license)
|
||||
{
|
||||
@ -454,7 +467,7 @@ class PaymentController extends \BaseController
|
||||
$license->save();
|
||||
}
|
||||
|
||||
return 'valid';
|
||||
return $productId == PRODUCT_ONE_CLICK_INSTALL ? 'valid' : $_ENV['INVOICE_DESIGNS'];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -95,7 +95,7 @@ class QuoteController extends \BaseController {
|
||||
'sizes' => Size::remember(DEFAULT_QUERY_CACHE)->orderBy('id')->get(),
|
||||
'paymentTerms' => PaymentTerm::remember(DEFAULT_QUERY_CACHE)->orderBy('num_days')->get(['name', 'num_days']),
|
||||
'industries' => Industry::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get(),
|
||||
'invoiceDesigns' => InvoiceDesign::remember(DEFAULT_QUERY_CACHE)->orderBy('id')->get(),
|
||||
'invoiceDesigns' => InvoiceDesign::remember(DEFAULT_QUERY_CACHE, 'invoice_designs_cache')->where('id', '<=', Auth::user()->maxInvoiceDesignId())->orderBy('id')->get(),
|
||||
'invoiceLabels' => Auth::user()->account->getInvoiceLabels()
|
||||
];
|
||||
}
|
||||
|
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AddAffiliatePrice extends Migration {
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('affiliates', function($table)
|
||||
{
|
||||
$table->decimal('price', 7, 2)->nullable();
|
||||
});
|
||||
|
||||
Schema::table('licenses', function($table)
|
||||
{
|
||||
$table->unsignedInteger('product_id')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('affiliates', function($table)
|
||||
{
|
||||
$table->dropColumn('price');
|
||||
});
|
||||
|
||||
Schema::table('licenses', function($table)
|
||||
{
|
||||
$table->dropColumn('product_id');
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -77,6 +77,34 @@ App::before(function($request)
|
||||
$locale = Session::get(SESSION_LOCALE, DEFAULT_LOCALE);
|
||||
App::setLocale($locale);
|
||||
}
|
||||
|
||||
$claimingLicense = Utils::startsWith($_SERVER['REQUEST_URI'], '/claim_license');
|
||||
if (!$claimingLicense && Input::has('license_key') && Input::has('product_id'))
|
||||
{
|
||||
$licenseKey = Input::get('license_key');
|
||||
$productId = Input::get('product_id');
|
||||
|
||||
if ($productId == PRODUCT_INVOICE_DESIGNS)
|
||||
{
|
||||
//$data = file_get_contents("http://ninja.dev/claim_license?license_key={$licenseKey}&product_id={$productId}");
|
||||
$data = file_get_contents(NINJA_URL . "/claim_license?license_key={$licenseKey}&product_id={$productId}");
|
||||
|
||||
if ($data = json_decode($data))
|
||||
{
|
||||
foreach ($data as $item)
|
||||
{
|
||||
$design = new InvoiceDesign();
|
||||
$design->id = $item->id;
|
||||
$design->name = $item->name;
|
||||
$design->javascript = $item->javascript;
|
||||
$design->save();
|
||||
}
|
||||
|
||||
Cache::forget('invoice_designs_cache');
|
||||
Session::flash('message', trans('texts.bought_designs'));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
@ -449,4 +449,14 @@ return array(
|
||||
'gateway_help_23' => 'Note: use your secret API key, not your publishable API key.',
|
||||
'gateway_help_27' => ':link to sign up for TwoCheckout.',
|
||||
|
||||
'more_designs' => 'More designs',
|
||||
'more_designs_title' => 'Additional Invoice Designs',
|
||||
'more_designs_cloud_header' => 'Go Pro for more invoice designs',
|
||||
'more_designs_cloud_text' => '',
|
||||
'more_designs_self_host_header' => 'Get 6 more invoice designs for just $20',
|
||||
'more_designs_self_host_text' => '',
|
||||
'buy' => 'Buy',
|
||||
'bought_designs' => 'Successfully added additional invoice designs',
|
||||
|
||||
|
||||
);
|
@ -85,6 +85,11 @@ class User extends ConfideUser implements UserInterface, RemindableInterface
|
||||
return $this->account->id == Utils::getDemoAccountId();
|
||||
}
|
||||
|
||||
public function maxInvoiceDesignId()
|
||||
{
|
||||
return $this->isPro() ? 10 : COUNT_FREE_DESIGNS;
|
||||
}
|
||||
|
||||
public function getDisplayName()
|
||||
{
|
||||
if ($this->getFullName())
|
||||
|
@ -37,7 +37,7 @@ class ContactMailer extends Mailer {
|
||||
'contactName' => $invitation->contact->getDisplayName(),
|
||||
'invoiceAmount' => Utils::formatMoney($invoice->amount, $invoice->client->currency_id),
|
||||
'emailFooter' => $invoice->account->email_footer,
|
||||
'showNinjaFooter' => !$invoice->account->isPro() || !Utils::isNinjaProd()
|
||||
'showNinjaFooter' => !$invoice->account->isPro()
|
||||
];
|
||||
|
||||
$fromEmail = $invitation->user->email;
|
||||
@ -67,25 +67,31 @@ class ContactMailer extends Mailer {
|
||||
'clientName' => $payment->client->getDisplayName(),
|
||||
'emailFooter' => $payment->account->email_footer,
|
||||
'paymentAmount' => Utils::formatMoney($payment->amount, $payment->client->currency_id),
|
||||
'showNinjaFooter' => !$payment->account->isPro() || !Utils::isNinjaProd()
|
||||
'showNinjaFooter' => !$payment->account->isPro()
|
||||
];
|
||||
|
||||
$user = $payment->invitation->user;
|
||||
$this->sendTo($payment->contact->email, $user->email, $user->getDisplayName(), $subject, $view, $data);
|
||||
}
|
||||
|
||||
public function sendLicensePaymentConfirmation($name, $email, $amount, $license)
|
||||
public function sendLicensePaymentConfirmation($name, $email, $amount, $license, $productId)
|
||||
{
|
||||
$view = 'payment_confirmation';
|
||||
$subject = trans('texts.payment_subject');
|
||||
|
||||
if ($productId == PRODUCT_ONE_CLICK_INSTALL) {
|
||||
$message = "Softaculous install license: $license";
|
||||
} else if ($productId == PRODUCT_INVOICE_DESIGNS) {
|
||||
$message = "Invoice designs license: $license";
|
||||
}
|
||||
|
||||
$data = [
|
||||
'accountName' => trans('texts.email_from'),
|
||||
'clientName' => $name,
|
||||
'emailFooter' => false,
|
||||
'paymentAmount' => Utils::formatMoney($amount, 1),
|
||||
'showNinjaFooter' => false,
|
||||
'emailMessage' => "Your license: $license",
|
||||
'emailMessage' => $message,
|
||||
];
|
||||
|
||||
$this->sendTo($email, CONTACT_EMAIL, CONTACT_NAME, $subject, $view, $data);
|
||||
|
@ -13,7 +13,7 @@
|
||||
*/
|
||||
|
||||
//apc_clear_cache();
|
||||
//Cache::flush();
|
||||
Cache::flush();
|
||||
|
||||
//dd(DB::getQueryLog());
|
||||
//dd(Client::getPrivateId(1));
|
||||
@ -248,8 +248,11 @@ define('NINJA_URL', 'https://www.invoiceninja.com');
|
||||
define('NINJA_VERSION', '1.4.0');
|
||||
define('RELEASES_URL', 'https://github.com/hillelcoren/invoice-ninja/releases/');
|
||||
|
||||
define('COUNT_FREE_DESIGNS', 4);
|
||||
define('PRO_PLAN_PRICE', 50);
|
||||
define('LICENSE_PRICE', 30.00);
|
||||
define('PRODUCT_ONE_CLICK_INSTALL', 1);
|
||||
define('PRODUCT_INVOICE_DESIGNS', 2);
|
||||
define('DESIGNS_AFFILIATE_KEY', 'T3RS74');
|
||||
|
||||
define('USER_TYPE_SELF_HOST', 'SELF_HOST');
|
||||
define('USER_TYPE_CLOUD_HOST', 'CLOUD_HOST');
|
||||
|
@ -17,8 +17,14 @@
|
||||
|
||||
function getDesignJavascript() {
|
||||
var id = $('#invoice_design_id').val();
|
||||
if (id == '-1') {
|
||||
showMoreDesigns();
|
||||
$('#invoice_design_id').val(1);
|
||||
return invoiceDesigns[0].javascript;
|
||||
} else {
|
||||
return invoiceDesigns[id-1].javascript;
|
||||
}
|
||||
}
|
||||
|
||||
function getPDFString() {
|
||||
invoice.is_pro = {{ Auth::user()->isPro() ? 'true' : 'false' }};
|
||||
@ -64,8 +70,15 @@
|
||||
{{ Former::populateField('hide_paid_to_date', intval($account->hide_paid_to_date)) }}
|
||||
|
||||
{{ Former::legend('invoice_design') }}
|
||||
{{ Former::select('invoice_design_id')->style('display:inline;width:120px')
|
||||
->fromQuery($invoiceDesigns, 'name', 'id') }}
|
||||
|
||||
|
||||
@if (InvoiceDesign::count() == COUNT_FREE_DESIGNS)
|
||||
{{ Former::select('invoice_design_id')->style('display:inline;width:120px')->fromQuery($invoiceDesigns, 'name', 'id')->addOption(trans('texts.more_designs') . '...', '-1') }}
|
||||
@else
|
||||
{{ Former::select('invoice_design_id')->style('display:inline;width:120px')->fromQuery($invoiceDesigns, 'name', 'id') }}
|
||||
@endif
|
||||
|
||||
|
||||
|
||||
{{ Former::text('primary_color') }}
|
||||
{{ Former::text('secondary_color') }}
|
||||
|
@ -265,10 +265,11 @@
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{{ Former::select('invoice_design_id')->style('display:inline;width:120px')->raw()
|
||||
->fromQuery($invoiceDesigns, 'name', 'id')->data_bind("value: invoice_design_id") }}
|
||||
|
||||
@if (InvoiceDesign::count() == COUNT_FREE_DESIGNS)
|
||||
{{ Former::select('invoice_design_id')->style('display:inline;width:150px')->raw()->fromQuery($invoiceDesigns, 'name', 'id')->data_bind("value: invoice_design_id")->addOption(trans('texts.more_designs') . '...', '-1') }}
|
||||
@else
|
||||
{{ Former::select('invoice_design_id')->style('display:inline;width:150px')->raw()->fromQuery($invoiceDesigns, 'name', 'id')->data_bind("value: invoice_design_id") }}
|
||||
@endif
|
||||
|
||||
{{ Button::primary(trans('texts.download_pdf'), array('onclick' => 'onDownloadClick()'))->append_with_icon('download-alt'); }}
|
||||
|
||||
@ -646,6 +647,7 @@
|
||||
function getPDFString() {
|
||||
var invoice = createInvoiceModel();
|
||||
var design = getDesignJavascript();
|
||||
if (!design) return;
|
||||
var doc = generatePDF(invoice, design);
|
||||
if (!doc) return;
|
||||
return doc.output('datauristring');
|
||||
@ -653,13 +655,21 @@
|
||||
|
||||
function getDesignJavascript() {
|
||||
var id = $('#invoice_design_id').val();
|
||||
if (id == '-1') {
|
||||
showMoreDesigns();
|
||||
$('#invoice_design_id').val(1);
|
||||
return invoiceDesigns[0].javascript;
|
||||
} else {
|
||||
return invoiceDesigns[id-1].javascript;
|
||||
}
|
||||
}
|
||||
|
||||
function onDownloadClick() {
|
||||
trackUrl('/download_pdf');
|
||||
var invoice = createInvoiceModel();
|
||||
var doc = generatePDF(invoice, true);
|
||||
var design = getDesignJavascript();
|
||||
if (!design) return;
|
||||
var doc = generatePDF(invoice, design, true);
|
||||
doc.save('Invoice-' + $('#invoice_number').val() + '.pdf');
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,54 @@
|
||||
<iframe id="theFrame" style="display:none" frameborder="1" width="100%" height="{{ isset($pdfHeight) ? $pdfHeight : 1180 }}px"></iframe>
|
||||
<canvas id="theCanvas" style="display:none;width:100%;border:solid 1px #CCCCCC;"></canvas>
|
||||
|
||||
<div class="modal fade" id="moreDesignsModal" tabindex="-1" role="dialog" aria-labelledby="moreDesignsModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title">{{ trans('texts.more_designs_title') }}</h4>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
@if (Utils::isNinja())
|
||||
<h3>{{ trans('texts.more_designs_cloud_header') }}</h3>
|
||||
<p>{{ trans('texts.more_designs_cloud_text') }}</p>
|
||||
@else
|
||||
<h3>{{ trans('texts.more_designs_self_host_header') }}</h3>
|
||||
<p>{{ trans('texts.more_designs_self_host_text') }}</p>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<center id="designThumbs">
|
||||
<p> </p>
|
||||
<a href="/images/designs/business.png" data-lightbox="more-designs" data-title="Business"><img src="/images/designs/business_thumb.png"/></a>
|
||||
<a href="/images/designs/creative.png" data-lightbox="more-designs" data-title="Creative"><img src="/images/designs/creative_thumb.png"/></a>
|
||||
<a href="/images/designs/elegant.png" data-lightbox="more-designs" data-title="Elegant"><img src="/images/designs/elegant_thumb.png"/></a>
|
||||
<p> </p>
|
||||
<a href="/images/designs/hipster.png" data-lightbox="more-designs" data-title="Hipster"><img src="/images/designs/hipster_thumb.png"/></a>
|
||||
<a href="/images/designs/playful.png" data-lightbox="more-designs" data-title="Playful"><img src="/images/designs/playful_thumb.png"/></a>
|
||||
<a href="/images/designs/photo.png" data-lightbox="more-designs" data-title="Photo"><img src="/images/designs/photo_thumb.png"/></a>
|
||||
<p> </p>
|
||||
</center>
|
||||
|
||||
<div class="modal-footer" id="signUpFooter">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">{{ trans('texts.cancel') }}</button>
|
||||
Coming soon
|
||||
|
||||
<!--
|
||||
@if (Utils::isNinja())
|
||||
<button type="button" class="btn btn-primary" onclick="submitProPlan()">{{ trans('texts.go_pro') }}</button>
|
||||
@else
|
||||
<button type="button" class="btn btn-primary" onclick="buyDesigns()">{{ trans('texts.buy') }}</button>
|
||||
@endif
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
window.logoImages = {};
|
||||
|
||||
@ -70,4 +118,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
function showMoreDesigns() {
|
||||
$('#moreDesignsModal').modal('show');
|
||||
}
|
||||
|
||||
function buyDesigns() {
|
||||
window.open('{{ NINJA_URL }}/license?return_url=' + window.location + '&affiliate_key={{ DESIGNS_AFFILIATE_KEY }}&product_id={{ PRODUCT_INVOICE_DESIGNS }}');
|
||||
}
|
||||
|
||||
</script>
|
@ -17,7 +17,8 @@
|
||||
"typeahead.js": "~0.9.3",
|
||||
"accounting": "~0.*",
|
||||
"spectrum": "~1.3.4",
|
||||
"d3": "~3.4.11"
|
||||
"d3": "~3.4.11",
|
||||
"lightbox2": "~2.7.1"
|
||||
},
|
||||
"resolutions": {
|
||||
"jquery": "~1.11"
|
||||
|
215
public/built.css
@ -1773,6 +1773,217 @@ See http://bgrins.github.io/spectrum/themes/ for instructions.
|
||||
border-radius: 6px;
|
||||
line-height: 1.33;
|
||||
}
|
||||
/* Preload images */
|
||||
body:after {
|
||||
content: url(images/lightbox/close.png) url(images/lightbox/loading.gif) url(images/lightbox/prev.png) url(images/lightbox/next.png);
|
||||
display: none;
|
||||
}
|
||||
|
||||
.lightboxOverlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 9999;
|
||||
background-color: black;
|
||||
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=80);
|
||||
opacity: 0.8;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.lightbox {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
z-index: 10000;
|
||||
text-align: center;
|
||||
line-height: 0;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.lightbox .lb-image {
|
||||
display: block;
|
||||
height: auto;
|
||||
max-width: inherit;
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
-ms-border-radius: 3px;
|
||||
-o-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.lightbox a img {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.lb-outerContainer {
|
||||
position: relative;
|
||||
background-color: white;
|
||||
*zoom: 1;
|
||||
width: 250px;
|
||||
height: 250px;
|
||||
margin: 0 auto;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
-ms-border-radius: 4px;
|
||||
-o-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.lb-outerContainer:after {
|
||||
content: "";
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.lb-container {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.lb-loader {
|
||||
position: absolute;
|
||||
top: 43%;
|
||||
left: 0;
|
||||
height: 25%;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.lb-cancel {
|
||||
display: block;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin: 0 auto;
|
||||
background: url(images/lightbox/loading.gif) no-repeat;
|
||||
}
|
||||
|
||||
.lb-nav {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.lb-container > .nav {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.lb-nav a {
|
||||
outline: none;
|
||||
background-image: url('data:image/gif;base64,R0lGODlhAQABAPAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==');
|
||||
}
|
||||
|
||||
.lb-prev, .lb-next {
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.lb-nav a.lb-prev {
|
||||
width: 34%;
|
||||
left: 0;
|
||||
float: left;
|
||||
background: url(images/lightbox/prev.png) left 48% no-repeat;
|
||||
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=0);
|
||||
opacity: 0;
|
||||
-webkit-transition: opacity 0.6s;
|
||||
-moz-transition: opacity 0.6s;
|
||||
-o-transition: opacity 0.6s;
|
||||
transition: opacity 0.6s;
|
||||
}
|
||||
|
||||
.lb-nav a.lb-prev:hover {
|
||||
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.lb-nav a.lb-next {
|
||||
width: 64%;
|
||||
right: 0;
|
||||
float: right;
|
||||
background: url(images/lightbox/next.png) right 48% no-repeat;
|
||||
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=0);
|
||||
opacity: 0;
|
||||
-webkit-transition: opacity 0.6s;
|
||||
-moz-transition: opacity 0.6s;
|
||||
-o-transition: opacity 0.6s;
|
||||
transition: opacity 0.6s;
|
||||
}
|
||||
|
||||
.lb-nav a.lb-next:hover {
|
||||
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.lb-dataContainer {
|
||||
margin: 0 auto;
|
||||
padding-top: 5px;
|
||||
*zoom: 1;
|
||||
width: 100%;
|
||||
-moz-border-radius-bottomleft: 4px;
|
||||
-webkit-border-bottom-left-radius: 4px;
|
||||
border-bottom-left-radius: 4px;
|
||||
-moz-border-radius-bottomright: 4px;
|
||||
-webkit-border-bottom-right-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
|
||||
.lb-dataContainer:after {
|
||||
content: "";
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.lb-data {
|
||||
padding: 0 4px;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.lb-data .lb-details {
|
||||
width: 85%;
|
||||
float: left;
|
||||
text-align: left;
|
||||
line-height: 1.1em;
|
||||
}
|
||||
|
||||
.lb-data .lb-caption {
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
line-height: 1em;
|
||||
}
|
||||
|
||||
.lb-data .lb-number {
|
||||
display: block;
|
||||
clear: left;
|
||||
padding-bottom: 1em;
|
||||
font-size: 12px;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.lb-data .lb-close {
|
||||
display: block;
|
||||
float: right;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
background: url(images/lightbox/close.png) top right no-repeat;
|
||||
text-align: right;
|
||||
outline: none;
|
||||
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=70);
|
||||
opacity: 0.7;
|
||||
-webkit-transition: opacity 0.2s;
|
||||
-moz-transition: opacity 0.2s;
|
||||
-o-transition: opacity 0.2s;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
.lb-data .lb-close:hover {
|
||||
cursor: pointer;
|
||||
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
body { background: #f8f8f8 !important;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
}
|
||||
@ -2482,6 +2693,10 @@ box-shadow: 0px 0px 15px 0px rgba(0, 5, 5, 0.2);
|
||||
.plans-table a .cta h2 span {background: #1e84a5;}
|
||||
|
||||
|
||||
#designThumbs img {
|
||||
border: 1px solid #CCCCCC;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 992px) {
|
||||
.hide-desktop {display: none;}
|
||||
}
|
||||
|
277
public/built.js
@ -707,6 +707,10 @@ box-shadow: 0px 0px 15px 0px rgba(0, 5, 5, 0.2);
|
||||
.plans-table a .cta h2 span {background: #1e84a5;}
|
||||
|
||||
|
||||
#designThumbs img {
|
||||
border: 1px solid #CCCCCC;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 992px) {
|
||||
.hide-desktop {display: none;}
|
||||
}
|
||||
|
BIN
public/images/designs/business.png
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
public/images/designs/business_thumb.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
public/images/designs/creative.png
Normal file
After Width: | Height: | Size: 47 KiB |
BIN
public/images/designs/creative_thumb.png
Normal file
After Width: | Height: | Size: 9.5 KiB |
BIN
public/images/designs/elegant.png
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
public/images/designs/elegant_thumb.png
Normal file
After Width: | Height: | Size: 7.4 KiB |
BIN
public/images/designs/hipster.png
Normal file
After Width: | Height: | Size: 41 KiB |
BIN
public/images/designs/hipster_thumb.png
Normal file
After Width: | Height: | Size: 8.4 KiB |
BIN
public/images/designs/photo.png
Normal file
After Width: | Height: | Size: 237 KiB |
BIN
public/images/designs/photo_thumb.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
public/images/designs/playful.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
public/images/designs/playful_thumb.png
Normal file
After Width: | Height: | Size: 9.8 KiB |
BIN
public/images/lightbox/close.png
Normal file
After Width: | Height: | Size: 280 B |
BIN
public/images/lightbox/loading.gif
Normal file
After Width: | Height: | Size: 8.3 KiB |
BIN
public/images/lightbox/next.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
public/images/lightbox/prev.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
@ -958,7 +958,6 @@ function getInvoiceTaxRate(invoice) {
|
||||
return tax;
|
||||
}
|
||||
|
||||
/*
|
||||
function displayInvoiceHeader(doc, invoice, layout) {
|
||||
|
||||
var costX = layout.unitCostRight - (doc.getStringUnitWidth(invoiceLabels.unit_cost) * doc.internal.getFontSize());
|
||||
@ -966,6 +965,15 @@ function displayInvoiceHeader(doc, invoice, layout) {
|
||||
var taxX = layout.taxRight - (doc.getStringUnitWidth(invoiceLabels.tax) * doc.internal.getFontSize());
|
||||
var totalX = layout.lineTotalRight - (doc.getStringUnitWidth(invoiceLabels.line_total) * doc.internal.getFontSize());
|
||||
|
||||
if (invoice.invoice_design_id == 6 || invoice.invoice_design_id == 8 || invoice.invoice_design_id == 10) {
|
||||
invoiceLabels.item = invoiceLabels.item.toUpperCase();
|
||||
invoiceLabels.description = invoiceLabels.description.toUpperCase();
|
||||
invoiceLabels.unit_cost = invoiceLabels.unit_cost.toUpperCase();
|
||||
invoiceLabels.quantity = invoiceLabels.quantity.toUpperCase();
|
||||
invoiceLabels.line_total = invoiceLabels.total.toUpperCase();
|
||||
invoiceLabels.tax = invoiceLabels.tax.toUpperCase();
|
||||
}
|
||||
|
||||
doc.text(layout.marginLeft, layout.tableTop, invoiceLabels.item);
|
||||
doc.text(layout.descriptionLeft, layout.tableTop, invoiceLabels.description);
|
||||
doc.text(costX, layout.tableTop, invoiceLabels.unit_cost);
|
||||
@ -978,257 +986,6 @@ function displayInvoiceHeader(doc, invoice, layout) {
|
||||
{
|
||||
doc.text(taxX, layout.tableTop, invoiceLabels.tax);
|
||||
}
|
||||
}
|
||||
|
||||
function displayInvoiceItems(doc, invoice, layout) {
|
||||
doc.setFontType("normal");
|
||||
|
||||
var line = 1;
|
||||
var total = 0;
|
||||
var shownItem = false;
|
||||
var currencyId = invoice && invoice.client ? invoice.client.currency_id : 1;
|
||||
var tableTop = layout.tableTop;
|
||||
var hideQuantity = invoice.account.hide_quantity == '1';
|
||||
|
||||
doc.setFontSize(8);
|
||||
for (var i=0; i<invoice.invoice_items.length; i++) {
|
||||
var item = invoice.invoice_items[i];
|
||||
var numLines = doc.splitTextToSize(item.notes, 200).length + 2;
|
||||
//console.log('num lines %s', numLines);
|
||||
|
||||
var y = tableTop + (line * layout.tableRowHeight) + (2 * layout.tablePadding);
|
||||
var top = y - layout.tablePadding;
|
||||
var newTop = top + (numLines * layout.tableRowHeight);
|
||||
|
||||
if (newTop > 770) {
|
||||
line = 0;
|
||||
tableTop = layout.accountTop + layout.tablePadding;
|
||||
y = tableTop;
|
||||
top = y - layout.tablePadding;
|
||||
newTop = top + (numLines * layout.tableRowHeight);
|
||||
doc.addPage();
|
||||
}
|
||||
|
||||
var left = layout.marginLeft - layout.tablePadding;
|
||||
var width = layout.marginRight + layout.tablePadding;
|
||||
|
||||
var cost = formatMoney(item.cost, currencyId, true);
|
||||
var qty = NINJA.parseFloat(item.qty) ? NINJA.parseFloat(item.qty) + '' : '';
|
||||
var notes = item.notes;
|
||||
var productKey = item.product_key;
|
||||
var tax = 0;
|
||||
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;
|
||||
|
||||
// process date variables
|
||||
notes = processVariables(notes);
|
||||
productKey = processVariables(productKey);
|
||||
|
||||
var lineTotal = NINJA.parseFloat(item.cost) * NINJA.parseFloat(item.qty);
|
||||
if (tax) {
|
||||
lineTotal += lineTotal * tax / 100;
|
||||
}
|
||||
if (lineTotal) {
|
||||
total += lineTotal;
|
||||
}
|
||||
lineTotal = formatMoney(lineTotal, currencyId);
|
||||
|
||||
var costX = layout.unitCostRight - (doc.getStringUnitWidth(cost) * doc.internal.getFontSize());
|
||||
var qtyX = layout.qtyRight - (doc.getStringUnitWidth(qty) * doc.internal.getFontSize());
|
||||
var taxX = layout.taxRight - (doc.getStringUnitWidth(tax+'%') * doc.internal.getFontSize());
|
||||
var totalX = layout.lineTotalRight - (doc.getStringUnitWidth(lineTotal) * doc.internal.getFontSize());
|
||||
|
||||
line += numLines;
|
||||
|
||||
if (invoice.invoice_design_id == 1) {
|
||||
if (i%2 == 0) {
|
||||
doc.setDrawColor(255,255,255);
|
||||
doc.setFillColor(246,246,246);
|
||||
doc.rect(left, top, width-left, newTop-top, 'FD');
|
||||
|
||||
doc.setLineWidth(0.3);
|
||||
doc.setDrawColor(200,200,200);
|
||||
doc.line(left, top, width, top);
|
||||
doc.line(left, newTop, width, newTop);
|
||||
}
|
||||
} else if (invoice.invoice_design_id == 2) {
|
||||
if (i%2 == 0) {
|
||||
left = 0;
|
||||
width = 1000;
|
||||
|
||||
doc.setDrawColor(255,255,255);
|
||||
doc.setFillColor(235,235,235);
|
||||
doc.rect(left, top, width-left, newTop-top, 'FD');
|
||||
|
||||
}
|
||||
} else if (invoice.invoice_design_id == 5) {
|
||||
if (i%2 == 0) {
|
||||
doc.setDrawColor(255,255,255);
|
||||
doc.setFillColor(247,247,247);
|
||||
doc.rect(left, top, width-left+17, newTop-top, 'FD');
|
||||
doc.setLineWidth(0.3);
|
||||
doc.setDrawColor(255,255,255);
|
||||
} else {
|
||||
doc.setDrawColor(255,255,255);
|
||||
doc.setFillColor(232,232,232);
|
||||
doc.rect(left, top, width-left+17, newTop-top, 'FD');
|
||||
|
||||
doc.setLineWidth(0.3);
|
||||
doc.setDrawColor(255,255,255);
|
||||
}
|
||||
} else {
|
||||
doc.setLineWidth(0.3);
|
||||
doc.setDrawColor(150,150,150);
|
||||
doc.line(left, newTop, width, newTop);
|
||||
}
|
||||
|
||||
y += 4;
|
||||
|
||||
if (invoice.invoice_design_id == 1) {
|
||||
SetPdfColor('LightBlue', doc, 'primary');
|
||||
} else if (invoice.invoice_design_id == 2) {
|
||||
SetPdfColor('SomeGreen', doc, 'primary');
|
||||
} else if (invoice.invoice_design_id == 3) {
|
||||
doc.setFontType('bold');
|
||||
} else if (invoice.invoice_design_id == 4) {
|
||||
SetPdfColor('Black', doc);
|
||||
} else if (invoice.invoice_design_id == 5) {
|
||||
SetPdfColor('Black', doc);
|
||||
}
|
||||
|
||||
var splitTitle = doc.splitTextToSize(productKey, 60);
|
||||
doc.text(layout.marginLeft, y+2, splitTitle);
|
||||
|
||||
if (invoice.invoice_design_id == 5) {
|
||||
doc.setDrawColor(255, 255, 255);
|
||||
doc.setLineWidth(1);
|
||||
doc.line(layout.descriptionLeft-8, y-16,layout.descriptionLeft-8, y+55);
|
||||
|
||||
doc.setDrawColor(255, 255, 255);
|
||||
doc.setLineWidth(1);
|
||||
doc.line(costX-30, y-16,costX-30, y+55);
|
||||
|
||||
doc.setDrawColor(255, 255, 255);
|
||||
doc.setLineWidth(1);
|
||||
doc.line(qtyX-45, y-16,qtyX-45, y+55);
|
||||
|
||||
if (invoice.has_taxes) {
|
||||
doc.setDrawColor(255, 255, 255);
|
||||
doc.setLineWidth(1);
|
||||
doc.line(taxX-15, y-16,taxX-15, y+55);
|
||||
}
|
||||
|
||||
doc.setDrawColor(255, 255, 255);
|
||||
doc.setLineWidth(1);
|
||||
doc.line(totalX-27, y-16,totalX-27, y+55);
|
||||
}
|
||||
|
||||
SetPdfColor('Black', doc);
|
||||
doc.setFontType('normal');
|
||||
|
||||
doc.text(layout.descriptionLeft, y+2, notes);
|
||||
doc.text(costX, y+2, cost);
|
||||
if (!hideQuantity) {
|
||||
doc.text(qtyX, y+2, qty);
|
||||
}
|
||||
doc.text(totalX, y+2, lineTotal);
|
||||
|
||||
if (tax) {
|
||||
doc.text(taxX, y+2, tax+'%');
|
||||
}
|
||||
}
|
||||
|
||||
y = tableTop + (line * layout.tableRowHeight) + (3 * layout.tablePadding);
|
||||
var cutoff = 700;
|
||||
if (invoice.terms) {
|
||||
cutoff -= 50;
|
||||
}
|
||||
if (invoice.public_notes) {
|
||||
cutoff -= 50;
|
||||
}
|
||||
|
||||
if (y > cutoff) {
|
||||
doc.addPage();
|
||||
return layout.marginLeft;
|
||||
}
|
||||
|
||||
return y;
|
||||
}
|
||||
*/
|
||||
|
||||
function displayInvoiceHeader(doc, invoice, layout) {
|
||||
|
||||
var costX = layout.unitCostRight - (doc.getStringUnitWidth(invoiceLabels.unit_cost) * doc.internal.getFontSize());
|
||||
var qtyX = layout.qtyRight - (doc.getStringUnitWidth(invoiceLabels.quantity) * doc.internal.getFontSize());
|
||||
var taxX = layout.taxRight - (doc.getStringUnitWidth(invoiceLabels.tax) * doc.internal.getFontSize());
|
||||
var totalX = layout.lineTotalRight - (doc.getStringUnitWidth(invoiceLabels.line_total) * doc.internal.getFontSize());
|
||||
|
||||
if(invoice.invoice_design_id == 6) {
|
||||
doc.setFontType('normal');
|
||||
doc.text(layout.marginLeft, layout.tableTop, invoiceLabels.item.toUpperCase());
|
||||
doc.text(layout.descriptionLeft, layout.tableTop, invoiceLabels.description.toUpperCase());
|
||||
doc.text(costX, layout.tableTop, ' UNIT');
|
||||
if (invoice.account.hide_quantity != '1') {
|
||||
doc.text(qtyX, layout.tableTop, invoiceLabels.quantity.toUpperCase());
|
||||
}
|
||||
doc.text(totalX, layout.tableTop, ' TOTAL');
|
||||
|
||||
if (invoice.has_taxes)
|
||||
{
|
||||
doc.text(taxX, layout.tableTop, invoiceLabels.tax.toUpperCase());
|
||||
}
|
||||
} else if(invoice.invoice_design_id == 8) {
|
||||
doc.setFontType('bold');
|
||||
doc.text(layout.marginLeft, layout.tableTop, invoiceLabels.item.toUpperCase());
|
||||
doc.text(layout.descriptionLeft, layout.tableTop, invoiceLabels.description.toUpperCase());
|
||||
doc.text(costX, layout.tableTop, ' UNIT');
|
||||
if (invoice.account.hide_quantity != '1') {
|
||||
doc.text(qtyX, layout.tableTop, invoiceLabels.quantity.toUpperCase());
|
||||
}
|
||||
doc.text(totalX, layout.tableTop, ' TOTAL');
|
||||
|
||||
if (invoice.has_taxes)
|
||||
{
|
||||
doc.text(taxX, layout.tableTop, invoiceLabels.tax.toUpperCase());
|
||||
}
|
||||
} else if(invoice.invoice_design_id == 10) {
|
||||
doc.setFontType('bold');
|
||||
doc.setTextColor(63,60,60);
|
||||
doc.text(layout.marginLeft, layout.tableTop, invoiceLabels.item.toUpperCase());
|
||||
doc.text(layout.descriptionLeft, layout.tableTop, invoiceLabels.description.toUpperCase());
|
||||
doc.text(costX, layout.tableTop, invoiceLabels.unit_cost.toUpperCase());
|
||||
if (invoice.account.hide_quantity != '1') {
|
||||
doc.text(qtyX, layout.tableTop, invoiceLabels.quantity.toUpperCase());
|
||||
}
|
||||
doc.text(totalX, layout.tableTop, invoiceLabels.line_total.toUpperCase());
|
||||
|
||||
if (invoice.has_taxes)
|
||||
{
|
||||
doc.text(taxX, layout.tableTop, invoiceLabels.tax.toUpperCase());
|
||||
}
|
||||
} else {
|
||||
doc.text(layout.marginLeft, layout.tableTop, invoiceLabels.item);
|
||||
doc.text(layout.descriptionLeft, layout.tableTop, invoiceLabels.description);
|
||||
doc.text(costX, layout.tableTop, invoiceLabels.unit_cost);
|
||||
if (invoice.account.hide_quantity != '1') {
|
||||
doc.text(qtyX, layout.tableTop, invoiceLabels.quantity);
|
||||
}
|
||||
doc.text(totalX, layout.tableTop, invoiceLabels.line_total);
|
||||
|
||||
if (invoice.has_taxes)
|
||||
{
|
||||
doc.text(taxX, layout.tableTop, invoiceLabels.tax);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1411,7 +1168,9 @@ function displayInvoiceItems(doc, invoice, layout) {
|
||||
|
||||
doc.line(qtyX-45, y-16,qtyX-45, y+55);
|
||||
|
||||
if (invoice.has_taxes) {
|
||||
doc.line(taxX-15, y-16,taxX-15, y+55);
|
||||
}
|
||||
|
||||
doc.line(totalX-27, y-16,totalX-27, y+55);
|
||||
|
||||
@ -1428,7 +1187,9 @@ function displayInvoiceItems(doc, invoice, layout) {
|
||||
|
||||
doc.line(qtyX-45, y-60,qtyX-45, y+20);
|
||||
|
||||
doc.line(taxX-15, y-60,taxX-15, y+20);
|
||||
if (invoice.has_taxes) {
|
||||
doc.line(taxX-10, y-60,taxX-10, y+20);
|
||||
}
|
||||
|
||||
doc.line(totalX-27, y-60,totalX-27, y+120);
|
||||
|
||||
|