Bug fixes

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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