diff --git a/app/Http/Controllers/AccountController.php b/app/Http/Controllers/AccountController.php
index 3f8917b65427..db2a65e6eca1 100644
--- a/app/Http/Controllers/AccountController.php
+++ b/app/Http/Controllers/AccountController.php
@@ -1301,4 +1301,37 @@ class AccountController extends BaseController
return Redirect::to("/settings/$section/", 301);
}
+
+ public function previewEmail(\App\Services\TemplateService $templateService)
+ {
+ $template = Input::get('template');
+ $invoice = Invoice::scope()
+ ->invoices()
+ ->withTrashed()
+ ->first();
+
+ if ( ! $invoice) {
+ return trans('texts.create_invoice_for_sample');
+ }
+
+ $account = Auth::user()->account;
+
+ // replace the variables with sample data
+ $data = [
+ 'account' => $account,
+ 'invoice' => $invoice,
+ 'invitation' => $invoice->invitations->first(),
+ 'client' => $invoice->client,
+ 'amount' => $invoice->amount
+ ];
+
+ // create the email view
+ $view = 'emails.' . $account->getTemplateView(ENTITY_INVOICE) . '_html';
+ $data = array_merge($data, [
+ 'body' => $templateService->processVariables($template, $data),
+ 'entityType' => ENTITY_INVOICE,
+ ]);
+
+ return Response::view($view, $data);
+ }
}
diff --git a/app/Http/Controllers/AppController.php b/app/Http/Controllers/AppController.php
index 568cb4d45f5b..a602ae7ecb85 100644
--- a/app/Http/Controllers/AppController.php
+++ b/app/Http/Controllers/AppController.php
@@ -266,18 +266,7 @@ class AppController extends BaseController
Cache::flush();
Session::flush();
Artisan::call('migrate', array('--force' => true));
- foreach ([
- 'PaymentLibraries',
- 'Fonts',
- 'Banks',
- 'InvoiceStatus',
- 'Currencies',
- 'DateFormats',
- 'InvoiceDesigns',
- 'PaymentTerms',
- ] as $seeder) {
- Artisan::call('db:seed', array('--force' => true, '--class' => "{$seeder}Seeder"));
- }
+ Artisan::call('db:seed', array('--force' => true, '--class' => "UpdateSeeder"));
Event::fire(new UserSettingsChanged());
Session::flash('message', trans('texts.processed_updates'));
} catch (Exception $e) {
diff --git a/app/Http/Requests/ClientRequest.php b/app/Http/Requests/ClientRequest.php
index adbe2d4c2ae6..ec28cdb77d1d 100644
--- a/app/Http/Requests/ClientRequest.php
+++ b/app/Http/Requests/ClientRequest.php
@@ -9,7 +9,7 @@ class ClientRequest extends EntityRequest {
$client = parent::entity();
// eager load the contacts
- if ($client && ! count($client->contacts)) {
+ if ($client && ! $client->relationLoaded('contacts')) {
$client->load('contacts');
}
diff --git a/app/Http/Requests/ExpenseRequest.php b/app/Http/Requests/ExpenseRequest.php
index d5e2c793c371..ae2e83b6d12f 100644
--- a/app/Http/Requests/ExpenseRequest.php
+++ b/app/Http/Requests/ExpenseRequest.php
@@ -8,11 +8,11 @@ class ExpenseRequest extends EntityRequest {
{
$expense = parent::entity();
- // eager load the contacts
- if ($expense && ! count($expense->documents)) {
+ // eager load the documents
+ if ($expense && ! $expense->relationLoaded('documents')) {
$expense->load('documents');
}
-
+
return $expense;
}
}
\ No newline at end of file
diff --git a/app/Http/Requests/InvoiceRequest.php b/app/Http/Requests/InvoiceRequest.php
index bf24c38839a9..5e2d93139003 100644
--- a/app/Http/Requests/InvoiceRequest.php
+++ b/app/Http/Requests/InvoiceRequest.php
@@ -8,8 +8,8 @@ class InvoiceRequest extends EntityRequest {
{
$invoice = parent::entity();
- // eager load the contacts
- if ($invoice && ! count($invoice->invoice_items)) {
+ // eager load the invoice items
+ if ($invoice && ! $invoice->relationLoaded('invoice_items')) {
$invoice->load('invoice_items');
}
diff --git a/app/Http/Requests/VendorRequest.php b/app/Http/Requests/VendorRequest.php
index a06e5ad808e6..8f96e7c55025 100644
--- a/app/Http/Requests/VendorRequest.php
+++ b/app/Http/Requests/VendorRequest.php
@@ -9,7 +9,7 @@ class VendorRequest extends EntityRequest {
$vendor = parent::entity();
// eager load the contacts
- if ($vendor && ! count($vendor->vendor_contacts)) {
+ if ($vendor && ! $vendor->relationLoaded('vendor_contacts')) {
$vendor->load('vendor_contacts');
}
diff --git a/app/Http/routes.php b/app/Http/routes.php
index a70b38cc707b..79a818a1aaa5 100644
--- a/app/Http/routes.php
+++ b/app/Http/routes.php
@@ -208,6 +208,7 @@ Route::group([
Route::resource('tax_rates', 'TaxRateController');
Route::post('tax_rates/bulk', 'TaxRateController@bulk');
+ Route::get('settings/email_preview', 'AccountController@previewEmail');
Route::get('company/{section}/{subSection?}', 'AccountController@redirectLegacy');
Route::get('settings/data_visualizations', 'ReportController@d3');
Route::get('settings/charts_and_reports', 'ReportController@showReports');
diff --git a/app/Libraries/Utils.php b/app/Libraries/Utils.php
index 7c1b11dfd84b..4699603d4d4c 100644
--- a/app/Libraries/Utils.php
+++ b/app/Libraries/Utils.php
@@ -341,6 +341,7 @@ class Utils
$currency = self::getFromCache($currencyId, 'currencies');
$thousand = $currency->thousand_separator;
$decimal = $currency->decimal_separator;
+ $precision = $currency->precision;
$code = $currency->code;
$swapSymbol = false;
@@ -355,7 +356,7 @@ class Utils
}
}
- $value = number_format($value, $currency->precision, $decimal, $thousand);
+ $value = number_format($value, $precision, $decimal, $thousand);
$symbol = $currency->symbol;
if ($showCode || !$symbol) {
diff --git a/app/Models/Account.php b/app/Models/Account.php
index c8ece3b4da95..92e2a623ff7b 100644
--- a/app/Models/Account.php
+++ b/app/Models/Account.php
@@ -212,7 +212,9 @@ class Account extends Eloquent
public function isGatewayConfigured($gatewayId = 0)
{
- $this->load('account_gateways');
+ if ( ! $this->relationLoaded('account_gateways')) {
+ $this->load('account_gateways');
+ }
if ($gatewayId) {
return $this->getGatewayConfig($gatewayId) != false;
@@ -241,7 +243,7 @@ class Account extends Eloquent
return $this->name;
}
- $this->load('users');
+ //$this->load('users');
$user = $this->users()->first();
return $user->getDisplayName();
@@ -1167,6 +1169,11 @@ class Account extends Eloquent
return str_replace('/>', ' />', $template);
}
+ public function getTemplateView($view = '')
+ {
+ return $this->getEmailDesignId() == EMAIL_DESIGN_PLAIN ? $view : 'design' . $this->getEmailDesignId();
+ }
+
public function getEmailFooter()
{
if ($this->email_footer) {
diff --git a/app/Models/Client.php b/app/Models/Client.php
index 85cb543a6b03..4b26f40df0a7 100644
--- a/app/Models/Client.php
+++ b/app/Models/Client.php
@@ -256,13 +256,17 @@ class Client extends EntityModel
public function getGatewayToken()
{
- $this->account->load('account_gateways');
+ $account = $this->account;
+
+ if ( ! $account->relationLoaded('account_gateways')) {
+ $account->load('account_gateways');
+ }
- if (!count($this->account->account_gateways)) {
+ if (!count($account->account_gateways)) {
return false;
}
- $accountGateway = $this->account->getGatewayConfig(GATEWAY_STRIPE);
+ $accountGateway = $account->getGatewayConfig(GATEWAY_STRIPE);
if (!$accountGateway) {
return false;
diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php
index deb65b75ab30..cd08e33a855d 100644
--- a/app/Models/Invoice.php
+++ b/app/Models/Invoice.php
@@ -228,6 +228,12 @@ class Invoice extends EntityModel implements BalanceAffecting
return $this->hasMany('App\Models\Expense','invoice_id','id')->withTrashed();
}
+ public function scopeInvoices($query)
+ {
+ return $query->where('is_quote', '=', false)
+ ->where('is_recurring', '=', false);
+ }
+
public function markInvitationsSent($notify = false)
{
foreach ($this->invitations as $invitation) {
diff --git a/app/Ninja/Mailers/ContactMailer.php b/app/Ninja/Mailers/ContactMailer.php
index 4b176628ebf0..fbebd0c5fdfd 100644
--- a/app/Ninja/Mailers/ContactMailer.php
+++ b/app/Ninja/Mailers/ContactMailer.php
@@ -1,17 +1,13 @@
templateService = $templateService;
+ }
+
public function sendInvoice(Invoice $invoice, $reminder = false, $pdfString = false)
{
$invoice->load('invitations', 'client.language', 'account');
@@ -144,7 +145,7 @@ class ContactMailer extends Mailer
}
$data = [
- 'body' => $this->processVariables($body, $variables),
+ 'body' => $this->templateService->processVariables($body, $variables),
'link' => $invitation->getLink(),
'entityType' => $invoice->getEntityType(),
'invoiceId' => $invoice->id,
@@ -160,14 +161,9 @@ class ContactMailer extends Mailer
$data['pdfFileName'] = $invoice->getFileName();
}
- $subject = $this->processVariables($subject, $variables);
+ $subject = $this->templateService->processVariables($subject, $variables);
$fromEmail = $user->email;
-
- if ($account->getEmailDesignId() == EMAIL_DESIGN_PLAIN) {
- $view = ENTITY_INVOICE;
- } else {
- $view = 'design' . ($account->getEmailDesignId() - 1);
- }
+ $view = $account->getTemplateView(ENTITY_INVOICE);
$response = $this->sendTo($invitation->contact->email, $fromEmail, $account->getDisplayName(), $subject, $view, $data);
@@ -230,7 +226,7 @@ class ContactMailer extends Mailer
];
$data = [
- 'body' => $this->processVariables($emailTemplate, $variables),
+ 'body' => $this->templateService->processVariables($emailTemplate, $variables),
'link' => $invitation->getLink(),
'invoice' => $invoice,
'client' => $client,
@@ -244,14 +240,10 @@ class ContactMailer extends Mailer
$data['pdfFileName'] = $invoice->getFileName();
}
- $subject = $this->processVariables($emailSubject, $variables);
+ $subject = $this->templateService->processVariables($emailSubject, $variables);
$data['invoice_id'] = $payment->invoice->id;
- if ($account->getEmailDesignId() == EMAIL_DESIGN_PLAIN) {
- $view = 'payment_confirmation';
- } else {
- $view = 'design' . ($account->getEmailDesignId() - 1);
- }
+ $view = $account->getTemplateView('payment_confirmation');
if ($user->email && $contact->email) {
$this->sendTo($contact->email, $user->email, $accountName, $subject, $view, $data);
@@ -281,75 +273,4 @@ class ContactMailer extends Mailer
$this->sendTo($email, CONTACT_EMAIL, CONTACT_NAME, $subject, $view, $data);
}
-
- private function processVariables($template, $data)
- {
- $account = $data['account'];
- $client = $data['client'];
- $invitation = $data['invitation'];
- $invoice = $invitation->invoice;
- $passwordHTML = isset($data['password'])?'
'.trans('texts.password').': '.$data['password'].'
':false;
- $documentsHTML = '';
-
- if($account->hasFeature(FEATURE_DOCUMENTS) && $invoice->hasDocuments()){
- $documentsHTML .= trans('texts.email_documents_header').'
';
- }
-
- $variables = [
- '$footer' => $account->getEmailFooter(),
- '$client' => $client->getDisplayName(),
- '$account' => $account->getDisplayName(),
- '$dueDate' => $account->formatDate($invoice->due_date),
- '$invoiceDate' => $account->formatDate($invoice->invoice_date),
- '$contact' => $invitation->contact->getDisplayName(),
- '$firstName' => $invitation->contact->first_name,
- '$amount' => $account->formatMoney($data['amount'], $client),
- '$invoice' => $invoice->invoice_number,
- '$quote' => $invoice->invoice_number,
- '$link' => $invitation->getLink(),
- '$password' => $passwordHTML,
- '$viewLink' => $invitation->getLink().'$password',
- '$viewButton' => Form::emailViewButton($invitation->getLink(), $invoice->getEntityType()).'$password',
- '$paymentLink' => $invitation->getLink('payment').'$password',
- '$paymentButton' => Form::emailPaymentButton($invitation->getLink('payment')).'$password',
- '$customClient1' => $account->custom_client_label1,
- '$customClient2' => $account->custom_client_label2,
- '$customInvoice1' => $account->custom_invoice_text_label1,
- '$customInvoice2' => $account->custom_invoice_text_label2,
- '$documents' => $documentsHTML,
- ];
-
- // Add variables for available payment types
- foreach (Gateway::$paymentTypes as $type) {
- $camelType = Gateway::getPaymentTypeName($type);
- $type = Utils::toSnakeCase($camelType);
- $variables["\${$camelType}Link"] = $invitation->getLink('payment') . "/{$type}";
- $variables["\${$camelType}Button"] = Form::emailPaymentButton($invitation->getLink('payment') . "/{$type}");
- }
-
- $includesPasswordPlaceholder = strpos($template, '$password') !== false;
-
- $str = str_replace(array_keys($variables), array_values($variables), $template);
-
- if(!$includesPasswordPlaceholder && $passwordHTML){
- $pos = strrpos($str, '$password');
- if($pos !== false)
- {
- $str = substr_replace($str, $passwordHTML, $pos, 9/* length of "$password" */);
- }
- }
- $str = str_replace('$password', '', $str);
- $str = autolink($str, 100);
-
- return $str;
- }
}
diff --git a/app/Ninja/Presenters/InvoicePresenter.php b/app/Ninja/Presenters/InvoicePresenter.php
index ebb3297d5c1a..36a2ce2acbd6 100644
--- a/app/Ninja/Presenters/InvoicePresenter.php
+++ b/app/Ninja/Presenters/InvoicePresenter.php
@@ -18,7 +18,7 @@ class InvoicePresenter extends Presenter {
public function balanceDueLabel()
{
- if ($this->entity->partial) {
+ if ($this->entity->partial > 0) {
return 'partial_due';
} elseif ($this->entity->is_quote) {
return 'total';
diff --git a/app/Ninja/Repositories/AccountRepository.php b/app/Ninja/Repositories/AccountRepository.php
index e8fe2d041843..3b3c36d3ecc3 100644
--- a/app/Ninja/Repositories/AccountRepository.php
+++ b/app/Ninja/Repositories/AccountRepository.php
@@ -167,6 +167,7 @@ class AccountRepository
ENTITY_QUOTE,
ENTITY_TASK,
ENTITY_EXPENSE,
+ ENTITY_VENDOR,
ENTITY_RECURRING_INVOICE,
ENTITY_PAYMENT,
ENTITY_CREDIT
@@ -183,15 +184,22 @@ class AccountRepository
];
}
- $features[] = ['dashboard', '/dashboard'];
- $features[] = ['customize_design', '/settings/customize_design'];
- $features[] = ['new_tax_rate', '/tax_rates/create'];
- $features[] = ['new_product', '/products/create'];
- $features[] = ['new_user', '/users/create'];
- $features[] = ['custom_fields', '/settings/invoice_settings'];
+ $features = array_merge($features, [
+ ['dashboard', '/dashboard'],
+ ['customize_design', '/settings/customize_design'],
+ ['new_tax_rate', '/tax_rates/create'],
+ ['new_product', '/products/create'],
+ ['new_user', '/users/create'],
+ ['custom_fields', '/settings/invoice_settings'],
+ ['invoice_number', '/settings/invoice_settings'],
+ ]);
$settings = array_merge(Account::$basicSettings, Account::$advancedSettings);
+ if ( ! Utils::isNinjaProd()) {
+ $settings[] = ACCOUNT_SYSTEM_SETTINGS;
+ }
+
foreach ($settings as $setting) {
$features[] = [
$setting,
@@ -332,7 +340,7 @@ class AccountRepository
$client->public_id = $account->id;
$client->user_id = $ninjaAccount->users()->first()->id;
$client->currency_id = 1;
- foreach (['name', 'address1', 'address2', 'city', 'state', 'postal_code', 'country_id', 'work_phone', 'language_id'] as $field) {
+ foreach (['name', 'address1', 'address2', 'city', 'state', 'postal_code', 'country_id', 'work_phone', 'language_id', 'vat_number'] as $field) {
$client->$field = $account->$field;
}
$ninjaAccount->clients()->save($client);
diff --git a/app/Ninja/Repositories/ClientRepository.php b/app/Ninja/Repositories/ClientRepository.php
index 8d8c3ed527d4..83f08cd97a59 100644
--- a/app/Ninja/Repositories/ClientRepository.php
+++ b/app/Ninja/Repositories/ClientRepository.php
@@ -105,9 +105,9 @@ class ClientRepository extends BaseRepository
// If the primary is set ensure it's listed first
usort($contacts, function ($left, $right) {
- return (isset($right['is_primary']) ? $right['is_primary'] : 0) - (isset($left['is_primary']) ? $left['is_primary'] : 0);
+ return (isset($right['is_primary']) ? $right['is_primary'] : 1) - (isset($left['is_primary']) ? $left['is_primary'] : 0);
});
-
+
foreach ($contacts as $contact) {
$contact = $client->addContact($contact, $first);
$contactIds[] = $contact->public_id;
diff --git a/app/Services/TemplateService.php b/app/Services/TemplateService.php
new file mode 100644
index 000000000000..5a41c705352d
--- /dev/null
+++ b/app/Services/TemplateService.php
@@ -0,0 +1,80 @@
+invoice;
+ $passwordHTML = isset($data['password'])?''.trans('texts.password').': '.$data['password'].'
':false;
+ $documentsHTML = '';
+
+ if ($account->hasFeature(FEATURE_DOCUMENTS) && $invoice->hasDocuments()) {
+ $documentsHTML .= trans('texts.email_documents_header').'
';
+ }
+
+ $variables = [
+ '$footer' => $account->getEmailFooter(),
+ '$client' => $client->getDisplayName(),
+ '$account' => $account->getDisplayName(),
+ '$dueDate' => $account->formatDate($invoice->due_date),
+ '$invoiceDate' => $account->formatDate($invoice->invoice_date),
+ '$contact' => $invitation->contact->getDisplayName(),
+ '$firstName' => $invitation->contact->first_name,
+ '$amount' => $account->formatMoney($data['amount'], $client),
+ '$invoice' => $invoice->invoice_number,
+ '$quote' => $invoice->invoice_number,
+ '$link' => $invitation->getLink(),
+ '$password' => $passwordHTML,
+ '$viewLink' => $invitation->getLink().'$password',
+ '$viewButton' => Form::emailViewButton($invitation->getLink(), $invoice->getEntityType()).'$password',
+ '$paymentLink' => $invitation->getLink('payment').'$password',
+ '$paymentButton' => Form::emailPaymentButton($invitation->getLink('payment')).'$password',
+ '$customClient1' => $account->custom_client_label1,
+ '$customClient2' => $account->custom_client_label2,
+ '$customInvoice1' => $account->custom_invoice_text_label1,
+ '$customInvoice2' => $account->custom_invoice_text_label2,
+ '$documents' => $documentsHTML,
+ ];
+
+ // Add variables for available payment types
+ foreach (Gateway::$paymentTypes as $type) {
+ $camelType = Gateway::getPaymentTypeName($type);
+ $type = Utils::toSnakeCase($camelType);
+ $variables["\${$camelType}Link"] = $invitation->getLink('payment') . "/{$type}";
+ $variables["\${$camelType}Button"] = Form::emailPaymentButton($invitation->getLink('payment') . "/{$type}");
+ }
+
+ $includesPasswordPlaceholder = strpos($template, '$password') !== false;
+
+ $str = str_replace(array_keys($variables), array_values($variables), $template);
+
+ if (!$includesPasswordPlaceholder && $passwordHTML) {
+ $pos = strrpos($str, '$password');
+ if ($pos !== false)
+ {
+ $str = substr_replace($str, $passwordHTML, $pos, 9/* length of "$password" */);
+ }
+ }
+ $str = str_replace('$password', '', $str);
+ $str = autolink($str, 100);
+
+ return $str;
+ }
+}
\ No newline at end of file
diff --git a/database/seeds/CurrenciesSeeder.php b/database/seeds/CurrenciesSeeder.php
index b3da84dad01d..3b44d55d8d7f 100644
--- a/database/seeds/CurrenciesSeeder.php
+++ b/database/seeds/CurrenciesSeeder.php
@@ -8,6 +8,7 @@ class CurrenciesSeeder extends Seeder
{
Eloquent::unguard();
+ // http://www.localeplanet.com/icu/currency.html
$currencies = [
['name' => 'US Dollar', 'code' => 'USD', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Pound Sterling', 'code' => 'GBP', 'symbol' => '£', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
@@ -56,6 +57,7 @@ class CurrenciesSeeder extends Seeder
['name' => 'Japanese Yen', 'code' => 'JPY', 'symbol' => '¥', 'precision' => '0', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Maldivian Rufiyaa', 'code' => 'MVR', 'symbol' => '', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Costa Rican Colón', 'code' => 'CRC', 'symbol' => '', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
+ ['name' => 'Pakistani Rupee', 'code' => 'PKR', 'symbol' => 'Rs ', 'precision' => '0', 'thousand_separator' => ',', 'decimal_separator' => '.'],
];
foreach ($currencies as $currency) {
diff --git a/database/seeds/DatabaseSeeder.php b/database/seeds/DatabaseSeeder.php
index 8791f30e71fb..d7f38d3e1e53 100644
--- a/database/seeds/DatabaseSeeder.php
+++ b/database/seeds/DatabaseSeeder.php
@@ -23,5 +23,6 @@ class DatabaseSeeder extends Seeder
$this->call('DateFormatsSeeder');
$this->call('InvoiceDesignsSeeder');
$this->call('PaymentTermsSeeder');
+ $this->call('LanguageSeeder');
}
}
diff --git a/database/seeds/LanguageSeeder.php b/database/seeds/LanguageSeeder.php
new file mode 100644
index 000000000000..c82b2630771c
--- /dev/null
+++ b/database/seeds/LanguageSeeder.php
@@ -0,0 +1,41 @@
+ 'English', 'locale' => 'en'],
+ ['name' => 'Italian', 'locale' => 'it'],
+ ['name' => 'German', 'locale' => 'de'],
+ ['name' => 'French', 'locale' => 'fr'],
+ ['name' => 'Brazilian Portuguese', 'locale' => 'pt_BR'],
+ ['name' => 'Dutch', 'locale' => 'nl'],
+ ['name' => 'Spanish', 'locale' => 'es'],
+ ['name' => 'Norwegian', 'locale' => 'nb_NO'],
+ ['name' => 'Danish', 'locale' => 'da'],
+ ['name' => 'Japanese', 'locale' => 'ja'],
+ ['name' => 'Swedish', 'locale' => 'sv'],
+ ['name' => 'Spanish - Spain', 'locale' => 'es_ES'],
+ ['name' => 'French - Canada', 'locale' => 'fr_CA'],
+ ['name' => 'Lithuanian', 'locale' => 'lt'],
+ ['name' => 'Polish', 'locale' => 'pl'],
+ ];
+
+ foreach ($languages as $language) {
+ $record = Language::whereLocale($language['locale'])->first();
+ if ($record) {
+ $record->name = $language['name'];
+ $record->save();
+ } else {
+ Language::create($language);
+ }
+ }
+
+ Eloquent::reguard();
+ }
+}
diff --git a/database/seeds/UpdateSeeder.php b/database/seeds/UpdateSeeder.php
index e4d43f78e512..d445811de506 100644
--- a/database/seeds/UpdateSeeder.php
+++ b/database/seeds/UpdateSeeder.php
@@ -19,5 +19,6 @@ class UpdateSeeder extends Seeder
$this->call('DateFormatsSeeder');
$this->call('InvoiceDesignsSeeder');
$this->call('PaymentTermsSeeder');
+ $this->call('LanguageSeeder');
}
}
diff --git a/database/seeds/UserTableSeeder.php b/database/seeds/UserTableSeeder.php
index 1ec659bf389e..dbaba660b75c 100644
--- a/database/seeds/UserTableSeeder.php
+++ b/database/seeds/UserTableSeeder.php
@@ -1,9 +1,13 @@
'Test Account',
+ 'name' => $faker->name,
+ 'address1' => $faker->streetAddress,
+ 'address2' => $faker->secondaryAddress,
+ 'city' => $faker->city,
+ 'state' => $faker->state,
+ 'postal_code' => $faker->postcode,
+ 'country_id' => Country::all()->random()->id,
'account_key' => str_random(RANDOM_KEY_LENGTH),
+ 'invoice_terms' => $faker->text($faker->numberBetween(50, 300)),
+ 'work_phone' => $faker->phoneNumber,
+ 'work_email' => $faker->safeEmail,
+ 'invoice_design_id' => min(InvoiceDesign::all()->random()->id, 10),
+ 'header_font_id' => min(Font::all()->random()->id, 17),
+ 'body_font_id' => min(Font::all()->random()->id, 17),
+ 'primary_color' => $faker->hexcolor,
'timezone_id' => 1,
'company_id' => $company->id,
]);
@@ -30,6 +48,8 @@ class UserTableSeeder extends Seeder
'password' => Hash::make(TEST_PASSWORD),
'registered' => true,
'confirmed' => true,
+ 'notify_sent' => false,
+ 'notify_paid' => false,
]);
Affiliate::create([
diff --git a/public/built.js b/public/built.js
index faffe4a2c348..2e1938ba78b6 100644
--- a/public/built.js
+++ b/public/built.js
@@ -31196,7 +31196,7 @@ NINJA.decodeJavascript = function(invoice, javascript)
field = toSnakeCase(field);
var value = getDescendantProp(invoice, field);
if (match.indexOf('?') < 0 || value) {
- if (invoice.partial && field == 'balance_due') {
+ if (invoice.partial > 0 && field == 'balance_due') {
field = 'partial_due';
} else if (invoice.is_quote) {
field = field.replace('invoice', 'quote');
@@ -31584,7 +31584,7 @@ NINJA.invoiceDetails = function(invoice) {
],
[
{text: (invoice.is_quote ? invoiceLabels.valid_until : invoiceLabels.due_date)},
- {text: invoice.due_date}
+ {text: invoice.is_recurring ? false : invoice.due_date}
]
];
diff --git a/public/css/built.css b/public/css/built.css
index 484aeebab8c2..3c7c53828f1c 100644
--- a/public/css/built.css
+++ b/public/css/built.css
@@ -2539,6 +2539,10 @@ ul.dropdown-menu,
box-shadow: 0 0 10px 2px rgba(0,0,0,.05);
}
+.twitter-typeahead .tt-menu {
+ overflow-x: hidden;
+}
+
.panel-default,
canvas {
border: 1px solid;
diff --git a/public/css/style.css b/public/css/style.css
index 0ac30b8a4694..801141c03cc9 100644
--- a/public/css/style.css
+++ b/public/css/style.css
@@ -410,6 +410,10 @@ ul.dropdown-menu,
box-shadow: 0 0 10px 2px rgba(0,0,0,.05);
}
+.twitter-typeahead .tt-menu {
+ overflow-x: hidden;
+}
+
.panel-default,
canvas {
border: 1px solid;
diff --git a/public/js/pdf.pdfmake.js b/public/js/pdf.pdfmake.js
index db8e16f79442..ca728d4066c3 100644
--- a/public/js/pdf.pdfmake.js
+++ b/public/js/pdf.pdfmake.js
@@ -192,7 +192,7 @@ NINJA.decodeJavascript = function(invoice, javascript)
field = toSnakeCase(field);
var value = getDescendantProp(invoice, field);
if (match.indexOf('?') < 0 || value) {
- if (invoice.partial && field == 'balance_due') {
+ if (invoice.partial > 0 && field == 'balance_due') {
field = 'partial_due';
} else if (invoice.is_quote) {
field = field.replace('invoice', 'quote');
@@ -580,7 +580,7 @@ NINJA.invoiceDetails = function(invoice) {
],
[
{text: (invoice.is_quote ? invoiceLabels.valid_until : invoiceLabels.due_date)},
- {text: invoice.due_date}
+ {text: invoice.is_recurring ? false : invoice.due_date}
]
];
diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php
index f101c79564e7..11be9fb1d5d7 100644
--- a/resources/lang/en/texts.php
+++ b/resources/lang/en/texts.php
@@ -1176,6 +1176,8 @@ $LANG = array(
'page_size' => 'Page Size',
'live_preview_disabled' => 'Live preview has been disabled to support selected font',
'invoice_number_padding' => 'Padding',
+ 'preview' => 'Preview',
+ 'list_vendors' => 'List Vendors',
);
diff --git a/resources/views/accounts/management.blade.php b/resources/views/accounts/management.blade.php
index cf9917deb005..cfb7b6eb28ee 100644
--- a/resources/views/accounts/management.blade.php
+++ b/resources/views/accounts/management.blade.php
@@ -94,9 +94,9 @@
@endif
@if (Utils::isNinjaProd())
- {!! Former::actions( Button::success(trans('texts.plan_upgrade'))->large()->withAttributes(['onclick' => 'showChangePlan()'])->appendIcon(Icon::create('plus-sign'))) !!}
- @else
- {!! Former::actions( Button::success(trans('texts.white_label_button'))->large()->withAttributes(['onclick' => 'loadImages("#whiteLabelModal");$("#whiteLabelModal").modal("show");'])->appendIcon(Icon::create('plus-sign'))) !!}
+ {!! Former::actions( Button::success(trans('texts.plan_upgrade'))->large()->withAttributes(['onclick' => 'showChangePlan()'])->appendIcon(Icon::create('plus-sign'))) !!}
+ @elseif (!$account->hasFeature(FEATURE_WHITE_LABEL))
+ {!! Former::actions( Button::success(trans('texts.white_label_button'))->large()->withAttributes(['onclick' => 'loadImages("#whiteLabelModal");$("#whiteLabelModal").modal("show");'])->appendIcon(Icon::create('plus-sign'))) !!}
@endif
@endif
diff --git a/resources/views/accounts/template.blade.php b/resources/views/accounts/template.blade.php
index 0d4294af5b6f..68279299f607 100644
--- a/resources/views/accounts/template.blade.php
+++ b/resources/views/accounts/template.blade.php
@@ -62,11 +62,14 @@
+
-
-
+
@include('partials/quill_toolbar', ['name' => $field])
+
+ {!! Button::primary(trans('texts.preview'))->withAttributes(['onclick' => 'serverPreview("'.$field.'")'])->small() !!}
+
diff --git a/resources/views/accounts/templates_and_reminders.blade.php b/resources/views/accounts/templates_and_reminders.blade.php
index 067433a21763..87453e80dae6 100644
--- a/resources/views/accounts/templates_and_reminders.blade.php
+++ b/resources/views/accounts/templates_and_reminders.blade.php
@@ -25,11 +25,16 @@
{!! Former::vertical_open()->addClass('warn-on-exit') !!}
- {!! Former::populate($account) !!}
@foreach ([ENTITY_INVOICE, ENTITY_QUOTE, ENTITY_PAYMENT, REMINDER1, REMINDER2, REMINDER3] as $type)
@foreach (['subject', 'template'] as $field)
- {!! Former::populateField("email_{$field}_{$type}", $templates[$type][$field]) !!}
+ {{ Former::populateField("email_{$field}_{$type}", $templates[$type][$field]) }}
+ @endforeach
+ @endforeach
+
+ @foreach ([REMINDER1, REMINDER2, REMINDER3] as $type)
+ @foreach (['enable', 'num_days', 'direction', 'field'] as $field)
+ {{ Former::populateField("{$field}_{$type}", $account->{"{$field}_{$type}"}) }}
@endforeach
@endforeach
@@ -80,6 +85,26 @@
+
+
+
@@ -158,6 +183,22 @@
}
}
+ function serverPreview(field) {
+ console.log(field);
+ $('#templatePreviewModal').modal('show');
+ var template = $('#email_template_' + field).val();
+ var url = '{{ URL::to('settings/email_preview') }}?template=' + template;
+ $('#server-preview').attr('src', url).load(function() {
+ // disable links in the preview
+ $('iframe').contents().find('a').each(function(index) {
+ $(this).on('click', function(event) {
+ event.preventDefault();
+ event.stopPropagation();
+ });
+ });
+ });
+ }
+
$(function() {
for (var i=0; i
- |