diff --git a/app/Http/Controllers/AccountController.php b/app/Http/Controllers/AccountController.php index 540567d9b339..dcb9438c1a8c 100644 --- a/app/Http/Controllers/AccountController.php +++ b/app/Http/Controllers/AccountController.php @@ -647,6 +647,9 @@ class AccountController extends BaseController $user->username = trim(Input::get('email')); $user->email = trim(strtolower(Input::get('email'))); $user->phone = trim(Input::get('phone')); + if (Utils::isNinja()) { + $user->dark_mode = Input::get('dark_mode') ? true : false; + } $user->save(); } diff --git a/app/Http/Controllers/AccountGatewayController.php b/app/Http/Controllers/AccountGatewayController.php index b6f3c5df22d5..ff4c84c649be 100644 --- a/app/Http/Controllers/AccountGatewayController.php +++ b/app/Http/Controllers/AccountGatewayController.php @@ -257,6 +257,8 @@ class AccountGatewayController extends BaseController } $accountGateway->accepted_credit_cards = $cardCount; + $accountGateway->show_address = Input::get('show_address') ? true : false; + $accountGateway->update_address = Input::get('update_address') ? true : false; $accountGateway->config = json_encode($config); if ($accountGatewayPublicId) { @@ -278,7 +280,7 @@ class AccountGatewayController extends BaseController Session::flash('message', $message); - return Redirect::to('company/payments'); + return Redirect::to("gateways/{$accountGateway->public_id}/edit"); } } diff --git a/app/Http/Controllers/InvoiceController.php b/app/Http/Controllers/InvoiceController.php index 0a9220c7271d..20c938e8252f 100644 --- a/app/Http/Controllers/InvoiceController.php +++ b/app/Http/Controllers/InvoiceController.php @@ -375,10 +375,9 @@ class InvoiceController extends BaseController 'method' => 'POST', 'url' => 'invoices', 'title' => trans('texts.new_invoice'), - 'client' => $client, - 'tasks' => Session::get('tasks') ? json_encode(Session::get('tasks')) : null); + 'client' => $client); $data = array_merge($data, self::getViewModel()); - + return View::make('invoices.edit', $data); } @@ -417,7 +416,7 @@ class InvoiceController extends BaseController ), 'recurringHelp' => $recurringHelp, 'invoiceLabels' => Auth::user()->account->getInvoiceLabels(), - + 'tasks' => Session::get('tasks') ? json_encode(Session::get('tasks')) : null, ]; } diff --git a/app/Http/Controllers/PaymentController.php b/app/Http/Controllers/PaymentController.php index a68841d580dd..6248a8e6917b 100644 --- a/app/Http/Controllers/PaymentController.php +++ b/app/Http/Controllers/PaymentController.php @@ -233,33 +233,41 @@ class PaymentController extends BaseController private function convertInputForOmnipay($input) { - $country = Country::find($input['country_id']); - - return [ + $data = [ 'firstName' => $input['first_name'], 'lastName' => $input['last_name'], 'number' => $input['card_number'], 'expiryMonth' => $input['expiration_month'], 'expiryYear' => $input['expiration_year'], 'cvv' => $input['cvv'], - 'billingAddress1' => $input['address1'], - 'billingAddress2' => $input['address2'], - 'billingCity' => $input['city'], - 'billingState' => $input['state'], - 'billingPostcode' => $input['postal_code'], - 'billingCountry' => $country->iso_3166_2, - 'shippingAddress1' => $input['address1'], - 'shippingAddress2' => $input['address2'], - 'shippingCity' => $input['city'], - 'shippingState' => $input['state'], - 'shippingPostcode' => $input['postal_code'], - 'shippingCountry' => $country->iso_3166_2 ]; + + if (isset($input['country_id'])) { + $country = Country::find($input['country_id']); + + $data = array_merge($data, [ + 'billingAddress1' => $input['address1'], + 'billingAddress2' => $input['address2'], + 'billingCity' => $input['city'], + 'billingState' => $input['state'], + 'billingPostcode' => $input['postal_code'], + 'billingCountry' => $country->iso_3166_2, + 'shippingAddress1' => $input['address1'], + 'shippingAddress2' => $input['address2'], + 'shippingCity' => $input['city'], + 'shippingState' => $input['state'], + 'shippingPostcode' => $input['postal_code'], + 'shippingCountry' => $country->iso_3166_2 + ]); + } + + return $data; } private function getPaymentDetails($invitation, $input = null) { $invoice = $invitation->invoice; + $account = $invoice->account; $key = $invoice->account_id.'-'.$invoice->invoice_number; $currencyCode = $invoice->client->currency ? $invoice->client->currency->code : ($invoice->account->currency ? $invoice->account->currency->code : 'USD'); @@ -330,6 +338,7 @@ class PaymentController extends BaseController 'currencyId' => $client->getCurrencyId(), 'account' => $client->account, 'hideLogo' => $account->isWhiteLabel(), + 'showAddress' => $accountGateway->show_address, ]; return View::make('payments.payment', $data); @@ -498,19 +507,30 @@ class PaymentController extends BaseController public function do_payment($invitationKey, $onSite = true, $useToken = false) { - $rules = array( + $invitation = Invitation::with('invoice.invoice_items', 'invoice.client.currency', 'invoice.client.account.currency', 'invoice.client.account.account_gateways.gateway')->where('invitation_key', '=', $invitationKey)->firstOrFail(); + $invoice = $invitation->invoice; + $client = $invoice->client; + $account = $client->account; + $accountGateway = $account->getGatewayByType(Session::get('payment_type')); + + $rules = [ 'first_name' => 'required', 'last_name' => 'required', 'card_number' => 'required', 'expiration_month' => 'required', 'expiration_year' => 'required', 'cvv' => 'required', - 'address1' => 'required', - 'city' => 'required', - 'state' => 'required', - 'postal_code' => 'required', - 'country_id' => 'required', - ); + ]; + + if ($accountGateway->show_address) { + $rules = array_merge($rules, [ + 'address1' => 'required', + 'city' => 'required', + 'state' => 'required', + 'postal_code' => 'required', + 'country_id' => 'required', + ]); + } if ($onSite) { $validator = Validator::make(Input::all(), $rules); @@ -522,23 +542,16 @@ class PaymentController extends BaseController ->withInput(); } } - - $invitation = Invitation::with('invoice.invoice_items', 'invoice.client.currency', 'invoice.client.account.currency', 'invoice.client.account.account_gateways.gateway')->where('invitation_key', '=', $invitationKey)->firstOrFail(); - $invoice = $invitation->invoice; - $client = $invoice->client; - $account = $client->account; - $accountGateway = $account->getGatewayByType(Session::get('payment_type')); - - /* - if ($onSite) { + + if ($onSite && $accountGateway->update_address) { $client->address1 = trim(Input::get('address1')); $client->address2 = trim(Input::get('address2')); $client->city = trim(Input::get('city')); $client->state = trim(Input::get('state')); $client->postal_code = trim(Input::get('postal_code')); + $client->country_id = Input::get('country_id'); $client->save(); } - */ try { $gateway = self::createGateway($accountGateway); diff --git a/app/Http/Controllers/TaskController.php b/app/Http/Controllers/TaskController.php index a1b12dad293c..9ca05f64f5d4 100644 --- a/app/Http/Controllers/TaskController.php +++ b/app/Http/Controllers/TaskController.php @@ -13,31 +13,19 @@ use DropdownButton; use App\Models\Client; use App\Models\Task; -/* -use Auth; -use Cache; - -use App\Models\Activity; -use App\Models\Contact; -use App\Models\Invoice; -use App\Models\Size; -use App\Models\PaymentTerm; -use App\Models\Industry; -use App\Models\Currency; -use App\Models\Country; -*/ - use App\Ninja\Repositories\TaskRepository; +use App\Ninja\Repositories\InvoiceRepository; class TaskController extends BaseController { protected $taskRepo; - public function __construct(TaskRepository $taskRepo) + public function __construct(TaskRepository $taskRepo, InvoiceRepository $invoiceRepo) { parent::__construct(); $this->taskRepo = $taskRepo; + $this->invoiceRepo = $invoiceRepo; } /** @@ -71,8 +59,8 @@ class TaskController extends BaseController ->addColumn('client_name', function ($model) { return $model->client_public_id ? link_to('clients/'.$model->client_public_id, Utils::getClientDisplayName($model)) : ''; }); } - return $table->addColumn('start_time', function($model) { return Utils::fromSqlDateTime($model->start_time); }) - ->addColumn('duration', function($model) { return gmdate('H:i:s', $model->is_running ? time() - strtotime($model->start_time) : $model->duration); }) + return $table->addColumn('created_at', function($model) { return Task::calcStartTime($model); }) + ->addColumn('time_log', function($model) { return gmdate('H:i:s', Task::calcDuration($model)); }) ->addColumn('description', function($model) { return $model->description; }) ->addColumn('invoice_number', function($model) { return self::getStatusLabel($model); }) ->addColumn('dropdown', function ($model) { @@ -169,8 +157,16 @@ class TaskController extends BaseController if ($task->invoice) { $actions[] = ['url' => URL::to("inovices/{$task->invoice->public_id}/edit"), 'label' => trans("texts.view_invoice")]; } else { - $actions[] = ['url' => 'javascript:submitAction("invoice")', 'label' => trans("texts.invoice_task")]; + $actions[] = ['url' => 'javascript:submitAction("invoice")', 'label' => trans("texts.create_invoice")]; + + // check for any open invoices + $invoices = $task->client_id ? $this->invoiceRepo->findOpenInvoices($task->client_id) : []; + + foreach ($invoices as $invoice) { + $actions[] = ['url' => 'javascript:submitAction("add_to_invoice", '.$invoice->public_id.')', 'label' => trans("texts.add_to_invoice", ["invoice" => $invoice->invoice_number])]; + } } + $actions[] = DropdownButton::DIVIDER; if (!$task->trashed()) { $actions[] = ['url' => 'javascript:submitAction("archive")', 'label' => trans('texts.archive_task')]; @@ -178,15 +174,15 @@ class TaskController extends BaseController } else { $actions[] = ['url' => 'javascript:submitAction("restore")', 'label' => trans('texts.restore_task')]; } - + $data = [ 'task' => $task, 'clientPublicId' => $task->client ? $task->client->public_id : 0, 'method' => 'PUT', 'url' => 'tasks/'.$publicId, 'title' => trans('texts.edit_task'), - 'duration' => $task->resume_time ? ($task->duration + strtotime('now') - strtotime($task->resume_time)) : (strtotime('now') - strtotime($task->start_time)), - 'actions' => $actions + 'duration' => $task->is_running ? $task->getCurrentDuration() : $task->getDuration(), + 'actions' => $actions, ]; $data = array_merge($data, self::getViewModel()); @@ -216,7 +212,7 @@ class TaskController extends BaseController { $action = Input::get('action'); - if (in_array($action, ['archive', 'delete', 'invoice', 'restore'])) { + if (in_array($action, ['archive', 'delete', 'invoice', 'restore', 'add_to_invoice'])) { return self::bulk(); } @@ -235,12 +231,11 @@ class TaskController extends BaseController $this->taskRepo->save($ids, ['action' => $action]); Session::flash('message', trans('texts.stopped_task')); return Redirect::to('tasks'); - } else if ($action == 'invoice') { - + } else if ($action == 'invoice' || $action == 'add_to_invoice') { $tasks = Task::scope($ids)->with('client')->get(); $clientPublicId = false; $data = []; - + foreach ($tasks as $task) { if ($task->client) { if (!$clientPublicId) { @@ -258,16 +253,21 @@ class TaskController extends BaseController Session::flash('error', trans('texts.task_error_invoiced')); return Redirect::to('tasks'); } - + $data[] = [ 'publicId' => $task->public_id, 'description' => $task->description, - 'startTime' => Utils::fromSqlDateTime($task->start_time), - 'duration' => round($task->duration / (60 * 60), 2) + 'startTime' => $task->getStartTime(), + 'duration' => $task->getHours(), ]; } - return Redirect::to("invoices/create/{$clientPublicId}")->with('tasks', $data); + if ($action == 'invoice') { + return Redirect::to("invoices/create/{$clientPublicId}")->with('tasks', $data); + } else { + $invoiceId = Input::get('invoice_id'); + return Redirect::to("invoices/{$invoiceId}/edit")->with('tasks', $data); + } } else { $count = $this->taskRepo->bulk($ids, $action); diff --git a/app/Http/routes.php b/app/Http/routes.php index 0825afb383e4..542c2638e7e8 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -1,5 +1,6 @@ share_counter ? $this->quote_number_counter : $this->invoice_number_counter; $prefix .= $isQuote ? $this->quote_number_prefix : $this->invoice_number_prefix; - + // confirm the invoice number isn't already taken do { $number = $prefix.str_pad($counter, 4, "0", STR_PAD_LEFT); @@ -186,11 +186,14 @@ class Account extends Eloquent { // check if the user modified the invoice number if (!$isRecurring && $invoiceNumber != $this->getNextInvoiceNumber($isQuote)) { - $number = intval(preg_replace('/[^0-9]/', '', $invoiceNumber)); + // remove the prefix + $prefix = $isQuote ? $this->quote_number_prefix : $this->invoice_number_prefix; + $invoiceNumber = preg_replace('/^'.$prefix.'/', '', $invoiceNumber); + $invoiceNumber = intval(preg_replace('/[^0-9]/', '', $invoiceNumber)); if ($isQuote && !$this->share_counter) { - $this->quote_number_counter = $number + 1; + $this->quote_number_counter = $invoiceNumber + 1; } else { - $this->invoice_number_counter = $number + 1; + $this->invoice_number_counter = $invoiceNumber + 1; } // otherwise, just increment the counter } else { diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index 6207bfb14041..27c0999c7a2c 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -252,8 +252,11 @@ class Invoice extends EntityModel } } -Invoice::created(function ($invoice) { +Invoice::creating(function ($invoice) { $invoice->account->incrementCounter($invoice->invoice_number, $invoice->is_quote, $invoice->recurring_invoice_id); +}); + +Invoice::created(function ($invoice) { Activity::createInvoice($invoice); }); @@ -267,4 +270,4 @@ Invoice::deleting(function ($invoice) { Invoice::restoring(function ($invoice) { Activity::restoreInvoice($invoice); -}); +}); \ No newline at end of file diff --git a/app/Models/Task.php b/app/Models/Task.php index 68cfaffe2e75..4ccbf9688ab3 100644 --- a/app/Models/Task.php +++ b/app/Models/Task.php @@ -1,7 +1,7 @@ belongsTo('App\Models\Client')->withTrashed(); } + + public static function calcStartTime($task) + { + $parts = json_decode($task->time_log) ?: []; + + if (count($parts)) { + return Utils::timestampToDateTimeString($parts[0][0]); + } else { + return ''; + } + } + + public function getStartTime() + { + return self::calcStartTime($this); + } + + public static function calcDuration($task) + { + $duration = 0; + $parts = json_decode($task->time_log) ?: []; + + foreach ($parts as $part) { + if (count($part) == 1 || !$part[1]) { + $duration += time() - $part[0]; + } else { + $duration += $part[1] - $part[0]; + } + } + + return $duration; + } + + public function getDuration() + { + return self::calcDuration($this); + } + + public function getCurrentDuration() + { + $parts = json_decode($this->time_log) ?: []; + $part = $parts[count($parts)-1]; + + if (count($part) == 1 || !$part[1]) { + return time() - $part[0]; + } else { + return 0; + } + } + + public function hasPreviousDuration() + { + $parts = json_decode($this->time_log) ?: []; + return count($parts) && (count($parts[0]) && $parts[0][1]); + } + + public function getHours() + { + return round($this->getDuration() / (60 * 60), 2); + } } Task::created(function ($task) { diff --git a/app/Ninja/Mailers/Mailer.php b/app/Ninja/Mailers/Mailer.php index 47c7756ab59f..ffd0abdadee8 100644 --- a/app/Ninja/Mailers/Mailer.php +++ b/app/Ninja/Mailers/Mailer.php @@ -34,10 +34,14 @@ class Mailer }); return true; - } catch (Exception $e) { - $response = $e->getResponse()->getBody()->getContents(); - $response = json_decode($response); - return nl2br($response->Message); + } catch (Exception $exception) { + if (method_exists($exception, 'getResponse')) { + $response = $exception->getResponse()->getBody()->getContents(); + $response = json_decode($response); + return nl2br($response->Message); + } else { + return $exception->getMessage(); + } } } } diff --git a/app/Ninja/Repositories/InvoiceRepository.php b/app/Ninja/Repositories/InvoiceRepository.php index f4caa63ee2e2..ce0397d64b4d 100644 --- a/app/Ninja/Repositories/InvoiceRepository.php +++ b/app/Ninja/Repositories/InvoiceRepository.php @@ -536,4 +536,16 @@ class InvoiceRepository return count($invoices); } + + public function findOpenInvoices($clientId) + { + return Invoice::scope() + ->whereClientId($clientId) + ->whereIsQuote(false) + ->whereIsRecurring(false) + ->whereHasTasks(true) + ->where('balance', '>', 0) + ->select(['public_id', 'invoice_number']) + ->get(); + } } diff --git a/app/Ninja/Repositories/TaskRepository.php b/app/Ninja/Repositories/TaskRepository.php index feb764850ad3..4504e78fb7fa 100644 --- a/app/Ninja/Repositories/TaskRepository.php +++ b/app/Ninja/Repositories/TaskRepository.php @@ -23,7 +23,7 @@ class TaskRepository }) ->where('contacts.deleted_at', '=', null) ->where('clients.deleted_at', '=', null) - ->select('tasks.public_id', 'clients.name as client_name', 'clients.public_id as client_public_id', 'contacts.first_name', 'contacts.email', 'contacts.last_name', 'invoices.invoice_status_id', 'tasks.start_time', 'tasks.description', 'tasks.duration', 'tasks.is_deleted', 'tasks.deleted_at', 'invoices.invoice_number', 'invoices.public_id as invoice_public_id', 'tasks.is_running'); + ->select('tasks.public_id', 'clients.name as client_name', 'clients.public_id as client_public_id', 'contacts.first_name', 'contacts.email', 'contacts.last_name', 'invoices.invoice_status_id', 'tasks.description', 'tasks.is_deleted', 'tasks.deleted_at', 'invoices.invoice_number', 'invoices.public_id as invoice_public_id', 'tasks.is_running', 'tasks.time_log', 'tasks.created_at'); if ($clientPublicId) { $query->where('clients.public_id', '=', $clientPublicId); @@ -60,36 +60,20 @@ class TaskRepository $task->description = trim($data['description']); } - $timeLog = $task->time_log ? json_decode($task->time_log, true) : []; - + //$timeLog = $task->time_log ? json_decode($task->time_log, true) : []; + $timeLog = isset($data['time_log']) ? json_decode($data['time_log']) : []; if ($data['action'] == 'start') { - $task->start_time = Carbon::now()->toDateTimeString(); $task->is_running = true; $timeLog[] = [strtotime('now'), false]; } else if ($data['action'] == 'resume') { - $task->break_duration = strtotime('now') - strtotime($task->start_time) + $task->duration; - $task->resume_time = Carbon::now()->toDateTimeString(); $task->is_running = true; $timeLog[] = [strtotime('now'), false]; } else if ($data['action'] == 'stop' && $task->is_running) { - if ($task->resume_time) { - $task->duration = $task->duration + strtotime('now') - strtotime($task->resume_time); - $task->resume_time = null; - } else { - $task->duration = strtotime('now') - strtotime($task->start_time); - } - $timeLog[count($timeLog)-1][1] = strtotime('now'); + $timeLog[count($timeLog)-1][1] = time(); $task->is_running = false; - } else if ($data['action'] == 'save' && !$task->is_running) { - $task->start_time = $data['start_time']; - $task->duration = $data['duration']; - $task->break_duration = $data['break_duration']; } - $task->duration = max($task->duration, 0); - $task->break_duration = max($task->break_duration, 0); $task->time_log = json_encode($timeLog); - $task->save(); return $task; diff --git a/database/migrations/2015_07_08_114333_simplify_tasks.php b/database/migrations/2015_07_08_114333_simplify_tasks.php new file mode 100644 index 000000000000..b0136a33ec91 --- /dev/null +++ b/database/migrations/2015_07_08_114333_simplify_tasks.php @@ -0,0 +1,73 @@ +start_time); + if (!$task->time_log || !count(json_decode($task->time_log))) { + $task->time_log = json_encode([[$startTime, $startTime + $task->duration]]); + $task->save(); + } elseif ($task->getDuration() != intval($task->duration)) { + $task->time_log = json_encode([[$startTime, $startTime + $task->duration]]); + $task->save(); + } + } + + Schema::table('tasks', function($table) + { + $table->dropColumn('start_time'); + $table->dropColumn('duration'); + $table->dropColumn('break_duration'); + $table->dropColumn('resume_time'); + }); + + Schema::table('users', function($table) + { + $table->boolean('dark_mode')->default(false)->nullable(); + }); + + Schema::table('users', function($table) + { + $table->dropColumn('theme_id'); + }); + + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('tasks', function($table) + { + $table->timestamp('start_time')->nullable(); + $table->integer('duration')->nullable(); + $table->timestamp('resume_time')->nullable(); + $table->integer('break_duration')->nullable(); + }); + + Schema::table('users', function($table) + { + $table->dropColumn('dark_mode'); + }); + Schema::table('users', function($table) + { + $table->integer('theme_id')->nullable(); + }); + } + +} diff --git a/public/css/built.css b/public/css/built.css index 5c4e52f5c523..ab4839c61fd8 100644 --- a/public/css/built.css +++ b/public/css/built.css @@ -2433,6 +2433,8 @@ th {border-left: 1px solid #d26b26; } .table>thead>tr>th, .table>tbody>tr>th, .table>tfoot>tr>th, .table>thead>tr>td, .table>tbody>tr>td, .table>tfoot>tr>td { vertical-align: middle; border-top: none; +} +table.invoice-table>thead>tr>th, table.invoice-table>tbody>tr>th, table.invoice-table>tfoot>tr>th, table.invoice-table>thead>tr>td, table.invoice-table>tbody>tr>td, table.invoice-table>tfoot>tr>td { border-bottom: 1px solid #dfe0e1; } table.dataTable.no-footer { diff --git a/public/css/style.css b/public/css/style.css index 5e536810750b..6c31f3041907 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -83,6 +83,8 @@ th {border-left: 1px solid #d26b26; } .table>thead>tr>th, .table>tbody>tr>th, .table>tfoot>tr>th, .table>thead>tr>td, .table>tbody>tr>td, .table>tfoot>tr>td { vertical-align: middle; border-top: none; +} +table.invoice-table>thead>tr>th, table.invoice-table>tbody>tr>th, table.invoice-table>tfoot>tr>th, table.invoice-table>thead>tr>td, table.invoice-table>tbody>tr>td, table.invoice-table>tfoot>tr>td { border-bottom: 1px solid #dfe0e1; } table.dataTable.no-footer { diff --git a/resources/lang/da/texts.php b/resources/lang/da/texts.php index 706250b733d1..5c9b160aa6bb 100644 --- a/resources/lang/da/texts.php +++ b/resources/lang/da/texts.php @@ -706,6 +706,24 @@ return array( 'login' => 'Login', 'or' => 'or', + 'email_error' => 'There was a problem sending the email', + 'created_by_recurring' => 'Created by recurring invoice :invoice', + 'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.', + 'old_browser' => 'Please use a newer browser', + 'payment_terms_help' => 'Sets the default invoice due date', + 'unlink_account' => 'Unlink Account', + 'unlink' => 'Unlink', + 'show_address' => 'Show Address', + 'show_address_help' => 'Require client to provide their billing address', + 'update_address' => 'Update Address', + 'update_address_help' => 'Update client\'s address with provided details', + 'times' => 'Times', + 'set_now' => 'Set now', + 'dark_mode' => 'Dark Mode', + 'dark_mode_help' => 'Show white text on black background', + 'add_to_invoice' => 'Add to invoice :invoice', + 'create_new_invoice' => 'Create new invoice', + 'task_errors' => 'Please correct any overlapping times', diff --git a/resources/lang/de/texts.php b/resources/lang/de/texts.php index 461b87811485..482c29ef0b1c 100644 --- a/resources/lang/de/texts.php +++ b/resources/lang/de/texts.php @@ -697,5 +697,24 @@ return array( 'login' => 'Login', 'or' => 'oder', + 'email_error' => 'There was a problem sending the email', + 'created_by_recurring' => 'Created by recurring invoice :invoice', + 'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.', + 'old_browser' => 'Please use a newer browser', + 'payment_terms_help' => 'Sets the default invoice due date', + 'unlink_account' => 'Unlink Account', + 'unlink' => 'Unlink', + 'show_address' => 'Show Address', + 'show_address_help' => 'Require client to provide their billing address', + 'update_address' => 'Update Address', + 'update_address_help' => 'Update client\'s address with provided details', + 'times' => 'Times', + 'set_now' => 'Set now', + 'dark_mode' => 'Dark Mode', + 'dark_mode_help' => 'Show white text on black background', + 'add_to_invoice' => 'Add to invoice :invoice', + 'create_new_invoice' => 'Create new invoice', + 'task_errors' => 'Please correct any overlapping times', + ); \ No newline at end of file diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 728fd8c37690..7861fb9a80ac 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -276,9 +276,9 @@ return array( // Payment page 'secure_payment' => 'Secure Payment', - 'card_number' => 'Card number', - 'expiration_month' => 'Expiration month', - 'expiration_year' => 'Expiration year', + 'card_number' => 'Card Number', + 'expiration_month' => 'Expiration Month', + 'expiration_year' => 'Expiration Year', 'cvv' => 'CVV', // Security alerts @@ -526,11 +526,11 @@ return array( 'token_billing_secure' => 'The data is stored securely by :stripe_link', 'support' => 'Support', - 'contact_information' => 'Contact information', + 'contact_information' => 'Contact Information', '256_encryption' => '256-Bit Encryption', 'amount_due' => 'Amount due', - 'billing_address' => 'Billing address', - 'billing_method' => 'Billing method', + 'billing_address' => 'Billing Address', + 'billing_method' => 'Billing Method', 'order_overview' => 'Order overview', 'match_address' => '*Address must match address associated with credit card.', 'click_once' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.', @@ -711,5 +711,16 @@ return array( 'payment_terms_help' => 'Sets the default invoice due date', 'unlink_account' => 'Unlink Account', 'unlink' => 'Unlink', + 'show_address' => 'Show Address', + 'show_address_help' => 'Require client to provide their billing address', + 'update_address' => 'Update Address', + 'update_address_help' => 'Update client\'s address with provided details', + 'times' => 'Times', + 'set_now' => 'Set now', + 'dark_mode' => 'Dark Mode', + 'dark_mode_help' => 'Show white text on black background', + 'add_to_invoice' => 'Add to invoice :invoice', + 'create_new_invoice' => 'Create new invoice', + 'task_errors' => 'Please correct any overlapping times', ); diff --git a/resources/lang/es/texts.php b/resources/lang/es/texts.php index 0d32d825eed3..826902066b98 100644 --- a/resources/lang/es/texts.php +++ b/resources/lang/es/texts.php @@ -676,5 +676,24 @@ return array( 'login' => 'Login', 'or' => 'or', + 'email_error' => 'There was a problem sending the email', + 'created_by_recurring' => 'Created by recurring invoice :invoice', + 'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.', + 'old_browser' => 'Please use a newer browser', + 'payment_terms_help' => 'Sets the default invoice due date', + 'unlink_account' => 'Unlink Account', + 'unlink' => 'Unlink', + 'show_address' => 'Show Address', + 'show_address_help' => 'Require client to provide their billing address', + 'update_address' => 'Update Address', + 'update_address_help' => 'Update client\'s address with provided details', + 'times' => 'Times', + 'set_now' => 'Set now', + 'dark_mode' => 'Dark Mode', + 'dark_mode_help' => 'Show white text on black background', + 'add_to_invoice' => 'Add to invoice :invoice', + 'create_new_invoice' => 'Create new invoice', + 'task_errors' => 'Please correct any overlapping times', + ); \ No newline at end of file diff --git a/resources/lang/es_ES/texts.php b/resources/lang/es_ES/texts.php index 38e48e8276d7..e230e930f1ec 100644 --- a/resources/lang/es_ES/texts.php +++ b/resources/lang/es_ES/texts.php @@ -705,6 +705,25 @@ return array( 'login' => 'Login', 'or' => 'or', + 'email_error' => 'There was a problem sending the email', + 'created_by_recurring' => 'Created by recurring invoice :invoice', + 'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.', + 'old_browser' => 'Please use a newer browser', + 'payment_terms_help' => 'Sets the default invoice due date', + 'unlink_account' => 'Unlink Account', + 'unlink' => 'Unlink', + 'show_address' => 'Show Address', + 'show_address_help' => 'Require client to provide their billing address', + 'update_address' => 'Update Address', + 'update_address_help' => 'Update client\'s address with provided details', + 'times' => 'Times', + 'set_now' => 'Set now', + 'dark_mode' => 'Dark Mode', + 'dark_mode_help' => 'Show white text on black background', + 'add_to_invoice' => 'Add to invoice :invoice', + 'create_new_invoice' => 'Create new invoice', + 'task_errors' => 'Please correct any overlapping times', + ); \ No newline at end of file diff --git a/resources/lang/fr/texts.php b/resources/lang/fr/texts.php index 010c5557709c..e16f140f5eb3 100644 --- a/resources/lang/fr/texts.php +++ b/resources/lang/fr/texts.php @@ -697,6 +697,25 @@ return array( 'login' => 'Connexion', 'or' => 'ou', + 'email_error' => 'There was a problem sending the email', + 'created_by_recurring' => 'Created by recurring invoice :invoice', + 'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.', + 'old_browser' => 'Please use a newer browser', + 'payment_terms_help' => 'Sets the default invoice due date', + 'unlink_account' => 'Unlink Account', + 'unlink' => 'Unlink', + 'show_address' => 'Show Address', + 'show_address_help' => 'Require client to provide their billing address', + 'update_address' => 'Update Address', + 'update_address_help' => 'Update client\'s address with provided details', + 'times' => 'Times', + 'set_now' => 'Set now', + 'dark_mode' => 'Dark Mode', + 'dark_mode_help' => 'Show white text on black background', + 'add_to_invoice' => 'Add to invoice :invoice', + 'create_new_invoice' => 'Create new invoice', + 'task_errors' => 'Please correct any overlapping times', + ); diff --git a/resources/lang/fr_CA/texts.php b/resources/lang/fr_CA/texts.php index 3e808ab19e7f..724cf87a4321 100644 --- a/resources/lang/fr_CA/texts.php +++ b/resources/lang/fr_CA/texts.php @@ -698,5 +698,24 @@ return array( 'login' => 'Login', 'or' => 'or', + 'email_error' => 'There was a problem sending the email', + 'created_by_recurring' => 'Created by recurring invoice :invoice', + 'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.', + 'old_browser' => 'Please use a newer browser', + 'payment_terms_help' => 'Sets the default invoice due date', + 'unlink_account' => 'Unlink Account', + 'unlink' => 'Unlink', + 'show_address' => 'Show Address', + 'show_address_help' => 'Require client to provide their billing address', + 'update_address' => 'Update Address', + 'update_address_help' => 'Update client\'s address with provided details', + 'times' => 'Times', + 'set_now' => 'Set now', + 'dark_mode' => 'Dark Mode', + 'dark_mode_help' => 'Show white text on black background', + 'add_to_invoice' => 'Add to invoice :invoice', + 'create_new_invoice' => 'Create new invoice', + 'task_errors' => 'Please correct any overlapping times', + ); diff --git a/resources/lang/it/texts.php b/resources/lang/it/texts.php index 8b5a3e5047de..4892d732c3f4 100644 --- a/resources/lang/it/texts.php +++ b/resources/lang/it/texts.php @@ -700,6 +700,25 @@ return array( 'login' => 'Login', 'or' => 'or', + 'email_error' => 'There was a problem sending the email', + 'created_by_recurring' => 'Created by recurring invoice :invoice', + 'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.', + 'old_browser' => 'Please use a newer browser', + 'payment_terms_help' => 'Sets the default invoice due date', + 'unlink_account' => 'Unlink Account', + 'unlink' => 'Unlink', + 'show_address' => 'Show Address', + 'show_address_help' => 'Require client to provide their billing address', + 'update_address' => 'Update Address', + 'update_address_help' => 'Update client\'s address with provided details', + 'times' => 'Times', + 'set_now' => 'Set now', + 'dark_mode' => 'Dark Mode', + 'dark_mode_help' => 'Show white text on black background', + 'add_to_invoice' => 'Add to invoice :invoice', + 'create_new_invoice' => 'Create new invoice', + 'task_errors' => 'Please correct any overlapping times', + ); diff --git a/resources/lang/lt/texts.php b/resources/lang/lt/texts.php index 66f56de588f8..eaf8bbb9e5d7 100644 --- a/resources/lang/lt/texts.php +++ b/resources/lang/lt/texts.php @@ -707,6 +707,25 @@ return array( 'login' => 'Login', 'or' => 'or', + 'email_error' => 'There was a problem sending the email', + 'created_by_recurring' => 'Created by recurring invoice :invoice', + 'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.', + 'old_browser' => 'Please use a newer browser', + 'payment_terms_help' => 'Sets the default invoice due date', + 'unlink_account' => 'Unlink Account', + 'unlink' => 'Unlink', + 'show_address' => 'Show Address', + 'show_address_help' => 'Require client to provide their billing address', + 'update_address' => 'Update Address', + 'update_address_help' => 'Update client\'s address with provided details', + 'times' => 'Times', + 'set_now' => 'Set now', + 'dark_mode' => 'Dark Mode', + 'dark_mode_help' => 'Show white text on black background', + 'add_to_invoice' => 'Add to invoice :invoice', + 'create_new_invoice' => 'Create new invoice', + 'task_errors' => 'Please correct any overlapping times', + ); diff --git a/resources/lang/nb_NO/texts.php b/resources/lang/nb_NO/texts.php index a5d9d569da21..1e2a21df14e2 100644 --- a/resources/lang/nb_NO/texts.php +++ b/resources/lang/nb_NO/texts.php @@ -705,6 +705,25 @@ return array( 'login' => 'Login', 'or' => 'or', + 'email_error' => 'There was a problem sending the email', + 'created_by_recurring' => 'Created by recurring invoice :invoice', + 'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.', + 'old_browser' => 'Please use a newer browser', + 'payment_terms_help' => 'Sets the default invoice due date', + 'unlink_account' => 'Unlink Account', + 'unlink' => 'Unlink', + 'show_address' => 'Show Address', + 'show_address_help' => 'Require client to provide their billing address', + 'update_address' => 'Update Address', + 'update_address_help' => 'Update client\'s address with provided details', + 'times' => 'Times', + 'set_now' => 'Set now', + 'dark_mode' => 'Dark Mode', + 'dark_mode_help' => 'Show white text on black background', + 'add_to_invoice' => 'Add to invoice :invoice', + 'create_new_invoice' => 'Create new invoice', + 'task_errors' => 'Please correct any overlapping times', + ); \ No newline at end of file diff --git a/resources/lang/nl/texts.php b/resources/lang/nl/texts.php index 6dad49264bfe..f4e64362a2aa 100644 --- a/resources/lang/nl/texts.php +++ b/resources/lang/nl/texts.php @@ -700,6 +700,25 @@ return array( 'login' => 'Login', 'or' => 'or', + 'email_error' => 'There was a problem sending the email', + 'created_by_recurring' => 'Created by recurring invoice :invoice', + 'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.', + 'old_browser' => 'Please use a newer browser', + 'payment_terms_help' => 'Sets the default invoice due date', + 'unlink_account' => 'Unlink Account', + 'unlink' => 'Unlink', + 'show_address' => 'Show Address', + 'show_address_help' => 'Require client to provide their billing address', + 'update_address' => 'Update Address', + 'update_address_help' => 'Update client\'s address with provided details', + 'times' => 'Times', + 'set_now' => 'Set now', + 'dark_mode' => 'Dark Mode', + 'dark_mode_help' => 'Show white text on black background', + 'add_to_invoice' => 'Add to invoice :invoice', + 'create_new_invoice' => 'Create new invoice', + 'task_errors' => 'Please correct any overlapping times', + ); diff --git a/resources/lang/pt_BR/texts.php b/resources/lang/pt_BR/texts.php index be2080b68341..bfa9c57fa910 100644 --- a/resources/lang/pt_BR/texts.php +++ b/resources/lang/pt_BR/texts.php @@ -700,5 +700,24 @@ return array( 'login' => 'Login', 'or' => 'or', + 'email_error' => 'There was a problem sending the email', + 'created_by_recurring' => 'Created by recurring invoice :invoice', + 'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.', + 'old_browser' => 'Please use a newer browser', + 'payment_terms_help' => 'Sets the default invoice due date', + 'unlink_account' => 'Unlink Account', + 'unlink' => 'Unlink', + 'show_address' => 'Show Address', + 'show_address_help' => 'Require client to provide their billing address', + 'update_address' => 'Update Address', + 'update_address_help' => 'Update client\'s address with provided details', + 'times' => 'Times', + 'set_now' => 'Set now', + 'dark_mode' => 'Dark Mode', + 'dark_mode_help' => 'Show white text on black background', + 'add_to_invoice' => 'Add to invoice :invoice', + 'create_new_invoice' => 'Create new invoice', + 'task_errors' => 'Please correct any overlapping times', + ); diff --git a/resources/lang/sv/texts.php b/resources/lang/sv/texts.php index 86a9de4b8471..e26f1ad515dc 100644 --- a/resources/lang/sv/texts.php +++ b/resources/lang/sv/texts.php @@ -703,6 +703,25 @@ return array( 'login' => 'Login', 'or' => 'or', + 'email_error' => 'There was a problem sending the email', + 'created_by_recurring' => 'Created by recurring invoice :invoice', + 'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.', + 'old_browser' => 'Please use a newer browser', + 'payment_terms_help' => 'Sets the default invoice due date', + 'unlink_account' => 'Unlink Account', + 'unlink' => 'Unlink', + 'show_address' => 'Show Address', + 'show_address_help' => 'Require client to provide their billing address', + 'update_address' => 'Update Address', + 'update_address_help' => 'Update client\'s address with provided details', + 'times' => 'Times', + 'set_now' => 'Set now', + 'dark_mode' => 'Dark Mode', + 'dark_mode_help' => 'Show white text on black background', + 'add_to_invoice' => 'Add to invoice :invoice', + 'create_new_invoice' => 'Create new invoice', + 'task_errors' => 'Please correct any overlapping times', + ); diff --git a/resources/views/accounts/account_gateway.blade.php b/resources/views/accounts/account_gateway.blade.php index 13d6cd337e27..2aa79c2dbb68 100644 --- a/resources/views/accounts/account_gateway.blade.php +++ b/resources/views/accounts/account_gateway.blade.php @@ -14,9 +14,12 @@
@if ($accountGateway) - {!! Former::populateField('payment_type_id', $paymentTypeId) !!} {!! Former::populateField('gateway_id', $accountGateway->gateway_id) !!} - {!! Former::populateField('recommendedGateway_id', $accountGateway->gateway_id) !!} + {!! Former::populateField('payment_type_id', $paymentTypeId) !!} + {!! Former::populateField('recommendedGateway_id', $accountGateway->gateway_id) !!} + {!! Former::populateField('show_address', intval($accountGateway->show_address)) !!} + {!! Former::populateField('update_address', intval($accountGateway->update_address)) !!} + @if ($config) @foreach ($accountGateway->fields as $field => $junk) @if (in_array($field, $hiddenFields)) @@ -28,6 +31,8 @@ @endif @else {!! Former::populateField('gateway_id', GATEWAY_STRIPE) !!} + {!! Former::populateField('show_address', 1) !!} + {!! Former::populateField('update_address', 1) !!} @endif {!! Former::select('payment_type_id') @@ -77,6 +82,15 @@ @endforeach + {!! Former::checkbox('show_address') + ->label(trans('texts.billing_address')) + ->text(trans('texts.show_address_help')) + ->addGroupClass('gateway-option') !!} + {!! Former::checkbox('update_address') + ->label(' ') + ->text(trans('texts.update_address_help')) + ->addGroupClass('gateway-option') !!} + {!! Former::checkboxes('creditCardTypes[]') ->label('Accepted Credit Cards') ->checkboxes($creditCardTypes) @@ -131,11 +145,25 @@ } } + function enableUpdateAddress(event) { + var disabled = !$('#show_address').is(':checked'); + $('#update_address').prop('disabled', disabled); + $('label[for=update_address]').css('color', disabled ? '#888' : '#000'); + if (disabled) { + $('#update_address').prop('checked', false); + } else if (event) { + $('#update_address').prop('checked', true); + } + } + $(function() { setPaymentType(); @if ($accountGateway) $('.payment-type-option').hide(); @endif + + $('#show_address').change(enableUpdateAddress); + enableUpdateAddress(); }) diff --git a/resources/views/accounts/details.blade.php b/resources/views/accounts/details.blade.php index feef5eceb57e..90475d384b75 100644 --- a/resources/views/accounts/details.blade.php +++ b/resources/views/accounts/details.blade.php @@ -22,6 +22,9 @@ {{ Former::populateField('last_name', $account->users()->first()->last_name) }} {{ Former::populateField('email', $account->users()->first()->email) }} {{ Former::populateField('phone', $account->users()->first()->phone) }} + @if (Utils::isNinja()) + {{ Former::populateField('dark_mode', intval($account->users()->first()->dark_mode)) }} + @endif @endif
@@ -88,6 +91,10 @@ {!! Former::text('last_name') !!} {!! Former::text('email') !!} {!! Former::text('phone') !!} + @if (Utils::isNinja()) + {!! Former::checkbox('dark_mode')->text(trans('texts.dark_mode_help')) !!} + @endif + @if (Auth::user()->confirmed) {!! Former::actions( Button::primary(trans('texts.change_password'))->small()->withAttributes(['onclick'=>'showChangePassword()'])) !!} @elseif (Auth::user()->registered) diff --git a/resources/views/accounts/invoice_settings.blade.php b/resources/views/accounts/invoice_settings.blade.php index b46bdfd17b0c..b3b03011578c 100644 --- a/resources/views/accounts/invoice_settings.blade.php +++ b/resources/views/accounts/invoice_settings.blade.php @@ -23,8 +23,7 @@ {{ Former::populateField('custom_invoice_taxes2', intval($account->custom_invoice_taxes2)) }} {{ Former::populateField('share_counter', intval($account->share_counter)) }} {{ Former::populateField('pdf_email_attachment', intval($account->pdf_email_attachment)) }} - {{ Former::populateField('utf8_invoices', intval($account->utf8_invoices)) }} - {{ Former::populateField('auto_wrap', intval($account->auto_wrap)) }} + {{ Former::populateField('utf8_invoices', intval($account->utf8_invoices)) }}
@@ -99,9 +98,6 @@
{!! Former::checkbox('pdf_email_attachment')->text(trans('texts.enable')) !!} {!! Former::checkbox('utf8_invoices')->text(trans('texts.enable')) !!} -
- {!! Former::checkbox('auto_wrap')->text(trans('texts.enable')) !!} -
diff --git a/resources/views/header.blade.php b/resources/views/header.blade.php index f4fc371e66ce..857cbb6b0664 100644 --- a/resources/views/header.blade.php +++ b/resources/views/header.blade.php @@ -25,6 +25,23 @@ } } + @if (Auth::check() && Auth::user()->dark_mode) + body { + background: #000 !important; + color: white !important; + } + + .panel-body { + background: #272822 !important; + /*background: #e6e6e6 !important;*/ + } + + .panel-default { + border-color: #444; + } + @endif + + @include('script') @@ -309,6 +326,15 @@ showSignUp(); @endif + $('ul.navbar-settings, ul.navbar-history').hover(function () { + //$('.user-accounts').find('li').hide(); + //$('.user-accounts').css({display: 'none'}); + //console.log($('.user-accounts').dropdown('')) + if ($('.user-accounts').css('display') == 'block') { + $('.user-accounts').dropdown('toggle'); + } + }); + @yield('onReady') }); @@ -409,7 +435,7 @@
-