diff --git a/.env.development.php b/.env.development.php index adeed69f24..eea3783a74 100644 --- a/.env.development.php +++ b/.env.development.php @@ -4,6 +4,6 @@ return array( //'TAG_MANAGER_KEY' => '', //'ANALYTICS_KEY' => '', - //'NINJA_PROD' => true, + //'NINJA_DEV' => true, ); diff --git a/app/controllers/UserController.php b/app/controllers/UserController.php index f1f4526256..a62c30e5de 100755 --- a/app/controllers/UserController.php +++ b/app/controllers/UserController.php @@ -11,20 +11,53 @@ use ninja\repositories\AccountRepository; use ninja\mailers\ContactMailer; +use ninja\mailers\UserMailer; class UserController extends BaseController { protected $accountRepo; protected $contactMailer; + protected $userMailer; - public function __construct(AccountRepository $accountRepo, ContactMailer $contactMailer) + public function __construct(AccountRepository $accountRepo, ContactMailer $contactMailer, UserMailer $userMailer) { parent::__construct(); $this->accountRepo = $accountRepo; $this->contactMailer = $contactMailer; + $this->userMailer = $userMailer; } + public function getDatatable() + { + $query = DB::table('users') + ->where('users.account_id', '=', Auth::user()->account_id) + ->where('users.deleted_at', '=', null) + ->where('users.public_id', '>', 0) + ->select('users.public_id', 'users.first_name', 'users.last_name', 'users.email', 'users.confirmed', 'users.public_id'); + + + return Datatable::query($query) + ->addColumn('first_name', function($model) { return link_to('users/' . $model->public_id . '/edit', $model->first_name . ' ' . $model->last_name); }) + ->addColumn('email', function($model) { return $model->email; }) + ->addColumn('confirmed', function($model) { return $model->confirmed ? trans('texts.active') : trans('texts.pending'); }) + ->addColumn('dropdown', function($model) + { + return '
'; + }) + ->orderColumns(['first_name', 'email', 'confirmed']) + ->make(); + } + public function setTheme() { $user = User::find(Auth::user()->id); @@ -45,50 +78,146 @@ class UserController extends BaseController { return Redirect::to('/dashboard'); } + public function edit($publicId) + { + $user = User::where('account_id', '=', Auth::user()->account_id) + ->where('public_id', '=', $publicId)->firstOrFail(); + + $data = [ + 'showBreadcrumbs' => false, + 'user' => $user, + 'method' => 'PUT', + 'url' => 'users/' . $publicId, + 'title' => trans('texts.edit_user') + ]; + + return View::make('users.edit', $data); + } + + public function update($publicId) + { + return $this->save($publicId); + } + + public function store() + { + return $this->save(); + } + /** * Displays the form for account creation * */ public function create() { - return View::make(Config::get('confide::signup_form')); + if (!Auth::user()->confirmed) + { + Session::flash('error', trans('texts.register_to_add_user')); + return Redirect::to('company/advanced_settings/user_management'); + } + + if (Utils::isNinja()) + { + $count = User::where('account_id', '=', Auth::user()->account_id)->count(); + if ($count >= MAX_NUM_USERS) + { + Session::flash('error', trans('texts.limit_users')); + return Redirect::to('company/advanced_settings/user_management'); + } + } + + $data = [ + 'showBreadcrumbs' => false, + 'user' => null, + 'method' => 'POST', + 'url' => 'users', + 'title' => trans('texts.add_user') + ]; + + return View::make('users.edit', $data); + } + + public function delete() + { + $userPublicId = Input::get('userPublicId'); + $user = User::where('account_id', '=', Auth::user()->account_id) + ->where('public_id', '=', $userPublicId)->firstOrFail(); + + $user->delete(); + + Session::flash('message', trans('texts.deleted_user')); + return Redirect::to('company/advanced_settings/user_management'); } /** * Stores new account * */ - public function store() + public function save($userPublicId = false) { - $user = new User; + $rules = [ + 'first_name' => 'required', + 'last_name' => 'required', + ]; - $user->username = Input::get( 'username' ); - $user->email = Input::get( 'email' ); - $user->password = Input::get( 'password' ); - - // The password confirmation will be removed from model - // before saving. This field will be used in Ardent's - // auto validation. - $user->password_confirmation = Input::get( 'password_confirmation' ); - - // Save if valid. Password field will be hashed before save - $user->save(); - - if ( $user->id ) + if ($userPublicId) { - // Redirect with success message, You may replace "Lang::get(..." for your custom message. - return Redirect::action('UserController@login') - ->with( 'notice', Lang::get('confide::confide.alerts.account_created') ); + $user = User::where('account_id', '=', Auth::user()->account_id) + ->where('public_id', '=', $userPublicId)->firstOrFail(); + + $rules['email'] = 'required|email|unique:users,email,' . $user->id . ',id'; } else { - // Get validation errors (see Ardent package) - $error = $user->errors()->all(':message'); - - return Redirect::action('UserController@create') - ->withInput(Input::except('password')) - ->with( 'error', $error ); + $rules['email'] = 'required|email|unique:users'; } + + $validator = Validator::make(Input::all(), $rules); + + if ($validator->fails()) + { + return Redirect::to($userPublicId ? 'users/edit' : 'users/create')->withInput()->withErrors($validator); + } + + if ($userPublicId) + { + $user->first_name = trim(Input::get('first_name')); + $user->last_name = trim(Input::get('last_name')); + $user->username = trim(Input::get('email')); + $user->email = trim(Input::get('email')); + } + else + { + $lastUser = User::withTrashed()->where('account_id', '=', Auth::user()->account_id) + ->orderBy('public_id', 'DESC')->first(); + + $user = new User; + $user->account_id = Auth::user()->account_id; + $user->first_name = trim(Input::get('first_name')); + $user->last_name = trim(Input::get('last_name')); + $user->username = trim(Input::get('email')); + $user->email = trim(Input::get('email')); + $user->registered = true; + $user->password = str_random(RANDOM_KEY_LENGTH); + $user->password_confirmation = $user->password; + $user->public_id = $lastUser->public_id + 1; + } + + $user->save(); + + if (!$user->confirmed) + { + $this->userMailer->sendConfirmation($user, Auth::user()); + $message = trans('texts.sent_invite'); + } + else + { + $message = trans('texts.updated_user'); + } + + Session::flash('message', $message); + + return Redirect::to('company/advanced_settings/user_management'); } /** @@ -183,21 +312,34 @@ class UserController extends BaseController { public function confirm( $code ) { if ( Confide::confirm( $code ) ) - { + { $notice_msg = trans('texts.confide.confirmation'); + + $user = User::where('confirmation_code', '=', $code)->get()->first(); + $user->confirmation_code = ''; + $user->save(); - if (Session::has(REQUESTED_PRO_PLAN)) + if ($user->public_id) { - Session::forget(REQUESTED_PRO_PLAN); + Auth::login($user); - if ($invoice = $this->accountRepo->enableProPlan()) + return Redirect::to('user/reset'); + } + else + { + if (Session::has(REQUESTED_PRO_PLAN)) { - $this->contactMailer->sendInvoice($invoice); - $notice_msg = trans('texts.pro_plan_success'); - } - } + Session::forget(REQUESTED_PRO_PLAN); - return Redirect::action('UserController@login')->with( 'message', $notice_msg ); + if ($invoice = $this->accountRepo->enableProPlan()) + { + $this->contactMailer->sendInvoice($invoice); + $notice_msg = trans('texts.pro_plan_success'); + } + } + + return Redirect::action('UserController@login')->with( 'message', $notice_msg ); + } } else { @@ -249,7 +391,7 @@ class UserController extends BaseController { * Shows the change password form with the given token * */ - public function reset_password( $token ) + public function reset_password( $token = false ) { return View::make(Config::get('confide::reset_password_form')) ->with('token', $token); @@ -260,26 +402,49 @@ class UserController extends BaseController { * */ public function do_reset_password() - { - $input = array( - 'token'=>Input::get( 'token' ), - 'password'=>Input::get( 'password' ), - 'password_confirmation'=>Input::get( 'password_confirmation' ), - ); - - // By passing an array with the token, password and confirmation - if( Confide::resetPassword( $input ) ) + { + if (Auth::check()) { - $notice_msg = trans('texts.confide.password_reset'); - return Redirect::action('UserController@login') - ->with( 'notice', $notice_msg ); + $rules = [ + 'password' => 'required|between:4,11|confirmed', + 'password_confirmation' => 'between:4,11', + ]; + $validator = Validator::make(Input::all(), $rules); + + if ($validator->fails()) + { + return Redirect::to('user/reset')->withInput()->withErrors($validator); + } + + $user = Auth::user(); + $user->password = Input::get('password'); + $user->save(); + + Session::flash('message', trans('texts.confide.password_reset')); + return Redirect::to('/dashboard'); } else { - $error_msg = trans('texts.confide.wrong_password_reset'); - return Redirect::action('UserController@reset_password', array('token'=>$input['token'])) - ->withInput() - ->with( 'error', $error_msg ); + $input = array( + 'token'=>Input::get( 'token' ), + 'password'=>Input::get( 'password' ), + 'password_confirmation'=>Input::get( 'password_confirmation' ), + ); + + // By passing an array with the token, password and confirmation + if( Confide::resetPassword( $input ) ) + { + $notice_msg = trans('texts.confide.password_reset'); + return Redirect::action('UserController@login') + ->with( 'notice', $notice_msg ); + } + else + { + $error_msg = trans('texts.confide.wrong_password_reset'); + return Redirect::action('UserController@reset_password', array('token'=>$input['token'])) + ->withInput() + ->with( 'error', $error_msg ); + } } } diff --git a/app/lang/en/texts.php b/app/lang/en/texts.php index b6504be860..a5b919fff3 100644 --- a/app/lang/en/texts.php +++ b/app/lang/en/texts.php @@ -400,11 +400,24 @@ return array( 'invoice_fields' => 'Invoice Fields', 'invoice_options' => 'Invoice Options', 'hide_quantity' => 'Hide quantity', - 'hide_quantity_help' => 'All line items will have a quantity of one', + 'hide_quantity_help' => 'If your line items quantities are always 1, then you can declutter invoices by no longer displaying this field.', 'hide_paid_to_date' => 'Hide paid to date', - 'hide_paid_to_date_help' => 'Hide until a payment is made', + 'hide_paid_to_date_help' => 'Only display the "Paid to Date" area on your invoices once a payment has been received.', 'charge_taxes' => 'Charge taxes', + 'user_management' => 'User Management', + 'add_user' => 'Add User', + 'send_invite' => 'Send invitation', + 'sent_invite' => 'Successfully sent invitation', + 'updated_user' => 'Successfully updated user', + 'invitation_message' => 'You\'ve been invited by :invitor. ', + 'register_to_add_user' => 'Please sign up to add a user', + 'user_state' => 'State', + 'edit_user' => 'Edit User', + 'delete_user' => 'Delete User', + 'active' => 'Active', + 'pending' => 'Pending', + 'deleted_user' => 'Successfully deleted user', + 'limit_users' => 'Sorry, this will exceed the limit of ' . MAX_NUM_USERS . ' users', -); - +); \ No newline at end of file diff --git a/app/ninja/mailers/UserMailer.php b/app/ninja/mailers/UserMailer.php index 7c10ae9708..066db805d6 100755 --- a/app/ninja/mailers/UserMailer.php +++ b/app/ninja/mailers/UserMailer.php @@ -8,7 +8,7 @@ use Utils; class UserMailer extends Mailer { - public function sendConfirmation(User $user) + public function sendConfirmation(User $user, User $invitor = null) { if (!$user->email) { @@ -19,7 +19,8 @@ class UserMailer extends Mailer { $subject = trans('texts.confirmation_subject'); $data = [ - 'user' => $user + 'user' => $user, + 'invitationMessage' => $invitor ? trans('texts.invitation_message', ['invitor' => $invitor->getDisplayName()]) : '' ]; $this->sendTo($user->email, CONTACT_EMAIL, CONTACT_NAME, $subject, $view, $data); diff --git a/app/ninja/repositories/InvoiceRepository.php b/app/ninja/repositories/InvoiceRepository.php index 8dd1b80a7d..8b416314b2 100755 --- a/app/ninja/repositories/InvoiceRepository.php +++ b/app/ninja/repositories/InvoiceRepository.php @@ -261,8 +261,8 @@ class InvoiceRepository $total *= (100 - $invoice->discount) / 100; } - $invoice->custom_value1 = $data['custom_value1']; - $invoice->custom_value2 = $data['custom_value2']; + $invoice->custom_value1 = round($data['custom_value1'], 2); + $invoice->custom_value2 = round($data['custom_value2'], 2); $invoice->custom_taxes1 = $data['custom_taxes1'] ? true : false; $invoice->custom_taxes2 = $data['custom_taxes2'] ? true : false; diff --git a/app/routes.php b/app/routes.php index d4c253597c..ba7341e1c2 100755 --- a/app/routes.php +++ b/app/routes.php @@ -57,7 +57,7 @@ Route::post('login', 'UserController@do_login'); Route::get('user/confirm/{code}', 'UserController@confirm'); Route::get('forgot_password', 'UserController@forgot_password'); Route::post('forgot_password', 'UserController@do_forgot_password'); -Route::get('user/reset/{token}', 'UserController@reset_password'); +Route::get('user/reset/{token?}', 'UserController@reset_password'); Route::post('user/reset', 'UserController@do_reset_password'); Route::get('logout', 'UserController@logout'); @@ -67,18 +67,15 @@ Route::group(array('before' => 'auth'), function() Route::get('dashboard', 'DashboardController@index'); Route::get('view_archive/{entity_type}/{visible}', 'AccountController@setTrashVisible'); Route::get('force_inline_pdf', 'UserController@forcePDFJS'); + + Route::get('api/users', array('as'=>'api.users', 'uses'=>'UserController@getDatatable')); + Route::resource('users', 'UserController'); + Route::post('users/delete', 'UserController@delete'); Route::get('api/products', array('as'=>'api.products', 'uses'=>'ProductController@getDatatable')); Route::resource('products', 'ProductController'); Route::get('products/{product_id}/archive', 'ProductController@archive'); - /* - Route::get('company/products/{product_id}/edit', 'ProductController@showProduct'); - Route::get('company/products/{product_id}/archive', 'ProductController@archiveProduct'); - Route::get('company/products/create', 'ProductController@createProduct'); - Route::post('company/products/{product_id?}', 'AccountController@saveProduct'); - */ - Route::get('company/advanced_settings/chart_builder', 'ReportController@report'); Route::post('company/advanced_settings/chart_builder', 'ReportController@report'); @@ -163,14 +160,16 @@ define('ACCOUNT_ADVANCED_SETTINGS', 'advanced_settings'); define('ACCOUNT_CUSTOM_FIELDS', 'custom_fields'); define('ACCOUNT_INVOICE_DESIGN', 'invoice_design'); define('ACCOUNT_CHART_BUILDER', 'chart_builder'); - +define('ACCOUNT_USER_MANAGEMENT', 'user_management'); + define('DEFAULT_INVOICE_NUMBER', '0001'); define('RECENTLY_VIEWED_LIMIT', 8); define('LOGGED_ERROR_LIMIT', 100); define('RANDOM_KEY_LENGTH', 32); define('MAX_NUM_CLIENTS', 500); -define('MAX_NUM_CLIENTS_PRO', 5000); +define('MAX_NUM_CLIENTS_PRO', 20000); +define('MAX_NUM_USERS', 5); define('INVOICE_STATUS_DRAFT', 1); define('INVOICE_STATUS_SENT', 2); diff --git a/app/start/global.php b/app/start/global.php index 4314e7817c..3cbc1a5ac7 100755 --- a/app/start/global.php +++ b/app/start/global.php @@ -58,9 +58,15 @@ $monolog->pushHandler(new Monolog\Handler\SyslogHandler('intranet', 'user', Logg App::error(function(Exception $exception, $code) { - Utils::logError($exception . ' ' . $code); - - return Response::view('error', ['hideHeader' => true, 'error' => "A {$code} error occurred."], $code); + if (Utils::isNinjaProd()) + { + Utils::logError($exception . ' ' . $code); + return Response::view('error', ['hideHeader' => true, 'error' => "A {$code} error occurred."], $code); + } + else + { + return null; + } }); /* diff --git a/app/views/accounts/nav_advanced.blade.php b/app/views/accounts/nav_advanced.blade.php index 538a14146a..8e0e03d79c 100644 --- a/app/views/accounts/nav_advanced.blade.php +++ b/app/views/accounts/nav_advanced.blade.php @@ -2,6 +2,7 @@ {{ HTML::nav_link('company/advanced_settings/custom_fields', 'custom_fields') }} {{ HTML::nav_link('company/advanced_settings/invoice_design', 'invoice_design') }} {{ HTML::nav_link('company/advanced_settings/chart_builder', 'chart_builder') }} + {{ HTML::nav_link('company/advanced_settings/user_management', 'user_management') }} +diff --git a/app/views/accounts/products.blade.php b/app/views/accounts/products.blade.php index 045a91568e..26cd3b66ee 100644 --- a/app/views/accounts/products.blade.php +++ b/app/views/accounts/products.blade.php @@ -28,10 +28,10 @@ ->setOptions('bFilter', false) ->setOptions('bAutoWidth', false) ->setOptions('aoColumns', [[ "sWidth"=> "20%" ], [ "sWidth"=> "45%" ], ["sWidth"=> "20%"], ["sWidth"=> "15%" ]]) + ->setOptions('aoColumnDefs', [['bSortable'=>false, 'aTargets'=>[3]]]) ->render('datatable') }} diff --git a/app/views/accounts/user_management.blade.php b/app/views/accounts/user_management.blade.php new file mode 100644 index 0000000000..3906222c55 --- /dev/null +++ b/app/views/accounts/user_management.blade.php @@ -0,0 +1,52 @@ +@extends('accounts.nav') + +@section('content') + @parent + @include('accounts.nav_advanced') + + {{ Button::success_link(URL::to('users/create'), trans("texts.add_user"), array('class' => 'pull-right'))->append_with_icon('plus-sign') }} + + {{ Datatable::table() + ->addColumn( + trans('texts.name'), + trans('texts.email'), + trans('texts.user_state'), + trans('texts.action')) + ->setUrl(url('api/users/')) + ->setOptions('sPaginationType', 'bootstrap') + ->setOptions('bFilter', false) + ->setOptions('bAutoWidth', false) + ->setOptions('aoColumns', [[ "sWidth"=> "20%" ], [ "sWidth"=> "45%" ], ["sWidth"=> "20%"], ["sWidth"=> "15%" ]]) + ->setOptions('aoColumnDefs', [['bSortable'=>false, 'aTargets'=>[3]]]) + ->render('datatable') }} + + + {{ Former::open('users/delete')->addClass('user-form') }} + + {{ Former::close() }} + + + +@stop diff --git a/app/views/credits/edit.blade.php b/app/views/credits/edit.blade.php index 052c6b8ad0..1b02490817 100755 --- a/app/views/credits/edit.blade.php +++ b/app/views/credits/edit.blade.php @@ -9,7 +9,7 @@ {{ Former::open($url)->addClass('col-md-10 col-md-offset-1 warn-on-exit')->method($method)->rules(array( - 'client' => 'required', + 'client' => 'required', 'amount' => 'required', )); }} diff --git a/app/views/emails/confirm_html.blade.php b/app/views/emails/confirm_html.blade.php index 23ccaa641d..cf9f696c8f 100755 --- a/app/views/emails/confirm_html.blade.php +++ b/app/views/emails/confirm_html.blade.php @@ -1,6 +1,6 @@
{{ Former::password('password') }} diff --git a/bootstrap/start.php b/bootstrap/start.php index 7382448fac..d265f8b1b7 100755 --- a/bootstrap/start.php +++ b/bootstrap/start.php @@ -1,6 +1,5 @@ 0 ? formatMoney(invoice.discount_amount, invoice.client.currency_id) : false} ]; - if (NINJA.parseFloat(invoice.custom_value1) && NINJA.parseFloat(invoice.custom_taxes1)) { + if (NINJA.parseFloat(invoice.custom_value1) && invoice.custom_taxes1 == '1') { data.push({'custom_invoice_label1': formatMoney(invoice.custom_value1, invoice.client.currency_id) }) } - if (NINJA.parseFloat(invoice.custom_value2) && NINJA.parseFloat(invoice.custom_taxes2)) { + if (NINJA.parseFloat(invoice.custom_value2) && invoice.custom_taxes2 == '1') { data.push({'custom_invoice_label2': formatMoney(invoice.custom_value2, invoice.client.currency_id) }) } data.push({'tax': invoice.tax_amount > 0 ? formatMoney(invoice.tax_amount, invoice.client.currency_id) : false}); - if (NINJA.parseFloat(invoice.custom_value1) && !NINJA.parseFloat(invoice.custom_taxes1)) { + if (NINJA.parseFloat(invoice.custom_value1) && invoice.custom_taxes1 != '1') { data.push({'custom_invoice_label1': formatMoney(invoice.custom_value1, invoice.client.currency_id) }) } - if (NINJA.parseFloat(invoice.custom_value2) && !NINJA.parseFloat(invoice.custom_taxes2)) { + if (NINJA.parseFloat(invoice.custom_value2) && invoice.custom_taxes2 != '1') { data.push({'custom_invoice_label2': formatMoney(invoice.custom_value2, invoice.client.currency_id) }) } @@ -47433,10 +47433,10 @@ function calculateAmounts(invoice) { } // custom fields with taxes - if (NINJA.parseFloat(invoice.custom_value1) && NINJA.parseFloat(invoice.custom_taxes1)) { + if (NINJA.parseFloat(invoice.custom_value1) && invoice.custom_taxes1 == '1') { total += roundToTwo(invoice.custom_value1); } - if (NINJA.parseFloat(invoice.custom_value2) && NINJA.parseFloat(invoice.custom_taxes2)) { + if (NINJA.parseFloat(invoice.custom_value2) && invoice.custom_taxes2 == '1') { total += roundToTwo(invoice.custom_value2); } @@ -47453,10 +47453,10 @@ function calculateAmounts(invoice) { } // custom fields w/o with taxes - if (NINJA.parseFloat(invoice.custom_value1) && !NINJA.parseFloat(invoice.custom_taxes1)) { + if (NINJA.parseFloat(invoice.custom_value1) && invoice.custom_taxes1 != '1') { total += roundToTwo(invoice.custom_value1); } - if (NINJA.parseFloat(invoice.custom_value2) && !NINJA.parseFloat(invoice.custom_taxes2)) { + if (NINJA.parseFloat(invoice.custom_value2) && invoice.custom_taxes2 != '1') { total += roundToTwo(invoice.custom_value2); } diff --git a/public/js/script.js b/public/js/script.js index f4e5b3a7de..759d21315e 100644 --- a/public/js/script.js +++ b/public/js/script.js @@ -1336,19 +1336,19 @@ function displaySubtotals(doc, layout, invoice, y, rightAlignTitleX) {'discount': invoice.discount_amount > 0 ? formatMoney(invoice.discount_amount, invoice.client.currency_id) : false} ]; - if (NINJA.parseFloat(invoice.custom_value1) && NINJA.parseFloat(invoice.custom_taxes1)) { + if (NINJA.parseFloat(invoice.custom_value1) && invoice.custom_taxes1 == '1') { data.push({'custom_invoice_label1': formatMoney(invoice.custom_value1, invoice.client.currency_id) }) } - if (NINJA.parseFloat(invoice.custom_value2) && NINJA.parseFloat(invoice.custom_taxes2)) { + if (NINJA.parseFloat(invoice.custom_value2) && invoice.custom_taxes2 == '1') { data.push({'custom_invoice_label2': formatMoney(invoice.custom_value2, invoice.client.currency_id) }) } data.push({'tax': invoice.tax_amount > 0 ? formatMoney(invoice.tax_amount, invoice.client.currency_id) : false}); - if (NINJA.parseFloat(invoice.custom_value1) && !NINJA.parseFloat(invoice.custom_taxes1)) { + if (NINJA.parseFloat(invoice.custom_value1) && invoice.custom_taxes1 != '1') { data.push({'custom_invoice_label1': formatMoney(invoice.custom_value1, invoice.client.currency_id) }) } - if (NINJA.parseFloat(invoice.custom_value2) && !NINJA.parseFloat(invoice.custom_taxes2)) { + if (NINJA.parseFloat(invoice.custom_value2) && invoice.custom_taxes2 != '1') { data.push({'custom_invoice_label2': formatMoney(invoice.custom_value2, invoice.client.currency_id) }) } @@ -1508,10 +1508,10 @@ function calculateAmounts(invoice) { } // custom fields with taxes - if (NINJA.parseFloat(invoice.custom_value1) && NINJA.parseFloat(invoice.custom_taxes1)) { + if (NINJA.parseFloat(invoice.custom_value1) && invoice.custom_taxes1 == '1') { total += roundToTwo(invoice.custom_value1); } - if (NINJA.parseFloat(invoice.custom_value2) && NINJA.parseFloat(invoice.custom_taxes2)) { + if (NINJA.parseFloat(invoice.custom_value2) && invoice.custom_taxes2 == '1') { total += roundToTwo(invoice.custom_value2); } @@ -1528,10 +1528,10 @@ function calculateAmounts(invoice) { } // custom fields w/o with taxes - if (NINJA.parseFloat(invoice.custom_value1) && !NINJA.parseFloat(invoice.custom_taxes1)) { + if (NINJA.parseFloat(invoice.custom_value1) && invoice.custom_taxes1 != '1') { total += roundToTwo(invoice.custom_value1); } - if (NINJA.parseFloat(invoice.custom_value2) && !NINJA.parseFloat(invoice.custom_taxes2)) { + if (NINJA.parseFloat(invoice.custom_value2) && invoice.custom_taxes2 != '1') { total += roundToTwo(invoice.custom_value2); }