From 89269f4bd768f3172a4b0770265bbf41c51fadf4 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Mon, 16 Feb 2015 18:15:05 +0200 Subject: [PATCH 01/32] Added ability for clients to approve a quote, converting it to an invoice --- app/controllers/InvoiceController.php | 13 ++---------- app/controllers/PaymentController.php | 4 ---- app/controllers/QuoteController.php | 22 +++++++++++++++++++- app/lang/da/texts.php | 2 +- app/lang/de/texts.php | 2 +- app/lang/en/texts.php | 1 + app/lang/es/texts.php | 2 +- app/lang/fr/texts.php | 2 +- app/lang/it/texts.php | 2 +- app/lang/lt/texts.php | 3 ++- app/lang/nb_NO/texts.php | 2 +- app/lang/nl/texts.php | 2 +- app/lang/pt_BR/texts.php | 2 +- app/models/Activity.php | 13 ++++++++++++ app/ninja/repositories/InvoiceRepository.php | 2 -- app/routes.php | 2 ++ app/views/invoices/pdf.blade.php | 1 + app/views/invoices/view.blade.php | 22 +++++++++++--------- 18 files changed, 62 insertions(+), 37 deletions(-) diff --git a/app/controllers/InvoiceController.php b/app/controllers/InvoiceController.php index a46df2de6012..11dd20b304d8 100755 --- a/app/controllers/InvoiceController.php +++ b/app/controllers/InvoiceController.php @@ -133,23 +133,13 @@ class InvoiceController extends \BaseController public function view($invitationKey) { $invitation = Invitation::where('invitation_key', '=', $invitationKey)->firstOrFail(); - $invoice = $invitation->invoice; if (!$invoice || $invoice->is_deleted) { return View::make('invoices.deleted'); } - if ($invoice->is_quote && $invoice->quote_invoice_id) { - $invoice = Invoice::scope($invoice->quote_invoice_id, $invoice->account_id)->firstOrFail(); - - if (!$invoice || $invoice->is_deleted) { - return View::make('invoices.deleted'); - } - } - $invoice->load('user', 'invoice_items', 'invoice_design', 'account.country', 'client.contacts', 'client.country'); - $client = $invoice->client; if (!$client || $client->is_deleted) { @@ -169,7 +159,7 @@ class InvoiceController extends \BaseController $invoice->invoice_date = Utils::fromSqlDate($invoice->invoice_date); $invoice->due_date = Utils::fromSqlDate($invoice->due_date); - $invoice->is_pro = $client->account->isPro(); + $invoice->is_pro = $client->account->isPro(); $contact = $invitation->contact; $contact->setVisible([ @@ -179,6 +169,7 @@ class InvoiceController extends \BaseController 'phone', ]); $data = array( + 'isConverted' => $invoice->quote_invoice_id ? true : false, 'showClientHeader' => true, 'showBreadcrumbs' => false, 'hideLogo' => $client->account->isWhiteLabel(), diff --git a/app/controllers/PaymentController.php b/app/controllers/PaymentController.php index 5dc5a2f93662..606ba6f8979e 100755 --- a/app/controllers/PaymentController.php +++ b/app/controllers/PaymentController.php @@ -614,10 +614,6 @@ class PaymentController extends \BaseController $account->save(); } - if ($invoice->is_quote) { - $invoice = $this->invoiceRepo->cloneInvoice($invoice, $invoice->id); - } - $payment = Payment::createNew($invitation); $payment->invitation_id = $invitation->id; $payment->account_gateway_id = $accountGateway->id; diff --git a/app/controllers/QuoteController.php b/app/controllers/QuoteController.php index 9a12dc7fa54d..7753d63fa51f 100644 --- a/app/controllers/QuoteController.php +++ b/app/controllers/QuoteController.php @@ -141,7 +141,7 @@ class QuoteController extends \BaseController $clone = $this->invoiceRepo->cloneInvoice($invoice, $invoice->id); Session::flash('message', trans('texts.converted_to_invoice')); - return Redirect::to('invoices/'.$clone->public_id); + return Redirect::to('invoices/'.$clone->public_id); } $statusId = Input::get('statusId'); @@ -156,4 +156,24 @@ class QuoteController extends \BaseController return Redirect::to('quotes'); } + + public function approve($invitationKey) + { + $invitation = Invitation::with('invoice.invoice_items', 'invoice.invitations')->where('invitation_key', '=', $invitationKey)->firstOrFail(); + $invoice = $invitation->invoice; + + if ($invoice->is_quote && !$invoice->quote_invoice_id) { + Activity::approveQuote($invitation); + $invoice = $this->invoiceRepo->cloneInvoice($invoice, $invoice->id); + Session::flash('message', trans('texts.converted_to_invoice')); + + foreach ($invoice->invitations as $invitationClone) { + if ($invitation->contact_id == $invitationClone->contact_id) { + $invitationKey = $invitationClone->invitation_key; + } + } + } + + return Redirect::to("view/{$invitationKey}"); + } } diff --git a/app/lang/da/texts.php b/app/lang/da/texts.php index 747a5c4eda6d..e1f9114c53e2 100644 --- a/app/lang/da/texts.php +++ b/app/lang/da/texts.php @@ -510,6 +510,6 @@ return array( 'payment_email' => 'Payment Email', 'quote_email' => 'Quote Email', 'reset_all' => 'Reset All', + 'approve' => 'Approve', - ); diff --git a/app/lang/de/texts.php b/app/lang/de/texts.php index 3d5e33a3eb82..2e6eb200db22 100644 --- a/app/lang/de/texts.php +++ b/app/lang/de/texts.php @@ -500,6 +500,6 @@ return array( 'payment_email' => 'Payment Email', 'quote_email' => 'Quote Email', 'reset_all' => 'Reset All', - + 'approve' => 'Approve', ); diff --git a/app/lang/en/texts.php b/app/lang/en/texts.php index 39908b5e78e4..d01ba177f7d9 100644 --- a/app/lang/en/texts.php +++ b/app/lang/en/texts.php @@ -508,5 +508,6 @@ return array( 'payment_email' => 'Payment Email', 'quote_email' => 'Quote Email', 'reset_all' => 'Reset All', + 'approve' => 'Approve', ); diff --git a/app/lang/es/texts.php b/app/lang/es/texts.php index e15ed8c80ebb..80b1dacf658e 100644 --- a/app/lang/es/texts.php +++ b/app/lang/es/texts.php @@ -480,6 +480,6 @@ return array( 'payment_email' => 'Payment Email', 'quote_email' => 'Quote Email', 'reset_all' => 'Reset All', - + 'approve' => 'Approve', ); \ No newline at end of file diff --git a/app/lang/fr/texts.php b/app/lang/fr/texts.php index 7abc939fff16..0e3304f18e8e 100644 --- a/app/lang/fr/texts.php +++ b/app/lang/fr/texts.php @@ -501,6 +501,6 @@ return array( 'payment_email' => 'Payment Email', 'quote_email' => 'Quote Email', 'reset_all' => 'Reset All', - + 'approve' => 'Approve', ); \ No newline at end of file diff --git a/app/lang/it/texts.php b/app/lang/it/texts.php index b21af7c3dcd5..4aae44b0e581 100644 --- a/app/lang/it/texts.php +++ b/app/lang/it/texts.php @@ -503,6 +503,6 @@ return array( 'payment_email' => 'Payment Email', 'quote_email' => 'Quote Email', 'reset_all' => 'Reset All', - + 'approve' => 'Approve', ); diff --git a/app/lang/lt/texts.php b/app/lang/lt/texts.php index 4e673fc5229f..f17166132271 100644 --- a/app/lang/lt/texts.php +++ b/app/lang/lt/texts.php @@ -511,6 +511,7 @@ return array( 'payment_email' => 'Payment Email', 'quote_email' => 'Quote Email', 'reset_all' => 'Reset All', - + 'approve' => 'Approve', + ); diff --git a/app/lang/nb_NO/texts.php b/app/lang/nb_NO/texts.php index 5e19acc1fc06..4874c2066838 100644 --- a/app/lang/nb_NO/texts.php +++ b/app/lang/nb_NO/texts.php @@ -509,7 +509,7 @@ return array( 'payment_email' => 'Payment Email', 'quote_email' => 'Quote Email', 'reset_all' => 'Reset All', - + 'approve' => 'Approve', ); \ No newline at end of file diff --git a/app/lang/nl/texts.php b/app/lang/nl/texts.php index 793566e479a6..1f0dc0922191 100644 --- a/app/lang/nl/texts.php +++ b/app/lang/nl/texts.php @@ -504,7 +504,7 @@ return array( 'payment_email' => 'Payment Email', 'quote_email' => 'Quote Email', 'reset_all' => 'Reset All', - + 'approve' => 'Approve', ); \ No newline at end of file diff --git a/app/lang/pt_BR/texts.php b/app/lang/pt_BR/texts.php index 4673a0d6d111..8cf7074dd189 100644 --- a/app/lang/pt_BR/texts.php +++ b/app/lang/pt_BR/texts.php @@ -491,7 +491,7 @@ return array( 'payment_email' => 'Payment Email', 'quote_email' => 'Quote Email', 'reset_all' => 'Reset All', - + 'approve' => 'Approve', ); diff --git a/app/models/Activity.php b/app/models/Activity.php index 1eca289b0163..fbaac9ac4507 100755 --- a/app/models/Activity.php +++ b/app/models/Activity.php @@ -231,6 +231,19 @@ class Activity extends Eloquent $activity->save(); } + public static function approveQuote($invitation) { + + $activity = Activity::getBlank($invitation); + $activity->client_id = $invitation->invoice->client_id; + $activity->invitation_id = $invitation->id; + $activity->contact_id = $invitation->contact_id; + $activity->invoice_id = $invitation->invoice_id; + $activity->activity_type_id = ACTIVITY_TYPE_APPROVE_QUOTE; + $activity->message = Utils::encodeActivity($invitation->contact, 'approved', $invitation->invoice); + $activity->balance = $invitation->invoice->client->balance; + $activity->save(); + } + public static function createPayment($payment) { $client = $payment->client; diff --git a/app/ninja/repositories/InvoiceRepository.php b/app/ninja/repositories/InvoiceRepository.php index f59044f578b5..c099706fc717 100755 --- a/app/ninja/repositories/InvoiceRepository.php +++ b/app/ninja/repositories/InvoiceRepository.php @@ -80,7 +80,6 @@ class InvoiceRepository $query = \DB::table('invitations') ->join('invoices', 'invoices.id', '=', 'invitations.invoice_id') ->join('clients', 'clients.id', '=', 'invoices.client_id') - //->join('contacts', 'contacts.client_id', '=', 'clients.id') ->where('invitations.contact_id', '=', $contactId) ->where('invitations.deleted_at', '=', null) ->where('invoices.is_quote', '=', $entityType == ENTITY_QUOTE) @@ -99,7 +98,6 @@ class InvoiceRepository } return $table->addColumn('due_date', function ($model) { return Utils::fromSqlDate($model->due_date); }) - //->addColumn('invoice_status_name', function($model) { return $model->invoice_status_name; }) ->make(); } diff --git a/app/routes.php b/app/routes.php index 061320de5d04..5cba05888d37 100755 --- a/app/routes.php +++ b/app/routes.php @@ -46,6 +46,7 @@ Route::post('get_started', 'AccountController@getStarted'); // Client visible pages Route::get('view/{invitation_key}', 'InvoiceController@view'); +Route::get('approve/{invitation_key}', 'QuoteController@approve'); Route::get('payment/{invitation_key}', 'PaymentController@show_payment'); Route::post('payment/{invitation_key}', 'PaymentController@do_payment'); Route::get('complete', 'PaymentController@offsite_payment'); @@ -228,6 +229,7 @@ define("ACTIVITY_TYPE_RESTORE_INVOICE", 25); define("ACTIVITY_TYPE_RESTORE_CLIENT", 26); define("ACTIVITY_TYPE_RESTORE_PAYMENT", 27); define("ACTIVITY_TYPE_RESTORE_CREDIT", 28); +define("ACTIVITY_TYPE_APPROVE_QUOTE", 29); define('DEFAULT_INVOICE_NUMBER', '0001'); define('RECENTLY_VIEWED_LIMIT', 8); diff --git a/app/views/invoices/pdf.blade.php b/app/views/invoices/pdf.blade.php index 22f4ab44f73b..95ac9b26fc85 100644 --- a/app/views/invoices/pdf.blade.php +++ b/app/views/invoices/pdf.blade.php @@ -81,6 +81,7 @@ var needsRefresh = false; function refreshPDF() { + PDFJS.disableWorker = true; if ({{ Auth::check() && Auth::user()->force_pdfjs ? 'false' : 'true' }} && (isFirefox || (isChrome && !isChromium))) { var string = getPDFString(); if (!string) return; diff --git a/app/views/invoices/view.blade.php b/app/views/invoices/view.blade.php index e8337001ccdb..34952176140b 100755 --- a/app/views/invoices/view.blade.php +++ b/app/views/invoices/view.blade.php @@ -22,18 +22,20 @@

 

- - @if ($invoice->client->account->isGatewayConfigured() && !$invoice->isPaid() && !$invoice->is_recurring) -
- {{ Button::normal(trans('texts.download_pdf'), array('onclick' => 'onDownloadClick()', 'class' => 'btn-lg')) }}   - {{ Button::success_link(URL::to('payment/' . $invitation->invitation_key), trans('texts.pay_now'), array('class' => 'btn-lg')) }} -
+
+ @if ($invoice->is_quote) + {{ Button::normal(trans('texts.download_pdf'), array('onclick' => 'onDownloadClick()', 'class' => 'btn-lg')) }}   + @if (!$isConverted) + {{ Button::success_link(URL::to('approve/' . $invitation->invitation_key), trans('texts.approve'), array('class' => 'btn-lg')) }} + @endif + @elseif ($invoice->client->account->isGatewayConfigured() && !$invoice->isPaid() && !$invoice->is_recurring) + {{ Button::normal(trans('texts.download_pdf'), array('onclick' => 'onDownloadClick()', 'class' => 'btn-lg')) }}   + {{ Button::success_link(URL::to('payment/' . $invitation->invitation_key), trans('texts.pay_now'), array('class' => 'btn-lg')) }} @else -
- {{ Button::success('Download PDF', array('onclick' => 'onDownloadClick()', 'class' => 'btn-lg')) }} -
+ {{ Button::success('Download PDF', array('onclick' => 'onDownloadClick()', 'class' => 'btn-lg')) }} @endif - +
+

 

From 897277831a42121fb6b657fd50ff009ce8655372 Mon Sep 17 00:00:00 2001 From: Fabian Marz Date: Wed, 18 Feb 2015 22:28:37 +0100 Subject: [PATCH 07/32] Added translation string and fixed german string --- app/lang/de/texts.php | 265 ++++++++++++++----------------- app/views/clients/show.blade.php | 70 ++++---- 2 files changed, 157 insertions(+), 178 deletions(-) diff --git a/app/lang/de/texts.php b/app/lang/de/texts.php index 1045212e65f9..ff38e939152e 100644 --- a/app/lang/de/texts.php +++ b/app/lang/de/texts.php @@ -1,4 +1,4 @@ - 'Zwischensumme', 'paid_to_date' => 'Bereits gezahlt', 'balance_due' => 'Rechnungsbetrag', - 'invoice_design_id' => 'Vorlage', + 'invoice_design_id' => 'Design', 'terms' => 'Bedingungen', 'your_invoice' => 'Ihre Rechnung', - + 'remove_contact' => 'Kontakt löschen', 'add_contact' => 'Kontakt hinzufügen', 'create_new_client' => 'Einen neuen Kunden erstellen', @@ -72,8 +72,8 @@ return array( 'tax_rates' => 'Steuersätze', 'rate' => 'Satz', 'settings' => 'Einstellungen', - 'enable_invoice_tax' => 'Ermögliche das Bestimmen einer Rechnungssteuer', - 'enable_line_item_tax' => 'Ermögliche das Bestimmen von Steuern für Belegpositionen', + 'enable_invoice_tax' => 'Ermögliche das bestimmen einer Rechnungssteuer', + 'enable_line_item_tax' => 'Ermögliche das bestimmen von Steuern für Belegpositionen', // navigation 'dashboard' => 'Dashboard', @@ -96,13 +96,13 @@ return array( 'import' => 'Importieren', 'download' => 'Downloaden', 'cancel' => 'Abbrechen', - 'provide_email' => 'Bitte gib eine gültige E-Mail Adresse an', + 'provide_email' => 'Bitte gebe eine gültige E-Mail Adresse an', 'powered_by' => 'Powered by', 'no_items' => 'Keine Objekte', // recurring invoices 'recurring_invoices' => 'Wiederkehrende Rechnungen', - 'recurring_help' => '

Sende deinem Kunden wöchentlich, zwei mal im Monat, monatlich, vierteljährlich oder jährlich automatisch die gleiche Rechnung.

+ 'recurring_help' => '

Sende deinen Kunden automatisch die selbe Rechnung wöchentlich, zwei-monatlich, monatlich, vierteljährlich oder jährlich.

Benutze :MONTH, :QUARTER oder :YEAR für ein dynamisches Datum. Grundlegende Mathematik funktioniert genauso gut, zum Beispiel :MONTH-1.

Beispiel zu dynamischen Rechnungs-Variabeln:

    @@ -115,12 +115,12 @@ return array( 'in_total_revenue' => 'Gesamtumsatz', 'billed_client' => 'abgerechneter Kunde', 'billed_clients' => 'abgerechnete Kunden', - 'active_client' => 'aktiver Kunde', - 'active_clients' => 'aktive Kunden', + 'active_client' => 'aktive Kunden', + 'active_clients' => 'aktive Kunden', 'invoices_past_due' => 'Fällige Rechnungen', 'upcoming_invoices' => 'Kommende Rechnungen', 'average_invoice' => 'Durchschnittlicher Rechnungsbetrag', - + // list pages 'archive' => 'archivieren', 'delete' => 'löschen', @@ -159,7 +159,7 @@ return array( 'edit_invoice' => 'Rechnung bearbeiten', // client view page - 'create_invoice' => 'Rechnung bearbeiten', + 'create_invoice' => 'Rechnung erstellen', 'enter_credit' => 'Guthaben eingeben', 'last_logged_in' => 'Zuletzt eingeloggt', 'details' => 'Details', @@ -230,10 +230,10 @@ return array( 'cloned_invoice' => 'Rechnung erfolgreich dupliziert', 'emailed_invoice' => 'Rechnung erfolgreich versendet', 'and_created_client' => 'und Kunde erstellt', - 'archived_invoice' => 'Rechnung erfolgreich archiviert', - 'archived_invoices' => ':count Rechnungen erfolgreich archiviert', - 'deleted_invoice' => 'Rechnung erfolgreich gelöscht', - 'deleted_invoices' => ':count Rechnungen erfolgreich gelöscht', + 'archived_invoice' => 'Guthaben erfolgreich archiviert', + 'archived_invoices' => ':count Guthaben erfolgreich archiviert', + 'deleted_invoice' => 'Guthaben erfolgreich gelöscht', + 'deleted_invoices' => ':count Guthaben erfolgreich gelöscht', 'created_payment' => 'Zahlung erfolgreich erstellt', 'archived_payment' => 'Zahlung erfolgreich archiviert', @@ -249,8 +249,8 @@ return array( 'deleted_credits' => ':count Guthaben erfolgreich gelöscht', // Emails - 'confirmation_subject' => 'Invoice Ninja Kontobestätigung', - 'confirmation_header' => 'Kontobestätigung', + 'confirmation_subject' => 'Invoice Ninja Konto Bestätigung', + 'confirmation_header' => 'Konto Bestätigung', 'confirmation_message' => 'Bitte klicke auf den folgenden Link um dein Konto zu bestätigen.', 'invoice_message' => 'Um Ihre Rechnung über :amount einzusehen, klicken Sie bitte auf den folgenden Link.', 'payment_subject' => 'Zahlungseingang', @@ -266,19 +266,19 @@ return array( 'notification_invoice_paid' => 'Eine Zahlung von :amount wurde von :client bezüglich Rechnung :invoice getätigt.', 'notification_invoice_sent' => 'Dem folgenden Kunden :client wurde die Rechnung :invoice über :amount zugesendet.', 'notification_invoice_viewed' => 'Der folgende Kunde :client hat sich Rechnung :invoice über :amount angesehen.', - 'reset_password' => 'Du kannst dein Passwort zurücksetzen, indem du auf den folgenden Link klickst:', + 'reset_password' => 'Du kannst dein Passwort zurücksetzen indem du auf den folgenden Link klickst:', 'reset_password_footer' => 'Wenn du das Zurücksetzen des Passworts nicht beantragt hast benachrichtige bitte unseren Support: ' . CONTACT_EMAIL, // Payment page 'secure_payment' => 'Sichere Zahlung', 'card_number' => 'Kartennummer', - 'expiration_month' => 'Ablaufmonat', + 'expiration_month' => 'Ablaufmonat', 'expiration_year' => 'Ablaufjahr', 'cvv' => 'Kartenprüfziffer', - + // Security alerts 'confide' => array( - 'too_many_attempts' => 'Zu viele Versuche. Bitte probiere es in ein paar Minuten erneut.', + 'too_many_attempts' => 'Zu viele versuche. Bitte versuche es in ein paar Minuten erneut.', 'wrong_credentials' => 'Falsche E-Mail Adresse oder falsches Passwort.', 'confirmation' => 'Dein Konto wurde bestätigt!', 'wrong_confirmation' => 'Falscher Bestätigungscode.', @@ -289,26 +289,26 @@ return array( // Pro Plan 'pro_plan' => [ - 'remove_logo' => ':link, um das Invoice Ninja Logo zu entfernen, indem du dem Pro Plan beitrittst', + 'remove_logo' => ':link um das Invoice Ninja Logo zu entfernen, indem du dem Pro Plan beitrittst', 'remove_logo_link' => 'Klicke hier', ], - 'logout' => 'Ausloggen', + 'logout' => 'Ausloggen', 'sign_up_to_save' => 'Melde dich an, um deine Arbeit zu speichern', 'agree_to_terms' =>'Ich akzeptiere die Invoice Ninja :terms', 'terms_of_service' => 'Service-Bedingungen', 'email_taken' => 'Diese E-Mail Adresse ist bereits registriert', 'working' => 'Wird bearbeitet', 'success' => 'Erfolg', - 'success_message' => 'Du hast dich erfolgreich registriert. Bitte besuche den Link in deiner Bestätigungsmail um deine E-Mail Adresse zu verifizieren.', - 'erase_data' => 'Diese Aktion wird deine Daten dauerhaft löschen.', + 'success_message' => 'Du hast dich erfolgreich registriert. Bitte besuche den Link in deiner Bestätigungsmail um deine E-Mail Adresse zu verfizieren.', + 'erase_data' => 'Diese Aktion wird deine Daten dauerhaft entfernen.', 'password' => 'Passwort', 'invoice_subject' => 'Neue Rechnung von :account', - 'close' => 'Schließen', + 'close' => 'Schließen', 'pro_plan_product' => 'Pro Plan', 'pro_plan_description' => 'Jahresmitgliedschaft beim Invoice Ninja Pro Plan.', - 'pro_plan_success' => 'Danke für den Beitritt! Sobald die Rechnung bezahlt wurde, beginnt deine Pro Plan Mitgliedschaft.', + 'pro_plan_success' => 'Danke für den Beitritt! Sobald die Rechnung bezahlt wurde beginnt deine Pro Plan Mitgliedschaft.', 'unsaved_changes' => 'Es liegen ungespeicherte Änderungen vor', 'custom_fields' => 'Benutzerdefinierte Felder', @@ -323,7 +323,7 @@ return array( 'product' => 'Produkt', 'products' => 'Produkte', 'fill_products' => 'Produkte automatisch ausfüllen', - 'fill_products_help' => 'Beim Auswählen eines Produktes werden automatisch Beschreibung und Kosten ausgefüllt', + 'fill_products_help' => 'Beim Auswählen eines Produktes werden automatisch eine Beschreibung und die Kosten ausgefüllt', 'update_products' => 'Produkte automatisch aktualisieren', 'update_products_help' => 'Beim Aktualisieren einer Rechnung werden die Produkte automatisch aktualisiert', 'create_product' => 'Produkt erstellen', @@ -332,17 +332,17 @@ return array( 'updated_product' => 'Produkt erfolgreich aktualisiert', 'created_product' => 'Produkt erfolgreich erstellt', 'archived_product' => 'Produkt erfolgreich archiviert', - 'product_library' => 'Produktbibliothek', + 'product_library' => 'Produktbibliothek', 'pro_plan_custom_fields' => ':link to enable custom fields by joining the Pro Plan', - 'advanced_settings' => 'Erweiterte Einstellungen', - 'pro_plan_advanced_settings' => ':link um durch eine Pro-Mitgliedschaft erweiterte Einstellungen zu aktivieren', - 'invoice_design' => 'Rechnungsvorlage', - 'specify_colors' => 'Farben wählen', - 'specify_colors_label' => 'Wähle die in der Rechnung verwendeten Farben', + 'advanced_settings' => 'Advanced Settings', + 'pro_plan_advanced_settings' => ':link to enable the advanced settings by joining the Pro Plan', + 'invoice_design' => 'Invoice Design', + 'specify_colors' => 'Specify colors', + 'specify_colors_label' => 'Select the colors used in the invoice', 'chart_builder' => 'Diagrammersteller', - 'ninja_email_footer' => 'Nutze :site um Kunden Rechnungen zu stellen und online bezahlt zu werden, kostenlos!', + 'ninja_email_footer' => 'Nutze :site um Kunden eine Rechnung zu stellen und online bezahlt zu werden, kostenlos!', 'go_pro' => 'Werde Pro-Mitglied', // Quotes @@ -352,7 +352,7 @@ return array( 'quote_number_short' => 'Angebot #', 'quote_date' => 'Angebotsdatum', 'quote_total' => 'Gesamtanzahl Angebote', - 'your_quote' => 'Ihr Angebot', + 'your_quote' => 'Dein Angebot', 'total' => 'Gesamt', 'clone' => 'Duplizieren', @@ -380,139 +380,114 @@ return array( 'converted_to_invoice' => 'Angebot erfolgreich in Rechnung umgewandelt', 'quote_subject' => 'Neues Angebot von :account', - 'quote_message' => 'Klicken Sie auf den folgenden Link um das Angebot über :amount anzuschauen.', + 'quote_message' => 'Klicke auf den folgenden Link um das Angebot über :amount anzuschauen.', 'quote_link_message' => 'Klicke auf den folgenden Link um das Angebot deines Kunden anzuschauen:', 'notification_quote_sent_subject' => 'Angebot :invoice wurde an :client versendet', 'notification_quote_viewed_subject' => 'Angebot :invoice wurde von :client angeschaut', 'notification_quote_sent' => 'Der folgende Kunde :client erhielt das Angebot :invoice über :amount.', - 'notification_quote_viewed' => 'Der folgende Kunde :client hat sich das Angebot :client über :amount angesehen.', + 'notification_quote_viewed' => 'Der folgende Kunde :client schaute das Angebot :client über :amount an.', 'session_expired' => 'Deine Sitzung ist abgelaufen.', - 'invoice_fields' => 'Rechnungsfelder', - 'invoice_options' => 'Rechnungsoptionen', - 'hide_quantity' => 'Anzahl verbergen', - 'hide_quantity_help' => 'Wenn deine Menge immer 1 beträgt, kannst du deine Rechnung einfach halten, indem du dieses Feld entfernst.', - 'hide_paid_to_date' => 'Bereits gezahlt ausblenden', - 'hide_paid_to_date_help' => '"Bereits gezahlt" nur anzeigen, wenn eine Zahlung eingegangen ist.', + 'invoice_fields' => 'Invoice Fields', + 'invoice_options' => 'Invoice Options', + 'hide_quantity' => 'Hide quantity', + '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' => 'Only display the "Paid to Date" area on your invoices once a payment has been received.', - 'charge_taxes' => 'Steuern erheben', - 'user_management' => 'Benutzerverwaltung', - 'add_user' => 'Benutzer hinzufügen', - 'send_invite' => 'Einladung senden', - 'sent_invite' => 'Einladung erfolgreich gesendet', - 'updated_user' => 'Benutzer erfolgreich aktualisiert', - 'invitation_message' => 'Du wurdest von :invitor eingeladen.', - 'register_to_add_user' => 'Bitte registrieren um einen Benutzer hinzuzufügen', - 'user_state' => 'Status', - 'edit_user' => 'Benutzer bearbeiten', - 'delete_user' => 'Benutzer löschen', - 'active' => 'Aktiv', - 'pending' => 'Ausstehend', - 'deleted_user' => 'Benutzer erfolgreich gelöscht', - 'limit_users' => 'Entschuldige, das würde das Limit von ' . MAX_NUM_USERS . ' Benutzern überschreiten', + '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', - 'confirm_email_invoice' => 'Bist du sicher, dass du diese Rechnung per E-Mail versenden möchtest?', - 'confirm_email_quote' => 'Bist du sicher, dass du dieses Angebot per E-Mail versenden möchtest', - 'confirm_recurring_email_invoice' => 'Wiederkehrende Rechnung ist aktiv. Bis du sicher, dass du diese Rechnung weiterhin als E-Mail verschicken möchtest?', + 'confirm_email_invoice' => 'Are you sure you want to email this invoice?', + 'confirm_email_quote' => 'Are you sure you want to email this quote?', + 'confirm_recurring_email_invoice' => 'Recurring is enabled, are you sure you want this invoice emailed?', - 'cancel_account' => 'Account Kündigen', - 'cancel_account_message' => 'Warnung: Alle Daten werden unwiderruflich und vollständig gelöscht, es gibt kein zurück.', + 'cancel_account' => 'Cancel Account', + 'cancel_account_message' => 'Warning: This will permanently erase all of your data, there is no undo.', 'go_back' => 'Go Back', - 'data_visualizations' => 'Datenvisualisierungen', - 'sample_data' => 'Beispieldaten werden angezeigt', - 'hide' => 'Verbergen', - 'new_version_available' => 'Eine neue Version von :releases_link ist verfügbar. Du benutzt v:user_version, die aktuelle ist v:latest_version', + 'data_visualizations' => 'Data Visualizations', + 'sample_data' => 'Sample data shown', + 'hide' => 'Hide', + 'new_version_available' => 'A new version of :releases_link is available. You\'re running v:user_version, the latest is v:latest_version', - 'invoice_settings' => 'Rechnungseinstellungen', - 'invoice_number_prefix' => 'Präfix für Rechnungsnummer', - 'invoice_number_counter' => 'Zähler für Rechnungsnummer', - 'quote_number_prefix' => 'Präfix für Angebotsnummer', - 'quote_number_counter' => 'Zähler für Angebotsnummer', - 'share_invoice_counter' => 'Zähler der Rechnung teilen', - 'invoice_issued_to' => 'Rechnung ausgestellt für', - 'invalid_counter' => 'Bitte setze, um Probleme zu vermeiden, entweder ein Rechnungs-oder Angebotspräfix.', - 'mark_sent' => 'Als gesendet markieren', + 'invoice_settings' => 'Invoice Settings', + 'invoice_number_prefix' => 'Invoice Number Prefix', + 'invoice_number_counter' => 'Invoice Number Counter', + 'quote_number_prefix' => 'Quote Number Prefix', + 'quote_number_counter' => 'Quote Number Counter', + 'share_invoice_counter' => 'Share invoice counter', + 'invoice_issued_to' => 'Invoice issued to', + 'invalid_counter' => 'To prevent a possible conflict please set either an invoice or quote number prefix', + 'mark_sent' => 'Mark sent', - 'gateway_help_1' => ':link um sich bei Authorize.net anzumelden.', - 'gateway_help_2' => ':link um sich bei Authorize.net anzumelden.', - 'gateway_help_17' => ':link um deine PayPal API-Signatur zu erhalten.', - 'gateway_help_23' => 'Anmerkung: benutze deinen secret API key, nicht deinen publishable API key.', - 'gateway_help_27' => ':link um sich bei TwoCheckout anzumelden.', + 'gateway_help_1' => ':link to sign up for Authorize.net.', + 'gateway_help_2' => ':link to sign up for Authorize.net.', + 'gateway_help_17' => ':link to get your PayPal API signature.', + 'gateway_help_23' => 'Note: use your secret API key, not your publishable API key.', + 'gateway_help_27' => ':link to sign up for TwoCheckout.', - 'more_designs' => 'Weitere Vorlagen', - 'more_designs_title' => 'Zusätzliche Rechnungsvorlagen', - 'more_designs_cloud_header' => 'Werde Pro-Mitglied für zusätzliche Rechnungsvorlagen', + 'more_designs' => 'More designs', + 'more_designs_title' => 'Additional Invoice Designs', + 'more_designs_cloud_header' => 'Go Pro for more invoice designs', 'more_designs_cloud_text' => '', - 'more_designs_self_host_header' => 'Erhalte 6 zusätzliche Rechnungsvorlagen für nur $20', + 'more_designs_self_host_header' => 'Get 6 more invoice designs for just $20', 'more_designs_self_host_text' => '', - 'buy' => 'Kaufen', - 'bought_designs' => 'Die zusätzliche Rechnungsvorlagen wurden erfolgreich hinzugefügt', + 'buy' => 'Buy', + 'bought_designs' => 'Successfully added additional invoice designs', - 'sent' => 'gesendet', + 'sent' => 'sent', 'timesheets' => 'Timesheets', - 'payment_title' => 'Geben Sie Ihre Rechnungsadresse und Ihre Kreditkarteninformationen ein', - 'payment_cvv' => '*Dies ist die 3-4-stellige Nummer auf der Rückseite Ihrer Kreditkarte', - 'payment_footer1' => '*Die Rechnungsadresse muss mit der Adresse der Kreditkarte übereinstimmen.', - 'payment_footer2' => '*Bitte drücken Sie nur einmal auf "Jetzt bezahlen" - die Verarbeitung der Transaktion kann bis zu einer Minute dauern.', - 'vat_number' => 'USt-IdNr.', + 'payment_title' => 'Enter Your Billing Address and Credit Card information', + 'payment_cvv' => '*This is the 3-4 digit number onthe back of your card', + 'payment_footer1' => '*Billing address must match address accociated with credit card.', + 'payment_footer2' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.', + 'vat_number' => 'Vat Number', - 'id_number' => 'ID-Nummer', - 'white_label_link' => 'Branding entfernen', - 'white_label_text' => 'Um das Invoice Ninja Logo auf der Kundenseite zu entfernen, kaufe bitte eine Lizenz für $10.00.', - 'white_label_header' => 'Branding entfernen', - 'bought_white_label' => 'Branding-freie Lizenz erfolgreich aktiviert', - 'white_labeled' => 'Branding entfernt', + 'id_number' => 'ID Number', + 'white_label_link' => 'Click to white label', + 'white_label_text' => 'Purchase a white label license for $10.00 to remove the Invoice Ninja branding from the top of the client pages.', + 'white_label_header' => 'White Label', + 'bought_white_label' => 'Successfully enabled white label license', + 'white_labeled' => 'White labeled', - 'restore' => 'Wiederherstellen', - 'restore_invoice' => 'Rechnung wiederherstellen', - 'restore_quote' => 'Angebot wiederherstellen', - 'restore_client' => 'Kunde wiederherstellen', - 'restore_credit' => 'Guthaben wiederherstellen', - 'restore_payment' => 'Zahlung wiederherstellen', + 'restore' => 'Restore', + 'restore_invoice' => 'Restore Invoice', + 'restore_quote' => 'Restore Quote', + 'restore_client' => 'Restore Client', + 'restore_credit' => 'Restore Credit', + 'restore_payment' => 'Restore Payment', - 'restored_invoice' => 'Rechnung erfolgreich wiederhergestellt', - 'restored_quote' => 'Angebot erfolgreich wiederhergestellt', - 'restored_client' => 'Kunde erfolgreich wiederhergestellt', - 'restored_payment' => 'Zahlung erfolgreich wiederhergestellt', - 'restored_credit' => 'Guthaben erfolgreich wiederhergestellt', - - 'reason_for_canceling' => 'Hilf uns, unser Angebot zu verbessern, indem du uns mitteilst, weswegen du gehst.', - 'discount_percent' => 'Prozent', - 'discount_amount' => 'Wert', + 'restored_invoice' => 'Successfully restored invoice', + 'restored_quote' => 'Successfully restored quote', + 'restored_client' => 'Successfully restored client', + 'restored_payment' => 'Successfully restored payment', + 'restored_credit' => 'Successfully restored credit', - 'invoice_history' => 'Rechnungshistorie', - 'quote_history' => 'Angebotshistorie', - 'current_version' => 'Aktuelle Version', - 'select_versiony' => 'Version auswählen', - 'view_history' => 'Historie anzeigen', + 'reason_for_canceling' => 'Help us improve our site by telling us why you\'re leaving.', + 'discount_percent' => 'Percent', + 'discount_amount' => 'Amount', + + 'invoice_history' => 'Invoice History', + 'quote_history' => 'Quote History', + 'current_version' => 'Current version', + 'select_versiony' => 'Select version', + 'view_history' => 'View History', - 'edit_payment' => 'Zahlung bearbeiten', - 'updated_payment' => 'Zahlung erfolgreich aktualisiert', - 'deleted' => 'Gelöscht', - 'restore_user' => 'Benutzer wiederherstellen', - 'restored_user' => 'Benutzer erfolgreich wiederhergestellt', - 'show_deleted_users' => 'Zeige gelöschte Benutzer', - 'email_templates' => 'E-Mail Vorlagen', - 'invoice_email' => 'Rechnungsmail', - 'payment_email' => 'Zahlungsmail', - 'quote_email' => 'Angebotsmail', - 'reset_all' => 'Alle zurücksetzen', - 'approve' => 'Approve', - 'token_billing_type_id' => 'Token Billing', - 'token_billing_help' => 'Enables you to store credit cards with your gateway, and charge them at a later date.', - 'token_billing_1' => 'Disabled', - 'token_billing_2' => 'Opt-in - checkbox is shown but not selected', - 'token_billing_3' => 'Opt-out - checkbox is shown and selected', - 'token_billing_4' => 'Always', - 'token_billing_checkbox' => 'Store credit card details', - 'view_in_stripe' => 'View in Stripe', - 'use_card_on_file' => 'Use card on file', - 'edit_payment_details' => 'Edit payment details', - 'token_billing' => 'Save card details', - 'token_billing_secure' => 'The data is stored securely by :stripe_link', - ); diff --git a/app/views/clients/show.blade.php b/app/views/clients/show.blade.php index 2b3661162460..1f8c4aef1709 100755 --- a/app/views/clients/show.blade.php +++ b/app/views/clients/show.blade.php @@ -1,8 +1,8 @@ @extends('header') -@section('content') - - +@section('content') + +
    {{ Former::open('clients/bulk')->addClass('mainForm') }}
    @@ -10,11 +10,15 @@ {{ Former::text('id')->value($client->public_id) }}
    +<<<<<<< HEAD @if ($gatewayLink) {{ Button::link($gatewayLink, trans('texts.view_in_stripe'), ['target' => '_blank']) }} @endif @if ($client->trashed()) +======= + @if ($client->trashed()) +>>>>>>> Added translation string and fixed german string {{ Button::primary(trans('texts.restore_client'), ['onclick' => 'onRestoreClick()']) }} @else {{ DropdownButton::normal(trans('texts.edit_client'), @@ -28,16 +32,16 @@ ) , ['id'=>'normalDropDown'])->split(); }} - {{ DropdownButton::primary('Create Invoice', Navigation::links($actionLinks), ['id'=>'primaryDropDown'])->split(); }} + {{ DropdownButton::primary(trans('texts.create_invoice'), Navigation::links($actionLinks), ['id'=>'primaryDropDown'])->split(); }} @endif - {{ Former::close() }} + {{ Former::close() }}
    - +

    {{ $client->getDisplayName() }}

    @if ($client->last_login > 0) -

    +

    {{ trans('texts.last_logged_in') }} {{ Utils::timestampToDateTimeString(strtotime($client->last_login)); }}

    @endif @@ -59,9 +63,9 @@

    {{ trans('texts.contacts') }}

    - @foreach ($client->contacts as $contact) - {{ $contact->getDetails() }} - @endforeach + @foreach ($client->contacts as $contact) + {{ $contact->getDetails() }} + @endforeach
    @@ -88,28 +92,28 @@

     

    - +
    - {{ Datatable::table() + {{ Datatable::table() ->addColumn( trans('texts.date'), trans('texts.message'), trans('texts.balance'), trans('texts.adjustment')) - ->setUrl(url('api/activities/'. $client->public_id)) + ->setUrl(url('api/activities/'. $client->public_id)) ->setOptions('sPaginationType', 'bootstrap') ->setOptions('bFilter', false) ->setOptions('aaSorting', [['0', 'desc']]) @@ -120,14 +124,14 @@ @if (Utils::isPro())
    - {{ Datatable::table() + {{ Datatable::table() ->addColumn( trans('texts.quote_number'), trans('texts.quote_date'), trans('texts.total'), trans('texts.due_date'), trans('texts.status')) - ->setUrl(url('api/quotes/'. $client->public_id)) + ->setUrl(url('api/quotes/'. $client->public_id)) ->setOptions('sPaginationType', 'bootstrap') ->setOptions('bFilter', false) ->setOptions('aaSorting', [['0', 'desc']]) @@ -139,20 +143,20 @@
    @if ($hasRecurringInvoices) - {{ Datatable::table() + {{ Datatable::table() ->addColumn( trans('texts.frequency_id'), trans('texts.start_date'), trans('texts.end_date'), - trans('texts.invoice_total')) - ->setUrl(url('api/recurring_invoices/' . $client->public_id)) + trans('texts.invoice_total')) + ->setUrl(url('api/recurring_invoices/' . $client->public_id)) ->setOptions('sPaginationType', 'bootstrap') ->setOptions('bFilter', false) ->setOptions('aaSorting', [['0', 'asc']]) ->render('datatable') }} @endif - {{ Datatable::table() + {{ Datatable::table() ->addColumn( trans('texts.invoice_number'), trans('texts.invoice_date'), @@ -160,46 +164,46 @@ trans('texts.balance_due'), trans('texts.due_date'), trans('texts.status')) - ->setUrl(url('api/invoices/' . $client->public_id)) + ->setUrl(url('api/invoices/' . $client->public_id)) ->setOptions('sPaginationType', 'bootstrap') ->setOptions('bFilter', false) ->setOptions('aaSorting', [['0', 'asc']]) ->render('datatable') }} - +
    - {{ Datatable::table() + {{ Datatable::table() ->addColumn( trans('texts.invoice'), - trans('texts.transaction_reference'), - trans('texts.method'), + trans('texts.transaction_reference'), + trans('texts.method'), trans('texts.payment_amount'), trans('texts.payment_date')) - ->setUrl(url('api/payments/' . $client->public_id)) + ->setUrl(url('api/payments/' . $client->public_id)) ->setOptions('sPaginationType', 'bootstrap') ->setOptions('bFilter', false) ->setOptions('aaSorting', [['0', 'asc']]) ->render('datatable') }} - +
    - {{ Datatable::table() + {{ Datatable::table() ->addColumn( trans('texts.credit_amount'), trans('texts.credit_balance'), trans('texts.credit_date'), trans('texts.private_notes')) - ->setUrl(url('api/credits/' . $client->public_id)) + ->setUrl(url('api/credits/' . $client->public_id)) ->setOptions('sPaginationType', 'bootstrap') ->setOptions('bFilter', false) ->setOptions('aaSorting', [['0', 'asc']]) ->render('datatable') }} - +
    - + From 53111d75848f6d0711fb615759c9e7a4b70588f3 Mon Sep 17 00:00:00 2001 From: Fabian Marz Date: Wed, 18 Feb 2015 22:59:46 +0100 Subject: [PATCH 08/32] Merge conflict --- app/views/clients/show.blade.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/views/clients/show.blade.php b/app/views/clients/show.blade.php index 1f8c4aef1709..00fa2f8e6255 100755 --- a/app/views/clients/show.blade.php +++ b/app/views/clients/show.blade.php @@ -10,15 +10,12 @@ {{ Former::text('id')->value($client->public_id) }}
    -<<<<<<< HEAD @if ($gatewayLink) {{ Button::link($gatewayLink, trans('texts.view_in_stripe'), ['target' => '_blank']) }} @endif - @if ($client->trashed()) -======= @if ($client->trashed()) ->>>>>>> Added translation string and fixed german string + @if ($client->trashed()) {{ Button::primary(trans('texts.restore_client'), ['onclick' => 'onRestoreClick()']) }} @else {{ DropdownButton::normal(trans('texts.edit_client'), From b55678b0ba589aea7fcd1e3de44bc0f5890847ce Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Thu, 19 Feb 2015 00:34:36 +0200 Subject: [PATCH 09/32] Restyled client pages --- Gruntfile.js | 6 + app/controllers/HomeController.php | 95 +- app/controllers/InvoiceController.php | 2 - app/controllers/PaymentController.php | 3 +- app/controllers/QuoteController.php | 1 - app/lang/en/texts.php | 12 +- app/routes.php | 12 +- app/views/invoices/view.blade.php | 2 - app/views/master.blade.php | 152 +-- app/views/payments/payment.blade.php | 463 ++++---- app/views/public/about_us.blade.php | 90 -- app/views/public/compare.blade.php | 320 ------ app/views/public/contact_us.blade.php | 124 -- app/views/public/faq.blade.php | 149 --- app/views/public/features.blade.php | 119 -- app/views/public/header.blade.php | 691 ++++------- app/views/public/plans.blade.php | 46 - app/views/public/splash.blade.php | 239 ---- app/views/public/terms.blade.php | 29 +- app/views/public/testimonials.blade.php | 45 - app/views/public_list.blade.php | 36 +- public/built.js | 2 +- public/built.public.css | 1389 ----------------------- public/images/icon-shield.png | Bin 0 -> 2017 bytes public/images/social/facebook.png | Bin 0 -> 229 bytes public/images/social/facebook.svg | 6 + public/images/social/github.png | Bin 0 -> 457 bytes public/images/social/twitter.png | Bin 0 -> 307 bytes public/images/social/twitter.svg | 6 + public/js/built.public.js | 22 +- public/js/script.js | 5 - 31 files changed, 629 insertions(+), 3437 deletions(-) delete mode 100644 app/views/public/about_us.blade.php delete mode 100644 app/views/public/compare.blade.php delete mode 100644 app/views/public/contact_us.blade.php delete mode 100644 app/views/public/faq.blade.php delete mode 100644 app/views/public/features.blade.php delete mode 100644 app/views/public/plans.blade.php delete mode 100755 app/views/public/splash.blade.php delete mode 100644 app/views/public/testimonials.blade.php create mode 100644 public/images/icon-shield.png create mode 100644 public/images/social/facebook.png create mode 100644 public/images/social/facebook.svg create mode 100644 public/images/social/github.png create mode 100644 public/images/social/twitter.png create mode 100644 public/images/social/twitter.svg diff --git a/Gruntfile.js b/Gruntfile.js index 2eedc311faa2..9213e01d255a 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -66,10 +66,14 @@ module.exports = function(grunt) { }, js_public: { src: [ + /* 'public/js/simpleexpand.js', 'public/js/valign.js', 'public/js/bootstrap.min.js', 'public/js/simpleexpand.js', + */ + 'public/vendor/bootstrap/dist/js/bootstrap.min.js', + ], dest: 'public/js/built.public.js', nonull: true @@ -97,8 +101,10 @@ module.exports = function(grunt) { css_public: { src: [ 'public/vendor/bootstrap/dist/css/bootstrap.min.css', + /* 'public/css/bootstrap.splash.css', 'public/css/splash.css', + */ 'public/vendor/datatables/media/css/jquery.dataTables.css', 'public/vendor/datatables-bootstrap3/BS3/assets/css/datatables.css', ], diff --git a/app/controllers/HomeController.php b/app/controllers/HomeController.php index 419aeb41d8b7..27e8a9983fd7 100755 --- a/app/controllers/HomeController.php +++ b/app/controllers/HomeController.php @@ -15,101 +15,20 @@ class HomeController extends BaseController public function showIndex() { - if (Utils::isNinja()) { - return View::make('public.splash'); + if (!Utils::isDatabaseSetup()) { + return Redirect::to('/setup'); + } elseif (Account::count() == 0) { + return Redirect::to('/invoice_now'); } else { - if (!Utils::isDatabaseSetup()) { - return Redirect::to('/setup'); - } elseif (Account::count() == 0) { - return Redirect::to('/invoice_now'); - } else { - return Redirect::to('/login'); - } + return Redirect::to('/login'); } } - public function showAboutUs() - { - $data = [ - 'title' => 'About Us', - 'description' => 'Invoice Ninja is an an open-source solution where you can create, customize, and generate invoices online for free using our templates!', - ]; - - return View::make('public.about_us', $data); - } - - public function showContactUs() - { - $data = [ - 'title' => 'Contact Us', - 'description' => 'Contact us today and try out our free or premium hassle-free plans. Start your online invoicing today with Invoice Ninja!', - ]; - - return View::make('public.contact_us', $data); - } - public function showTerms() { - return View::make('public.terms'); + return View::make('public.terms', ['hideHeader' => true]); } - - public function showFaq() - { - return View::make('public.faq'); - } - - public function showFeatures() - { - return View::make('public.features'); - } - - public function showPlans() - { - $data = [ - 'title' => 'Professional Invoicing Software & Templates', - 'description' => 'Invoice Ninja allows you to create and generate your own custom invoices. Choose from our professional invoice templates or customize your own with our pro plan.', - ]; - - return View::make('public.plans', $data); - } - public function showTestimonials() - { - return View::make('public.testimonials'); - } - - public function doContactUs() - { - $email = Input::get('email'); - $name = Input::get('name'); - $message = Input::get('message'); - - $data = [ - 'text' => $message, - ]; - - $this->mailer->sendTo(CONTACT_EMAIL, $email, $name, 'Invoice Ninja Feedback', 'contact', $data); - - $message = trans('texts.sent_message'); - Session::flash('message', $message); - - return View::make('public.contact_us'); - } - - public function showComingSoon() - { - return View::make('coming_soon'); - } - - public function showSecurePayment() - { - return View::make('secure_payment'); - } - - public function showCompare() - { - return View::make('public.compare'); - } - + public function invoiceNow() { if (Auth::check()) { diff --git a/app/controllers/InvoiceController.php b/app/controllers/InvoiceController.php index 884e26efd819..6c5b589e6e5d 100755 --- a/app/controllers/InvoiceController.php +++ b/app/controllers/InvoiceController.php @@ -47,7 +47,6 @@ class InvoiceController extends \BaseController public function clientIndex() { $data = [ - 'showClientHeader' => true, 'hideLogo' => Session::get('white_label'), 'title' => trans('texts.invoices'), 'entityType' => ENTITY_INVOICE, @@ -170,7 +169,6 @@ class InvoiceController extends \BaseController $data = array( 'isConverted' => $invoice->quote_invoice_id ? true : false, - 'showClientHeader' => true, 'showBreadcrumbs' => false, 'hideLogo' => $client->account->isWhiteLabel(), 'invoice' => $invoice->hidePrivateFields(), diff --git a/app/controllers/PaymentController.php b/app/controllers/PaymentController.php index ff4668c0b490..bfbf7c1c2dce 100755 --- a/app/controllers/PaymentController.php +++ b/app/controllers/PaymentController.php @@ -31,7 +31,6 @@ class PaymentController extends \BaseController public function clientIndex() { return View::make('public_list', array( - 'showClientHeader' => true, 'hideLogo' => Session::get('white_label'), 'entityType' => ENTITY_PAYMENT, 'title' => trans('texts.payments'), @@ -313,9 +312,9 @@ class PaymentController extends \BaseController $data = [ 'showBreadcrumbs' => false, - 'hideHeader' => true, 'url' => 'payment/'.$invitationKey, 'amount' => $invoice->amount, + 'invoiceNumber' => $invoice->invoice_number, 'client' => $client, 'contact' => $invitation->contact, 'paymentLibrary' => $paymentLibrary, diff --git a/app/controllers/QuoteController.php b/app/controllers/QuoteController.php index 7753d63fa51f..b060dec80a5f 100644 --- a/app/controllers/QuoteController.php +++ b/app/controllers/QuoteController.php @@ -48,7 +48,6 @@ class QuoteController extends \BaseController public function clientIndex() { $data = [ - 'showClientHeader' => true, 'hideLogo' => Session::get('white_label'), 'title' => trans('texts.quotes'), 'entityType' => ENTITY_QUOTE, diff --git a/app/lang/en/texts.php b/app/lang/en/texts.php index 5b681bae62fe..99d84e7d387b 100644 --- a/app/lang/en/texts.php +++ b/app/lang/en/texts.php @@ -522,6 +522,16 @@ return array( 'edit_payment_details' => 'Edit payment details', 'token_billing' => 'Save card details', 'token_billing_secure' => 'The data is stored securely by :stripe_link', - + + 'support' => 'Support', + 'contact_information' => 'Contact information', + '256_encryption' => '256-Bit Encryption', + 'amount_due' => 'Amount due', + 'billing_address' => 'Billing address', + 'billing_method' => 'Billing method', + 'order_overview' => 'Order overview', + 'match_address' => '*Address must match address accociated with credit card.', + 'click_once' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.', + ); diff --git a/app/routes.php b/app/routes.php index 49ecd9baa1f9..d21b545686a2 100755 --- a/app/routes.php +++ b/app/routes.php @@ -29,17 +29,7 @@ Route::get('update', 'AppController@update'); // Public pages Route::get('/', 'HomeController@showIndex'); -Route::get('/rocksteady', 'HomeController@showIndex'); -Route::get('/about', 'HomeController@showAboutUs'); -Route::get('/terms', 'HomeController@showTerms'); -Route::get('/contact', 'HomeController@showContactUs'); -Route::get('/plans', 'HomeController@showPlans'); -Route::post('/contact_submit', 'HomeController@doContactUs'); -Route::get('/faq', 'HomeController@showFaq'); -Route::get('/features', 'HomeController@showFeatures'); -Route::get('/testimonials', 'HomeController@showTestimonials'); -Route::get('/compare-online-invoicing{sites?}', 'HomeController@showCompare'); - +Route::get('terms', 'HomeController@showTerms'); Route::get('log_error', 'HomeController@logError'); Route::get('invoice_now', 'HomeController@invoiceNow'); Route::post('get_started', 'AccountController@getStarted'); diff --git a/app/views/invoices/view.blade.php b/app/views/invoices/view.blade.php index b3157ed0333e..c667c74e92f9 100755 --- a/app/views/invoices/view.blade.php +++ b/app/views/invoices/view.blade.php @@ -5,8 +5,6 @@ @include('script') - - diff --git a/app/views/master.blade.php b/app/views/master.blade.php index 1d8d04dcf175..d174c873917f 100755 --- a/app/views/master.blade.php +++ b/app/views/master.blade.php @@ -1,6 +1,6 @@ - + Invoice Ninja | {{ isset($title) ? $title : ' ' . trans('public.title') }} @@ -22,112 +22,118 @@ - + - - @yield('head') - +@yield('head') - + + + @if (isset($_ENV['TAG_MANAGER_KEY']) && $_ENV['TAG_MANAGER_KEY']) - - - - + + + + - + url = '/track' + url.replace('http:/', ''); + dataLayer.push({'event':url, 'eventLabel':this.src}); + } + @elseif (isset($_ENV['ANALYTICS_KEY']) && $_ENV['ANALYTICS_KEY']) - + @else - + @endif - @yield('body') +@yield('body') - + }); + function openUrl(url, track) { + trackUrl(track ? track : url); + window.open(url, '_blank'); + } - + +//$('a[rel!=ext]').click(function() { $(window).off('beforeunload') }); + + + \ No newline at end of file diff --git a/app/views/payments/payment.blade.php b/app/views/payments/payment.blade.php index bee50f514cd5..dfddfbc4717e 100755 --- a/app/views/payments/payment.blade.php +++ b/app/views/payments/payment.blade.php @@ -3,20 +3,117 @@ @section('content') @@ -42,18 +139,156 @@ {{ Former::populateField('last_name', $contact->last_name) }} @endif -
    -
    -
    -

    Secure Payment

    -

    256-BiT Encryption

    - -
    -
    -
    +
    +

     

    -
    -
    +
    +
    + +
    +
    +
    +

    {{ $client->getDisplayName() }}

    +

    {{ trans('texts.invoice') . ' ' . $invoiceNumber }}|  {{ trans('texts.amount_due') }}: {{ Utils::formatMoney($amount, $currencyId) }}

    +
    +
    +
    +
    +

    {{ trans('texts.secure_payment') }}

    +
    {{ trans('texts.256_encryption') }}
    +
    +
    +
    + +

     
     

    + +
    +

    {{ trans('texts.contact_information') }}

    +
    +
    + {{ Former::text('first_name')->placeholder(trans('texts.first_name'))->raw() }} +
    +
    + {{ Former::text('last_name')->placeholder(trans('texts.last_name'))->raw() }} +
    +
    + @if (isset($paymentTitle)) +
    +
    + {{ Former::text('email')->placeholder(trans('texts.email'))->raw() }} +
    +
    + @endif + +

     
     

    + +

    {{ trans('texts.billing_address') }}

    +
    +
    + {{ Former::text('address1')->placeholder(trans('texts.address1'))->raw() }} +
    +
    +
    +
    + {{ Former::text('address2')->placeholder(trans('texts.address2'))->raw() }} +
    +
    + {{ Former::text('city')->placeholder(trans('texts.city'))->raw() }} +
    +
    +
    +
    + {{ Former::text('state')->placeholder(trans('texts.state'))->raw() }} +
    +
    + {{ Former::text('postal_code')->placeholder(trans('texts.postal_code'))->raw() }} +
    +
    + +

     
     

    + +

    {{ trans('texts.billing_method') }}  {{ trans('texts.match_address') }}

    +
    +
    + {{ Former::text('card_number')->placeholder(trans('texts.card_number'))->raw() }} +
    +
    +
    +
    + {{ Former::select('expiration_month')->placeholder(trans('texts.expiration_month')) + ->addOption('01 - January', '1') + ->addOption('02 - February', '2') + ->addOption('03 - March', '3') + ->addOption('04 - April', '4') + ->addOption('05 - May', '5') + ->addOption('06 - June', '6') + ->addOption('07 - July', '7') + ->addOption('08 - August', '8') + ->addOption('09 - September', '9') + ->addOption('10 - October', '10') + ->addOption('11 - November', '11') + ->addOption('12 - December', '12')->raw(); + }} +
    +
    + {{ Former::select('expiration_year')->placeholder(trans('texts.expiration_year')) + ->addOption('2014', '2014') + ->addOption('2015', '2015') + ->addOption('2016', '2016') + ->addOption('2017', '2017') + ->addOption('2018', '2018') + ->addOption('2019', '2019') + ->addOption('2020', '2020')->raw(); + }} +
    +
    + {{ Former::text('cvv')->placeholder(trans('texts.cvv'))->raw() }} +
    +
    + + +
    +
    + @if ($account->showTokenCheckbox()) + selectTokenCheckbox() ? 'CHECKED' : '' }} value="1" style="margin-left:0px; vertical-align:text-top"> + + {{ trans('texts.token_billing_secure', ['stripe_link' => link_to('https://stripe.com/', 'Stripe.com', ['target' => '_blank'])]) }} + @endif +
    + +
    + @if (isset($acceptedCreditCardTypes)) +
    + @foreach ($acceptedCreditCardTypes as $card) + {{ $card['alt'] }} + @endforeach +
    + @endif +
    +
    + + +

     
     

    + +
    +
    + {{ Button::block_success_submit_lg(strtoupper(trans('texts.pay_now') . ' - ' . Utils::formatMoney($amount, $currencyId) )) }} +
    +
    + + +
    + +
    +
    + + +

     

    +

     

    + +
    + + -
    -
    -
    -
    -
    - {{ Former::text('card_number') }} - -
    -
    -
    -
    - {{ Former::select('expiration_month')->addOption('','') - ->addOption('01 - January', '1') - ->addOption('02 - February', '2') - ->addOption('03 - March', '3') - ->addOption('04 - April', '4') - ->addOption('05 - May', '5') - ->addOption('06 - June', '6') - ->addOption('07 - July', '7') - ->addOption('08 - August', '8') - ->addOption('09 - September', '9') - ->addOption('10 - October', '10') - ->addOption('11 - November', '11') - ->addOption('12 - December', '12') - }} - -
    -
    - {{ Former::select('expiration_year')->addOption('','') - ->addOption('2014', '2014') - ->addOption('2015', '2015') - ->addOption('2016', '2016') - ->addOption('2017', '2017') - ->addOption('2018', '2018') - ->addOption('2019', '2019') - ->addOption('2020', '2020') - }} - -
    -
    - - -
    -
    - {{ Former::text('cvv') }} -
    -
    -
    {{ otrans('texts.payment_cvv') }}
    -
    -
    - -
    -
    - - @if ($account->showTokenCheckbox()) -
    - selectTokenCheckbox() ? 'CHECKED' : '' }} value="1" style="margin-left:0px; vertical-align:text-top"> - - {{ trans('texts.token_billing_secure', ['stripe_link' => link_to('https://stripe.com/', 'Stripe.com', ['target' => '_blank'])]) }} -
    - @endif - - @if (isset($acceptedCreditCardTypes)) -
    -
    - @foreach ($acceptedCreditCardTypes as $card) - {{ $card['alt'] }} - @endforeach -
    -
    - @endif - -
    - -
    -
    -

-
-
- {{ Button::block_primary_submit_lg(strtoupper(trans('texts.pay_now')) . ' - ' . Utils::formatMoney($amount, $currencyId) ) }} -
-
-
-
-

 

- Click here to view our terms of service. -
-
- - - - - - - - +--> {{ Former::close() }} diff --git a/app/views/public/about_us.blade.php b/app/views/public/about_us.blade.php deleted file mode 100644 index 305e781fb829..000000000000 --- a/app/views/public/about_us.blade.php +++ /dev/null @@ -1,90 +0,0 @@ -@extends('public.header') - -@section('content') -
-
-
-

{{ trans('public.about.header') }}

-
-
-
- -
-
-
-
-
-

{{ trans('public.about.what_is') }}

-
-

{{ trans('public.description') }}

-
-
- -
-
-
-
- -
-
-
-
-

{{ trans('public.about.team_ninja') }}

-

{{ trans('public.about.team_ninja_text') }}

-
-
-
-
-
- Shalom Stark -
-

Shalom Stark

-

{{ trans('public.about.co_founder') }}, {{ trans('public.about.ceo') }}

- -

{{ trans('public.about.shalom_bio') }}

-
-
-
- Hillel Coren -
-

Hillel Coren

-

{{ trans('public.about.co_founder') }}, {{ trans('public.about.cto') }}

- -

{{ trans('public.about.hillel_bio') }}

-
-
-
- Razi Kantorp -
-

Razi Kantorp-Weglin

-

{{ trans('public.about.designer') }}

- -

{{ trans('public.about.razi_bio') }}

-
-
-
- Ben Jacobsen -
-

Ben Jacobson

-

{{ trans('public.about.marketing') }}

- -

{{ trans('public.about.ben_bio') }}

-
-
-
-
- -@stop \ No newline at end of file diff --git a/app/views/public/compare.blade.php b/app/views/public/compare.blade.php deleted file mode 100644 index d163d62e5f9b..000000000000 --- a/app/views/public/compare.blade.php +++ /dev/null @@ -1,320 +0,0 @@ -@extends('public.header') - -@section('content') - -
-
-
-

{{ trans('public.compare.header') }}

-
-
-
- -
-
-
-
-

{{ trans('public.compare.free_plan_comparison') }}

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{{ trans('public.compare.app') }}{{ trans('public.compare.cost') }}{{ trans('public.compare.clients') }}{{ trans('public.compare.invoices') }}{{ trans('public.compare.payment_gateways') }}{{ trans('public.compare.custom_logo') }}{{ trans('public.compare.multiple_templates') }}{{ trans('public.compare.recurring_payments') }}{{ trans('public.compare.open_source') }}
Invoice Ninja{{ trans('public.compare.free') }}500{{ trans('public.compare.unlimited') }}23
FreshBooks{{ trans('public.compare.free') }}3{{ trans('public.compare.unlimited') }}13
Wave{{ trans('public.compare.free') }}{{ trans('public.compare.unlimited') }}{{ trans('public.compare.unlimited') }}1
NutCache{{ trans('public.compare.free') }}{{ trans('public.compare.unlimited') }}{{ trans('public.compare.unlimited') }}3
CurdBee{{ trans('public.compare.free') }}{{ trans('public.compare.unlimited') }}{{ trans('public.compare.unlimited') }}3
Zoho Invoice{{ trans('public.compare.free') }}5{{ trans('public.compare.unlimited') }}6
Ronin{{ trans('public.compare.free') }}2{{ trans('public.compare.unlimited') }}1
Invoiceable{{ trans('public.compare.free') }}{{ trans('public.compare.unlimited') }}{{ trans('public.compare.unlimited') }}1
Harvest{{ trans('public.compare.free') }}4{{ trans('public.compare.unlimited') }}4
InvoiceOcean{{ trans('public.compare.free') }}{{ trans('public.compare.unlimited') }}31
- -

 

-

 

- -

{{ trans('public.compare.paid_plan_comparison') }}

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{{ trans('public.compare.app') }}{{ trans('public.compare.cost') }}{{ trans('public.compare.clients') }}{{ trans('public.compare.invoices') }}{{ trans('public.compare.payment_gateways') }}{{ trans('public.compare.custom_logo') }}{{ trans('public.compare.multiple_templates') }}{{ trans('public.compare.recurring_payments') }}{{ trans('public.compare.open_source') }}
Invoice Ninja$50 {{ trans('public.compare.per_year') }}{{ trans('public.compare.unlimited') }}{{ trans('public.compare.unlimited') }}23
FreeAgent$20 {{ trans('public.compare.per_month') }}{{ trans('public.compare.unlimited') }}{{ trans('public.compare.unlimited') }}3
Xero$20 {{ trans('public.compare.per_month') }}{{ trans('public.compare.unlimited') }}58
Invoice2go$49 {{ trans('public.compare.per_year') }}501001
Invoice Machine$12 {{ trans('public.compare.per_month') }}{{ trans('public.compare.unlimited') }}302
FreshBooks$20 {{ trans('public.compare.per_month') }}25{{ trans('public.compare.unlimited') }}13
CurdBee$50 {{ trans('public.compare.per_year') }}{{ trans('public.compare.unlimited') }}{{ trans('public.compare.unlimited') }}3
Zoho Invoice$15 {{ trans('public.compare.per_month') }}500{{ trans('public.compare.unlimited') }}6
Ronin$29 {{ trans('public.compare.per_month') }}{{ trans('public.compare.unlimited') }}{{ trans('public.compare.unlimited') }}2
Harvest$12 {{ trans('public.compare.per_month') }}{{ trans('public.compare.unlimited') }}{{ trans('public.compare.unlimited') }}4
Invoice Ocean$9 {{ trans('public.compare.per_month') }}{{ trans('public.compare.unlimited') }}{{ trans('public.compare.unlimited') }}1
Apptivo$10 {{ trans('public.compare.per_month') }}{{ trans('public.compare.unlimited') }}{{ trans('public.compare.unlimited') }}3
-
-
-
-
- - - - - -@stop \ No newline at end of file diff --git a/app/views/public/contact_us.blade.php b/app/views/public/contact_us.blade.php deleted file mode 100644 index d413e604ea55..000000000000 --- a/app/views/public/contact_us.blade.php +++ /dev/null @@ -1,124 +0,0 @@ -@extends('public.header') - - -@section('content') - - - -
-
-
-

Contact us

-
-
-
- -
-
-
- -
-
-
-

{{ trans('public.contact.header') }}

-

{{ trans('public.contact.sub_header') }}

-
- {{ Form::open(['url' => 'contact_submit', 'class' => 'feedbackForm']) }} -
- - -
-
- - -
-
- - -
-
-
- -
-
- - {{ Form::close() }} - -
-
-

{{ trans('public.contact.other_ways') }}

-

contact@invoiceninja.com

-

Google Group

-

QGitHub Project

- -
-
-
- - -
- - - - -@stop \ No newline at end of file diff --git a/app/views/public/faq.blade.php b/app/views/public/faq.blade.php deleted file mode 100644 index 80145f49ff86..000000000000 --- a/app/views/public/faq.blade.php +++ /dev/null @@ -1,149 +0,0 @@ -@extends('public.header') - -@section('content') - -
-
-
-

{{ trans('public.faq.header') }}

-
-
-
- -
-
-
-
-
- {{ trans('public.faq.question1') }} - -
-

{{ trans('public.faq.answer1') }}

-
-
-
- {{ trans('public.faq.question2') }} - -
-

{{ trans('public.faq.answer2') }} -

-
-
-
- {{ trans('public.faq.question3') }} - -
-

{{ trans('public.faq.answer3') }} -

-
-
-
- {{ trans('public.faq.question4') }} - -
-

{{ trans('public.faq.answer4') }} -

-
-
-
- {{ trans('public.faq.question5') }} - -
-

{{ trans('public.faq.answer5') }}

-
-
-
- {{ trans('public.faq.question6') }} - -
-

{{ trans('public.faq.answer6') }} -

-
-
-
- {{ trans('public.faq.question7') }} - -
-

{{ trans('public.faq.answer7') }} -

-
-
-
- {{ trans('public.faq.question8') }} - -
-

{{ trans('public.faq.answer8') }} -

-
-
-
- {{ trans('public.faq.question9') }} - -
-

{{ trans('public.faq.answer9') }} -

-
-
-
- {{ trans('public.faq.question10') }} - -
-

{{ trans('public.faq.answer10') }} -

-
-
- @if (Utils::getDemoAccountId()) -
- {{ trans('public.faq.question11') }} -
-

{{ trans('public.faq.answer11') }} -

-
-
- @endif -
- {{ trans('public.faq.question12') }} - -
-

{{ trans('public.faq.answer12') }} -

-
-
-
- {{ trans('public.faq.question13') }} - -
-

{{ trans('public.faq.answer13') }} -

-
-
-
- {{ trans('public.faq.question14') }} - -
-

{{ trans('public.faq.answer14') }} -

-
-
-
-
-
-
-
-
-
- -

{{ trans('public.faq.miss_something') }}

-
-
-

{{ trans('public.faq.miss_something_text') }} -

-
-
-
-
-
-
-
- -@stop \ No newline at end of file diff --git a/app/views/public/features.blade.php b/app/views/public/features.blade.php deleted file mode 100644 index 34419f6857ad..000000000000 --- a/app/views/public/features.blade.php +++ /dev/null @@ -1,119 +0,0 @@ -@extends('public.header') - -@section('content') -
-
-
-

{{ trans('public.features.header') }}

-
-
-
- -
-
-
-
- -
-

{{ trans('public.features.open_source') }}

-
-

{{ trans('public.features.open_source_text1') }}

-

{{ trans('public.features.open_source_text2') }}

-
-
- -
-
-
-
- -
-
-
- -
- -
-
- -
-

{{ trans('public.features.free_forever') }}

-
-

{{ trans('public.features.free_forever_text1') }}

-

{{ trans('public.features.free_forever_text2') }}

-
- -
-
-
-
-
-
-
- -
-

{{ trans('public.features.secure') }}

-
-

{{ trans('public.features.secure_text1') }}

-

{{ trans('public.features.secure_text2') }}

- -
-
- -
-
-
-
-
-
-
-
- -
-
-
-

{{ trans('public.features.live_pdf') }}

-
-

{{ trans('public.features.live_pdf_text1') }}

-

{{ trans('public.features.live_pdf_text2') }}

-

{{ trans('public.features.live_pdf_text3') }}

- -
-
-
-
-
-
-
-
-
-

{{ trans('public.features.online_payments') }}

-
-

{{ trans('public.features.online_payments_text1') }}

-

{{ trans('public.features.online_payments_text2') }}

-
-
- -
-
-
-
- - - -@stop diff --git a/app/views/public/header.blade.php b/app/views/public/header.blade.php index 225f420bc2fa..efbd742ef540 100644 --- a/app/views/public/header.blade.php +++ b/app/views/public/header.blade.php @@ -1,36 +1,106 @@ @extends('master') -@section('head') +@section('head') - + @@ -55,465 +125,154 @@ {{ Form::close() }} -@if ((!isset($hideHeader) || !$hideHeader) && (!isset($showClientHeader) || !$showClientHeader)) - - - - - - - - -@stop \ No newline at end of file diff --git a/app/views/public/splash.blade.php b/app/views/public/splash.blade.php deleted file mode 100755 index 3e2fd6e4df3f..000000000000 --- a/app/views/public/splash.blade.php +++ /dev/null @@ -1,239 +0,0 @@ -@extends('public.header') - -@section('content') - - - -
-
- -
-
-
-
-

{{ trans('public.home.header') }}

-

{{ trans('public.home.sub_header') }}

-
-
-
-
- - - - - -
- -
-
-
-
-
-
-

{{ trans('public.home.free_always') }}

-

{{ trans('public.home.free_always_text') }}

-
-
- -
-
-
-

{{ trans('public.home.open_source') }}

-

{{ trans('public.home.open_source_text') }}

-
-
- -
-
-
-

{{ trans('public.home.live_pdf') }}

-

{{ trans('public.home.live_pdf_text') }}

-
-
- -
-
-
-

{{ trans('public.home.online_payments') }}

-

{{ trans('public.home.online_payments_text') }}

-

-
-
-
-
-
-
-
- -
-
-
- -
-
- Invoice Ninja Does Everything You'd Expect Your Online Invoicing App to Do -
-
-
-
- -
-
- - Invoice clients via email -
-
- - Intuitive editing interface -
- -
- - Printable .pdf invoices -
-
- - Multiple tax settings -
-
- - Import/export records -
-
- -
-
- - Accept payments online -
-
- - Best-in-class security -
- -
- - Adjustable payment terms -
-
- - Multiple currency support -
-
- - Recurring invoice profiles -
-
- -
-
- - Free invoicing platform -
-
- - Estimates & pro-forma -
- -
- - Payment tracking -
-
- - Multilingual support -
-
- - Self-hosted available -
-
- -
-
- - Live .pdf creation -
-
- - Clone invoices -
- -
- - Cloud-based app -
-
- - Open source -
-
- - Beautiful templates -
-
- -
-
- - Cutomize invoices with your company logo -
-
- - Personalize invoice color schemes -
- -
- - Alerts when invoices are viewed or paid -
-
- - Integrate with top payment gateways -
-
- - Manual or automatic invoice numbers -
-
- -
-
-
- -
-
-
-
-

{{ trans('public.home.footer') }}

- -

{{ trans('public.no_signup_needed') }}

-
-
- -
-
-
-
- - -@stop \ No newline at end of file diff --git a/app/views/public/terms.blade.php b/app/views/public/terms.blade.php index ddbea803a134..4f99598cada6 100644 --- a/app/views/public/terms.blade.php +++ b/app/views/public/terms.blade.php @@ -2,11 +2,12 @@ @section('content') -
+
-
-

Terms of Service & Conditions of Use -

+
+
+

Terms of Service & Conditions of Use

+
@@ -28,7 +29,7 @@
-

Definitions

+

Definitions

Invoiceninja.com users who access invoiceninja.com services are defined as “User Accounts”. User Account clients who use invoiceninja.com services to view and/or pay invoices are defined as “Clients.” The wording “data” and “content” are used interchangeably.

@@ -38,7 +39,7 @@
-

Responsibility

+

Responsibility

User Accounts must ensure the confidentiality of usernames and passwords used to access their account. User Accounts are responsible for all activity occurring under their account including all laws relating to data, privacy, personal information, international copyright and trademark laws.

@@ -49,7 +50,7 @@
-

Data Ownership

+

Data Ownership

The User Accounts owns all data generated in their invoiceninja.com account. Invoiceninja.com will not modify or distribute User Account data. Invoiceninja.com will store and access data solely for the purpose of providing services to User Accounts.

User Accounts are responsible for their data. Invoiceninja.com has no responsibility or liability for User Account data or Client experience. User Accounts are responsible for any loss or damage a User Account may cause to their Clients or other people. Although we have no obligation to do so, if deemed legally necessary invoiceninja.com has absolute discretion to remove or edit User Account data without notice or penalty.

Invoiceninja.com does not own User Account data, but we do reserve the right to use User Account data as necessary to operate invoiceninja.com and improve User Account services.

@@ -63,7 +64,7 @@
-

Copyright & Trademarks

+

Copyright & Trademarks

User Accounts are responsible that company logos, graphics, and content uploaded to invoiceninja.com do not infringe on international copyright & trademark law.

@@ -75,7 +76,7 @@
-

Open Source License

+

Open Source License

Invoiceninja.com is an open source application and invoiceninja.com source code is governed by international attribution assurances licensing: https://github.com/hillelcoren/invoice-ninja/blob/master/LICENSE.

@@ -87,7 +88,7 @@
-

User Account Limited License

+

User Account Limited License

Invoiceninja.com grants User Accounts & Clients a limited license to access the invoiceninja.com services such as User Account creation and all invoiceninja.om services, and Client services such as viewing invoices, downloading invoices, and printing invoices. This limited license may be revoked if deemed legally necessary without notice or penalty.

@@ -99,7 +100,7 @@
-

Use of Emailing Services

+

Use of Emailing Services

Keep it legal and clean. Any User Account emailing invoices data, hyper-links, or other material that is unlawful, libelous, defamatory, pornographic, harassing, invasive, fraudulent or otherwise objectionable will be deactivated.

Content that would constitute criminal offence or create legal liability, violate copyright, trademark, or intellectual property will be deleted or provided to legal authorities.

@@ -112,7 +113,7 @@
-

Security

+

Security

Invoiceninja.com does not store or obtain credit card or sensitive financial data in any form. Responsibility for Third-Party Material User Account may utilize hyper-linking to third-party web sites. Invoiceninja.com takes no responsibility for third party content.

@@ -124,7 +125,7 @@
-

Limited Liability

+

Limited Liability

User Accounts and Clients agree to indemnify, defend, and hold invoiceninja.com, its directors or employees harmless against any and all liability and cost as a result of using invoiceninja.com. User Accounts and Clients shall not assert any claim or allegation of any nature whatsoever against invoiceninja.com, its directors or employees.

Invoiceninja.com shall not be liable for damages of any kind, including but not limited to loss of site use, loss of profits or loss of data, tort or otherwise, arising out of or in any way connected with the use of or inability to use invoiceninja.com.

You shall defend, indemnify and hold harmless invoiceninja.com from any loss, damages, liabilities, expenses, claims and proceedings arising out of your use of invoiceninja.com.

@@ -137,7 +138,7 @@
-

Availability

+

Availability

Invoiceninja.com uses third party hosting that strives to ensure maximum uptime. However, invoiceninja.com cannot guarantee uninterrupted access invoiceninja.com. Invoiceninja.com reserves the right to interrupt access to invoiceninja.com for the sake of forming maintenance, updates, and security requirements.

diff --git a/app/views/public/testimonials.blade.php b/app/views/public/testimonials.blade.php deleted file mode 100644 index ee0fe3633827..000000000000 --- a/app/views/public/testimonials.blade.php +++ /dev/null @@ -1,45 +0,0 @@ -@extends('public.header') - -@section('content') - -
-
-
-

{{ trans('public.testimonials.testimonials') }}

-
-
-
-
-
-
-
-

{{ trans('public.testimonials.header') }}

-
-
-
-
-
-
-
-
- - - - - - - - - - - - - - -
-
-
-
- - -@stop \ No newline at end of file diff --git a/app/views/public_list.blade.php b/app/views/public_list.blade.php index 16949de93513..d906256951ba 100755 --- a/app/views/public_list.blade.php +++ b/app/views/public_list.blade.php @@ -81,7 +81,7 @@ -
+

 

@@ -101,33 +101,11 @@
+ + @stop -@section('onReady') - - var tableFilter = ''; - var searchTimeout = false; - - var oTable0 = $('#DataTables_Table_0').dataTable(); - function filterTable(val) { - if (val == tableFilter) { - return; - } - tableFilter = val; - oTable0.fnFilter(val); - @if (isset($secEntityType)) - oTable1.fnFilter(val); - @endif - } - - $('#tableFilter').on('keyup', function(){ - if (searchTimeout) { - window.clearTimeout(searchTimeout); - } - - searchTimeout = setTimeout(function() { - filterTable($('#tableFilter').val()); - }, 1000); - }) - -@stop \ No newline at end of file diff --git a/public/built.js b/public/built.js index e0e22a4ecd81..b526de7baa0e 100644 --- a/public/built.js +++ b/public/built.js @@ -33024,7 +33024,7 @@ function toggleDatePicker(field) { function roundToTwo(num, toString) { var val = +(Math.round(num + "e+2") + "e-2"); - return toString ? val.toFixed(2) : val || 0; + return toString ? val.toFixed(2) : (val || 0); } function truncate(str, length) { diff --git a/public/built.public.css b/public/built.public.css index ed6c61672308..f58246860324 100644 --- a/public/built.public.css +++ b/public/built.public.css @@ -3,1395 +3,6 @@ * Copyright 2011-2014 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) *//*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:before,:after{color:#000!important;text-shadow:none!important;background:transparent!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before,.glyphicon-eur:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:before,:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:hover,a:focus{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive,.thumbnail>img,.thumbnail a>img,.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:400;line-height:1;color:#777}h1,.h1,h2,.h2,h3,.h3{margin-top:20px;margin-bottom:10px}h1 small,.h1 small,h2 small,.h2 small,h3 small,.h3 small,h1 .small,.h1 .small,h2 .small,.h2 .small,h3 .small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:10px;margin-bottom:10px}h4 small,.h4 small,h5 small,.h5 small,h6 small,.h6 small,h4 .small,.h4 .small,h5 .small,.h5 .small,h6 .small,.h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}mark,.mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dt,dd{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse footer:before,blockquote.pull-right footer:before,.blockquote-reverse small:before,blockquote.pull-right small:before,.blockquote-reverse .small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,blockquote.pull-right footer:after,.blockquote-reverse small:after,blockquote.pull-right small:after,.blockquote-reverse .small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr.active:hover>th{background-color:#e8e8e8}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.info,.table>tbody>tr>td.info,.table>tfoot>tr>td.info,.table>thead>tr>th.info,.table>tbody>tr>th.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>tbody>tr.info>td,.table>tfoot>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr.info>th,.table>tfoot>tr.info>th{background-color:#d9edf7}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr.info:hover>th{background-color:#c4e3f3}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=radio],input[type=checkbox]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=radio]:focus,input[type=checkbox]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee;opacity:1}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date],input[type=time],input[type=datetime-local],input[type=month]{line-height:34px}input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.radio,.checkbox{position:relative;display:block;margin-top:10px;margin-bottom:10px}.radio label,.checkbox label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.radio input[type=radio],.radio-inline input[type=radio],.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox]{position:absolute;margin-top:4px \9;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type=radio][disabled],input[type=checkbox][disabled],input[type=radio].disabled,input[type=checkbox].disabled,fieldset[disabled] input[type=radio],fieldset[disabled] input[type=checkbox]{cursor:not-allowed}.radio-inline.disabled,.checkbox-inline.disabled,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.radio.disabled label,.checkbox.disabled label,fieldset[disabled] .radio label,fieldset[disabled] .checkbox label{cursor:not-allowed}.form-control-static{padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm,.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm,select.form-group-sm .form-control{height:30px;line-height:30px}textarea.input-sm,textarea.form-group-sm .form-control,select[multiple].input-sm,select[multiple].form-group-sm .form-control{height:auto}.input-lg,.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg,select.form-group-lg .form-control{height:46px;line-height:46px}textarea.input-lg,textarea.form-group-lg .form-control,select[multiple].input-lg,select[multiple].form-group-lg .form-control{height:auto}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline,.has-success.radio label,.has-success.checkbox label,.has-success.radio-inline label,.has-success.checkbox-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline,.has-warning.radio label,.has-warning.checkbox label,.has-warning.radio-inline label,.has-warning.checkbox-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline,.has-error.radio label,.has-error.checkbox label,.has-error.radio-inline label,.has-error.checkbox-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn,.form-inline .input-group .form-control{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .radio,.form-inline .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .radio label,.form-inline .checkbox label{padding-left:0}.form-inline .radio input[type=radio],.form-inline .checkbox input[type=checkbox]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .radio,.form-horizontal .checkbox{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.3px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn:focus,.btn:active:focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn.active.focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus,.btn.focus{color:#333;text-decoration:none}.btn:active,.btn.active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default.focus,.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled.focus,.btn-default[disabled].focus,fieldset[disabled] .btn-default.focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary:hover,.btn-primary:focus,.btn-primary.focus,.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled.focus,.btn-primary[disabled].focus,fieldset[disabled] .btn-primary.focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success.focus,.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled.focus,.btn-success[disabled].focus,fieldset[disabled] .btn-success.focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info.focus,.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled.focus,.btn-info[disabled].focus,fieldset[disabled] .btn-info.focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning.focus,.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled.focus,.btn-warning[disabled].focus,fieldset[disabled] .btn-warning.focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger.focus,.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled.focus,.btn-danger[disabled].focus,fieldset[disabled] .btn-danger.focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link:active,.btn-link.active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#777;text-decoration:none}.btn-lg,.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm,.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs,.btn-group-xs>.btn{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=submit].btn-block,input[type=reset].btn-block,input[type=button].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none;visibility:hidden}.collapse.in{display:block;visibility:visible}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#777}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px solid}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=radio],[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn,select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn,select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=radio],.input-group-addon input[type=checkbox]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:last-child>.btn-group:not(:last-child)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:first-child>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:hover,.input-group-btn>.btn:focus,.input-group-btn>.btn:active{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none;visibility:hidden}.tab-content>.active{display:block;visibility:visible}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important;visibility:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:200px}}.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn,.navbar-form .input-group .form-control{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .radio label,.navbar-form .checkbox label{padding-left:0}.navbar-form .radio input[type=radio],.navbar-form .checkbox input[type=checkbox]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:hover,.navbar-default .btn-link:focus{color:#333}.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:hover,.navbar-default .btn-link[disabled]:focus,fieldset[disabled] .navbar-default .btn-link:focus{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:hover,.navbar-inverse .btn-link:focus{color:#fff}.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:hover,.navbar-inverse .btn-link[disabled]:focus,fieldset[disabled] .navbar-inverse .btn-link:focus{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:hover,a.label:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:hover,.label-default[href]:focus{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-xs .badge{top:0;padding:1px 5px}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px 15px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron h1,.jumbotron .h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding:48px 0}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron h1,.jumbotron .h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail>img,.thumbnail a>img{margin-right:auto;margin-left:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar,.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress.active .progress-bar,.progress-bar.active{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-left,.media-right,.media-body{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{color:#555;text-decoration:none;background-color:#f5f5f5}.list-group-item.disabled,.list-group-item.disabled:hover,.list-group-item.disabled:focus{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>.small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:hover .list-group-item-text,.list-group-item.active:focus .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:hover,a.list-group-item-success:focus{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:hover,a.list-group-item-success.active:focus{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:hover,a.list-group-item-info:focus{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:hover,a.list-group-item-info.active:focus{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:hover,a.list-group-item-warning:focus{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:hover,a.list-group-item-danger:focus{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.table,.panel>.table-responsive>.table,.panel>.panel-collapse>.table{margin-bottom:0}.panel>.table caption,.panel>.table-responsive>.table caption,.panel>.panel-collapse>.table caption{padding-right:15px;padding-left:15px}.panel>.table:first-child,.panel>.table-responsive:first-child>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table:last-child,.panel>.table-responsive:last-child>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child th,.panel>.table>tbody:first-child>tr:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.panel-body,.panel-group .panel-heading+.panel-collapse>.list-group{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive iframe,.embed-responsive embed,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:absolute;top:0;right:0;left:0;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{min-height:16.43px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-weight:400;line-height:1.4;visibility:visible;filter:alpha(opacity=0);opacity:0}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-weight:400;line-height:1.42857143;text-align:left;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2)}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000;perspective:1000}.carousel-inner>.item.next,.carousel-inner>.item.active.right{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.prev,.carousel-inner>.item.active.left{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right,.carousel-inner>.item.active{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%;margin-left:-10px}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%;margin-right:-10px}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after,.dl-horizontal dd:before,.dl-horizontal dd:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after,.form-horizontal .form-group:before,.form-horizontal .form-group:after,.btn-toolbar:before,.btn-toolbar:after,.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after,.nav:before,.nav:after,.navbar:before,.navbar:after,.navbar-header:before,.navbar-header:after,.navbar-collapse:before,.navbar-collapse:after,.pager:before,.pager:after,.panel-body:before,.panel-body:after,.modal-footer:before,.modal-footer:after{display:table;content:" "}.clearfix:after,.dl-horizontal dd:after,.container:after,.container-fluid:after,.row:after,.form-horizontal .form-group:after,.btn-toolbar:after,.btn-group-vertical>.btn-group:after,.nav:after,.navbar:after,.navbar-header:after,.navbar-collapse:after,.pager:after,.panel-body:after,.modal-footer:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,.visible-sm,.visible-md,.visible-lg{display:none!important}.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}} -/*! - * Bootstrap v3.0.3 - * - * Copyright 2013 Twitter, Inc - * Licensed under the Apache License v2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Designed and built with all the love in the world @twitter by @mdo and @fat. - */ - -article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block;}audio,canvas,video{display:inline-block;}audio:not([controls]){display:none;height:0;}[hidden],template{display:none;}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;}body{margin:0;}a{background:transparent;}a:focus{outline:thin dotted;}a:active,a:hover{outline:0;}h1{font-size:2em;margin:0.67em 0;}abbr[title]{border-bottom:1px dotted;}b,strong{font-weight:bold;}dfn{font-style:italic;}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0;}mark{background:#ff0;color:#000;}code,kbd,pre,samp{font-family:monospace, serif;font-size:1em;}pre{white-space:pre-wrap;}q{quotes:"\201C" "\201D" "\2018" "\2019";}small{font-size:80%;}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}sup{top:-0.5em;}sub{bottom:-0.25em;}img{border:0;}svg:not(:root){overflow:hidden;}figure{margin:0;}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em;}legend{border:0;padding:0;}button,input,select,textarea{font-family:inherit;font-size:100%;margin:0;}button,input{line-height:normal;}button,select{text-transform:none;}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;}button[disabled],html input[disabled]{cursor:default;}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0;}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none;}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0;}textarea{overflow:auto;vertical-align:top;}table{border-collapse:collapse;border-spacing:0;}@media print{*{text-shadow:none !important;color:#000 !important;background:transparent !important;box-shadow:none !important;} a,a:visited{text-decoration:underline;} a[href]:after{content:" (" attr(href) ")";} abbr[title]:after{content:" (" attr(title) ")";} a[href^="javascript:"]:after,a[href^="#"]:after{content:"";} pre,blockquote{border:1px solid #999;page-break-inside:avoid;} thead{display:table-header-group;} tr,img{page-break-inside:avoid;} img{max-width:100% !important;} @page {margin:2cm .5cm;}p,h2,h3{orphans:3;widows:3;} h2,h3{page-break-after:avoid;} select{background:#fff !important;} .navbar{display:none;} .table td,.table th{background-color:#fff !important;} .btn>.caret,.dropup>.btn>.caret{border-top-color:#000 !important;} .label{border:1px solid #000;} .table{border-collapse:collapse !important;} .table-bordered th,.table-bordered td{border:1px solid #ddd !important;}}*,*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;}html{font-size:62.5%;-webkit-tap-highlight-color:rgba(0, 0, 0, 0);}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.428571429;color:#4f4747;background-color:#f1f1f1;}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit;}a{color:#2299c0;text-decoration:none;}a:hover,a:focus{color:#16657f;text-decoration:underline;}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}img{vertical-align:middle;}.img-responsive{display:block;max-width:100%;height:auto;}.img-rounded{border-radius:6px;}.img-thumbnail{padding:4px;line-height:1.428571429;background-color:#f1f1f1;border:1px solid #dddddd;border-radius:4px;-webkit-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out;display:inline-block;max-width:100%;height:auto;}.img-circle{border-radius:50%;}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eeeeee;}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:500;line-height:1.1;color:inherit;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:normal;line-height:1;color:#999999;}h1,h2,h3{margin-top:20px;margin-bottom:10px;}h1 small,h2 small,h3 small,h1 .small,h2 .small,h3 .small{font-size:65%;}h4,h5,h6{margin-top:10px;margin-bottom:10px;}h4 small,h5 small,h6 small,h4 .small,h5 .small,h6 .small{font-size:75%;}h1,.h1{font-size:36px;}h2,.h2{font-size:30px;}h3,.h3{font-size:24px;}h4,.h4{font-size:18px;}h5,.h5{font-size:14px;}h6,.h6{font-size:12px;}p{margin:0 0 10px;}.lead{margin-bottom:20px;font-size:16px;font-weight:200;line-height:1.4;}@media (min-width:768px){.lead{font-size:21px;}}small,.small{font-size:85%;}cite{font-style:normal;}.text-muted{color:#999999;}.text-primary{color:#edd71e;}.text-primary:hover{color:#c8b410;}.text-warning{color:#8a6d3b;}.text-warning:hover{color:#66512c;}.text-danger{color:#a94442;}.text-danger:hover{color:#843534;}.text-success{color:#3c763d;}.text-success:hover{color:#2b542c;}.text-info{color:#31708f;}.text-info:hover{color:#245269;}.text-left{text-align:left;}.text-right{text-align:right;}.text-center{text-align:center;}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eeeeee;}ul,ol{margin-top:0;margin-bottom:10px;}ul ul,ol ul,ul ol,ol ol{margin-bottom:0;}.list-unstyled{padding-left:0;list-style:none;}.list-inline{padding-left:0;list-style:none;}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px;}.list-inline>li:first-child{padding-left:0;}dl{margin-top:0;margin-bottom:20px;}dt,dd{line-height:1.428571429;}dt{font-weight:bold;}dd{margin-left:0;}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;} .dl-horizontal dd{margin-left:180px;}.dl-horizontal dd:before,.dl-horizontal dd:after{content:" ";display:table;} .dl-horizontal dd:after{clear:both;} .dl-horizontal dd:before,.dl-horizontal dd:after{content:" ";display:table;} .dl-horizontal dd:after{clear:both;}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999999;}.initialism{font-size:90%;text-transform:uppercase;}blockquote{padding:10px 20px;margin:0 0 20px;border-left:5px solid #eeeeee;}blockquote p{font-size:17.5px;font-weight:300;line-height:1.25;}blockquote p:last-child{margin-bottom:0;}blockquote small,blockquote .small{display:block;line-height:1.428571429;color:#999999;}blockquote small:before,blockquote .small:before{content:'\2014 \00A0';}blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eeeeee;border-left:0;}blockquote.pull-right p,blockquote.pull-right small,blockquote.pull-right .small{text-align:right;}blockquote.pull-right small:before,blockquote.pull-right .small:before{content:'';}blockquote.pull-right small:after,blockquote.pull-right .small:after{content:'\00A0 \2014';}blockquote:before,blockquote:after{content:"";}address{margin-bottom:20px;font-style:normal;line-height:1.428571429;}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace;}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;white-space:nowrap;border-radius:4px;}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.428571429;word-break:break-all;word-wrap:break-word;color:#333333;background-color:#f5f5f5;border:1px solid #cccccc;border-radius:4px;}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0;}.pre-scrollable{max-height:340px;overflow-y:scroll;}.container{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px;}.container:before,.container:after{content:" ";display:table;}.container:after{clear:both;}.container:before,.container:after{content:" ";display:table;}.container:after{clear:both;}@media (min-width:768px){.container{width:750px;}}@media (min-width:992px){.container{width:970px;}}@media (min-width:1200px){.container{width:1170px;}}.row{margin-left:-15px;margin-right:-15px;}.row:before,.row:after{content:" ";display:table;}.row:after{clear:both;}.row:before,.row:after{content:" ";display:table;}.row:after{clear:both;}.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12{position:relative;min-height:1px;padding-left:15px;padding-right:15px;}.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12{float:left;}.col-xs-12{width:100%;}.col-xs-11{width:91.66666666666666%;}.col-xs-10{width:83.33333333333334%;}.col-xs-9{width:75%;}.col-xs-8{width:66.66666666666666%;}.col-xs-7{width:58.333333333333336%;}.col-xs-6{width:50%;}.col-xs-5{width:41.66666666666667%;}.col-xs-4{width:33.33333333333333%;}.col-xs-3{width:25%;}.col-xs-2{width:16.666666666666664%;}.col-xs-1{width:8.333333333333332%;}.col-xs-pull-12{right:100%;}.col-xs-pull-11{right:91.66666666666666%;}.col-xs-pull-10{right:83.33333333333334%;}.col-xs-pull-9{right:75%;}.col-xs-pull-8{right:66.66666666666666%;}.col-xs-pull-7{right:58.333333333333336%;}.col-xs-pull-6{right:50%;}.col-xs-pull-5{right:41.66666666666667%;}.col-xs-pull-4{right:33.33333333333333%;}.col-xs-pull-3{right:25%;}.col-xs-pull-2{right:16.666666666666664%;}.col-xs-pull-1{right:8.333333333333332%;}.col-xs-pull-0{right:0%;}.col-xs-push-12{left:100%;}.col-xs-push-11{left:91.66666666666666%;}.col-xs-push-10{left:83.33333333333334%;}.col-xs-push-9{left:75%;}.col-xs-push-8{left:66.66666666666666%;}.col-xs-push-7{left:58.333333333333336%;}.col-xs-push-6{left:50%;}.col-xs-push-5{left:41.66666666666667%;}.col-xs-push-4{left:33.33333333333333%;}.col-xs-push-3{left:25%;}.col-xs-push-2{left:16.666666666666664%;}.col-xs-push-1{left:8.333333333333332%;}.col-xs-push-0{left:0%;}.col-xs-offset-12{margin-left:100%;}.col-xs-offset-11{margin-left:91.66666666666666%;}.col-xs-offset-10{margin-left:83.33333333333334%;}.col-xs-offset-9{margin-left:75%;}.col-xs-offset-8{margin-left:66.66666666666666%;}.col-xs-offset-7{margin-left:58.333333333333336%;}.col-xs-offset-6{margin-left:50%;}.col-xs-offset-5{margin-left:41.66666666666667%;}.col-xs-offset-4{margin-left:33.33333333333333%;}.col-xs-offset-3{margin-left:25%;}.col-xs-offset-2{margin-left:16.666666666666664%;}.col-xs-offset-1{margin-left:8.333333333333332%;}.col-xs-offset-0{margin-left:0%;}@media (min-width:768px){.col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12{float:left;} .col-sm-12{width:100%;} .col-sm-11{width:91.66666666666666%;} .col-sm-10{width:83.33333333333334%;} .col-sm-9{width:75%;} .col-sm-8{width:66.66666666666666%;} .col-sm-7{width:58.333333333333336%;} .col-sm-6{width:50%;} .col-sm-5{width:41.66666666666667%;} .col-sm-4{width:33.33333333333333%;} .col-sm-3{width:25%;} .col-sm-2{width:16.666666666666664%;} .col-sm-1{width:8.333333333333332%;} .col-sm-pull-12{right:100%;} .col-sm-pull-11{right:91.66666666666666%;} .col-sm-pull-10{right:83.33333333333334%;} .col-sm-pull-9{right:75%;} .col-sm-pull-8{right:66.66666666666666%;} .col-sm-pull-7{right:58.333333333333336%;} .col-sm-pull-6{right:50%;} .col-sm-pull-5{right:41.66666666666667%;} .col-sm-pull-4{right:33.33333333333333%;} .col-sm-pull-3{right:25%;} .col-sm-pull-2{right:16.666666666666664%;} .col-sm-pull-1{right:8.333333333333332%;} .col-sm-pull-0{right:0%;} .col-sm-push-12{left:100%;} .col-sm-push-11{left:91.66666666666666%;} .col-sm-push-10{left:83.33333333333334%;} .col-sm-push-9{left:75%;} .col-sm-push-8{left:66.66666666666666%;} .col-sm-push-7{left:58.333333333333336%;} .col-sm-push-6{left:50%;} .col-sm-push-5{left:41.66666666666667%;} .col-sm-push-4{left:33.33333333333333%;} .col-sm-push-3{left:25%;} .col-sm-push-2{left:16.666666666666664%;} .col-sm-push-1{left:8.333333333333332%;} .col-sm-push-0{left:0%;} .col-sm-offset-12{margin-left:100%;} .col-sm-offset-11{margin-left:91.66666666666666%;} .col-sm-offset-10{margin-left:83.33333333333334%;} .col-sm-offset-9{margin-left:75%;} .col-sm-offset-8{margin-left:66.66666666666666%;} .col-sm-offset-7{margin-left:58.333333333333336%;} .col-sm-offset-6{margin-left:50%;} .col-sm-offset-5{margin-left:41.66666666666667%;} .col-sm-offset-4{margin-left:33.33333333333333%;} .col-sm-offset-3{margin-left:25%;} .col-sm-offset-2{margin-left:16.666666666666664%;} .col-sm-offset-1{margin-left:8.333333333333332%;} .col-sm-offset-0{margin-left:0%;}}@media (min-width:992px){.col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12{float:left;} .col-md-12{width:100%;} .col-md-11{width:91.66666666666666%;} .col-md-10{width:83.33333333333334%;} .col-md-9{width:75%;} .col-md-8{width:66.66666666666666%;} .col-md-7{width:58.333333333333336%;} .col-md-6{width:50%;} .col-md-5{width:41.66666666666667%;} .col-md-4{width:33.33333333333333%;} .col-md-3{width:25%;} .col-md-2{width:16.666666666666664%;} .col-md-1{width:8.333333333333332%;} .col-md-pull-12{right:100%;} .col-md-pull-11{right:91.66666666666666%;} .col-md-pull-10{right:83.33333333333334%;} .col-md-pull-9{right:75%;} .col-md-pull-8{right:66.66666666666666%;} .col-md-pull-7{right:58.333333333333336%;} .col-md-pull-6{right:50%;} .col-md-pull-5{right:41.66666666666667%;} .col-md-pull-4{right:33.33333333333333%;} .col-md-pull-3{right:25%;} .col-md-pull-2{right:16.666666666666664%;} .col-md-pull-1{right:8.333333333333332%;} .col-md-pull-0{right:0%;} .col-md-push-12{left:100%;} .col-md-push-11{left:91.66666666666666%;} .col-md-push-10{left:83.33333333333334%;} .col-md-push-9{left:75%;} .col-md-push-8{left:66.66666666666666%;} .col-md-push-7{left:58.333333333333336%;} .col-md-push-6{left:50%;} .col-md-push-5{left:41.66666666666667%;} .col-md-push-4{left:33.33333333333333%;} .col-md-push-3{left:25%;} .col-md-push-2{left:16.666666666666664%;} .col-md-push-1{left:8.333333333333332%;} .col-md-push-0{left:0%;} .col-md-offset-12{margin-left:100%;} .col-md-offset-11{margin-left:91.66666666666666%;} .col-md-offset-10{margin-left:83.33333333333334%;} .col-md-offset-9{margin-left:75%;} .col-md-offset-8{margin-left:66.66666666666666%;} .col-md-offset-7{margin-left:58.333333333333336%;} .col-md-offset-6{margin-left:50%;} .col-md-offset-5{margin-left:41.66666666666667%;} .col-md-offset-4{margin-left:33.33333333333333%;} .col-md-offset-3{margin-left:25%;} .col-md-offset-2{margin-left:16.666666666666664%;} .col-md-offset-1{margin-left:8.333333333333332%;} .col-md-offset-0{margin-left:0%;}}@media (min-width:1200px){.col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12{float:left;} .col-lg-12{width:100%;} .col-lg-11{width:91.66666666666666%;} .col-lg-10{width:83.33333333333334%;} .col-lg-9{width:75%;} .col-lg-8{width:66.66666666666666%;} .col-lg-7{width:58.333333333333336%;} .col-lg-6{width:50%;} .col-lg-5{width:41.66666666666667%;} .col-lg-4{width:33.33333333333333%;} .col-lg-3{width:25%;} .col-lg-2{width:16.666666666666664%;} .col-lg-1{width:8.333333333333332%;} .col-lg-pull-12{right:100%;} .col-lg-pull-11{right:91.66666666666666%;} .col-lg-pull-10{right:83.33333333333334%;} .col-lg-pull-9{right:75%;} .col-lg-pull-8{right:66.66666666666666%;} .col-lg-pull-7{right:58.333333333333336%;} .col-lg-pull-6{right:50%;} .col-lg-pull-5{right:41.66666666666667%;} .col-lg-pull-4{right:33.33333333333333%;} .col-lg-pull-3{right:25%;} .col-lg-pull-2{right:16.666666666666664%;} .col-lg-pull-1{right:8.333333333333332%;} .col-lg-pull-0{right:0%;} .col-lg-push-12{left:100%;} .col-lg-push-11{left:91.66666666666666%;} .col-lg-push-10{left:83.33333333333334%;} .col-lg-push-9{left:75%;} .col-lg-push-8{left:66.66666666666666%;} .col-lg-push-7{left:58.333333333333336%;} .col-lg-push-6{left:50%;} .col-lg-push-5{left:41.66666666666667%;} .col-lg-push-4{left:33.33333333333333%;} .col-lg-push-3{left:25%;} .col-lg-push-2{left:16.666666666666664%;} .col-lg-push-1{left:8.333333333333332%;} .col-lg-push-0{left:0%;} .col-lg-offset-12{margin-left:100%;} .col-lg-offset-11{margin-left:91.66666666666666%;} .col-lg-offset-10{margin-left:83.33333333333334%;} .col-lg-offset-9{margin-left:75%;} .col-lg-offset-8{margin-left:66.66666666666666%;} .col-lg-offset-7{margin-left:58.333333333333336%;} .col-lg-offset-6{margin-left:50%;} .col-lg-offset-5{margin-left:41.66666666666667%;} .col-lg-offset-4{margin-left:33.33333333333333%;} .col-lg-offset-3{margin-left:25%;} .col-lg-offset-2{margin-left:16.666666666666664%;} .col-lg-offset-1{margin-left:8.333333333333332%;} .col-lg-offset-0{margin-left:0%;}}.clearfix:before,.clearfix:after{content:" ";display:table;}.clearfix:after{clear:both;}.center-block{display:block;margin-left:auto;margin-right:auto;}.pull-right{float:right !important;}.pull-left{float:left !important;}.hide{display:none !important;}.show{display:block !important;}.invisible{visibility:hidden;}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0;}.hidden{display:none !important;visibility:hidden !important;}.affix{position:fixed;}@-ms-viewport{width:device-width;}.visible-xs,tr.visible-xs,th.visible-xs,td.visible-xs{display:none !important;}@media (max-width:767px){.visible-xs{display:block !important;}table.visible-xs{display:table;} tr.visible-xs{display:table-row !important;} th.visible-xs,td.visible-xs{display:table-cell !important;}}@media (min-width:768px) and (max-width:991px){.visible-xs.visible-sm{display:block !important;}table.visible-xs.visible-sm{display:table;} tr.visible-xs.visible-sm{display:table-row !important;} th.visible-xs.visible-sm,td.visible-xs.visible-sm{display:table-cell !important;}}@media (min-width:992px) and (max-width:1199px){.visible-xs.visible-md{display:block !important;}table.visible-xs.visible-md{display:table;} tr.visible-xs.visible-md{display:table-row !important;} th.visible-xs.visible-md,td.visible-xs.visible-md{display:table-cell !important;}}@media (min-width:1200px){.visible-xs.visible-lg{display:block !important;}table.visible-xs.visible-lg{display:table;} tr.visible-xs.visible-lg{display:table-row !important;} th.visible-xs.visible-lg,td.visible-xs.visible-lg{display:table-cell !important;}}.visible-sm,tr.visible-sm,th.visible-sm,td.visible-sm{display:none !important;}@media (max-width:767px){.visible-sm.visible-xs{display:block !important;}table.visible-sm.visible-xs{display:table;} tr.visible-sm.visible-xs{display:table-row !important;} th.visible-sm.visible-xs,td.visible-sm.visible-xs{display:table-cell !important;}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block !important;}table.visible-sm{display:table;} tr.visible-sm{display:table-row !important;} th.visible-sm,td.visible-sm{display:table-cell !important;}}@media (min-width:992px) and (max-width:1199px){.visible-sm.visible-md{display:block !important;}table.visible-sm.visible-md{display:table;} tr.visible-sm.visible-md{display:table-row !important;} th.visible-sm.visible-md,td.visible-sm.visible-md{display:table-cell !important;}}@media (min-width:1200px){.visible-sm.visible-lg{display:block !important;}table.visible-sm.visible-lg{display:table;} tr.visible-sm.visible-lg{display:table-row !important;} th.visible-sm.visible-lg,td.visible-sm.visible-lg{display:table-cell !important;}}.visible-md,tr.visible-md,th.visible-md,td.visible-md{display:none !important;}@media (max-width:767px){.visible-md.visible-xs{display:block !important;}table.visible-md.visible-xs{display:table;} tr.visible-md.visible-xs{display:table-row !important;} th.visible-md.visible-xs,td.visible-md.visible-xs{display:table-cell !important;}}@media (min-width:768px) and (max-width:991px){.visible-md.visible-sm{display:block !important;}table.visible-md.visible-sm{display:table;} tr.visible-md.visible-sm{display:table-row !important;} th.visible-md.visible-sm,td.visible-md.visible-sm{display:table-cell !important;}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block !important;}table.visible-md{display:table;} tr.visible-md{display:table-row !important;} th.visible-md,td.visible-md{display:table-cell !important;}}@media (min-width:1200px){.visible-md.visible-lg{display:block !important;}table.visible-md.visible-lg{display:table;} tr.visible-md.visible-lg{display:table-row !important;} th.visible-md.visible-lg,td.visible-md.visible-lg{display:table-cell !important;}}.visible-lg,tr.visible-lg,th.visible-lg,td.visible-lg{display:none !important;}@media (max-width:767px){.visible-lg.visible-xs{display:block !important;}table.visible-lg.visible-xs{display:table;} tr.visible-lg.visible-xs{display:table-row !important;} th.visible-lg.visible-xs,td.visible-lg.visible-xs{display:table-cell !important;}}@media (min-width:768px) and (max-width:991px){.visible-lg.visible-sm{display:block !important;}table.visible-lg.visible-sm{display:table;} tr.visible-lg.visible-sm{display:table-row !important;} th.visible-lg.visible-sm,td.visible-lg.visible-sm{display:table-cell !important;}}@media (min-width:992px) and (max-width:1199px){.visible-lg.visible-md{display:block !important;}table.visible-lg.visible-md{display:table;} tr.visible-lg.visible-md{display:table-row !important;} th.visible-lg.visible-md,td.visible-lg.visible-md{display:table-cell !important;}}@media (min-width:1200px){.visible-lg{display:block !important;}table.visible-lg{display:table;} tr.visible-lg{display:table-row !important;} th.visible-lg,td.visible-lg{display:table-cell !important;}}.hidden-xs{display:block !important;}table.hidden-xs{display:table;}tr.hidden-xs{display:table-row !important;}th.hidden-xs,td.hidden-xs{display:table-cell !important;}@media (max-width:767px){.hidden-xs,tr.hidden-xs,th.hidden-xs,td.hidden-xs{display:none !important;}}@media (min-width:768px) and (max-width:991px){.hidden-xs.hidden-sm,tr.hidden-xs.hidden-sm,th.hidden-xs.hidden-sm,td.hidden-xs.hidden-sm{display:none !important;}}@media (min-width:992px) and (max-width:1199px){.hidden-xs.hidden-md,tr.hidden-xs.hidden-md,th.hidden-xs.hidden-md,td.hidden-xs.hidden-md{display:none !important;}}@media (min-width:1200px){.hidden-xs.hidden-lg,tr.hidden-xs.hidden-lg,th.hidden-xs.hidden-lg,td.hidden-xs.hidden-lg{display:none !important;}}.hidden-sm{display:block !important;}table.hidden-sm{display:table;}tr.hidden-sm{display:table-row !important;}th.hidden-sm,td.hidden-sm{display:table-cell !important;}@media (max-width:767px){.hidden-sm.hidden-xs,tr.hidden-sm.hidden-xs,th.hidden-sm.hidden-xs,td.hidden-sm.hidden-xs{display:none !important;}}@media (min-width:768px) and (max-width:991px){.hidden-sm,tr.hidden-sm,th.hidden-sm,td.hidden-sm{display:none !important;}}@media (min-width:992px) and (max-width:1199px){.hidden-sm.hidden-md,tr.hidden-sm.hidden-md,th.hidden-sm.hidden-md,td.hidden-sm.hidden-md{display:none !important;}}@media (min-width:1200px){.hidden-sm.hidden-lg,tr.hidden-sm.hidden-lg,th.hidden-sm.hidden-lg,td.hidden-sm.hidden-lg{display:none !important;}}.hidden-md{display:block !important;}table.hidden-md{display:table;}tr.hidden-md{display:table-row !important;}th.hidden-md,td.hidden-md{display:table-cell !important;}@media (max-width:767px){.hidden-md.hidden-xs,tr.hidden-md.hidden-xs,th.hidden-md.hidden-xs,td.hidden-md.hidden-xs{display:none !important;}}@media (min-width:768px) and (max-width:991px){.hidden-md.hidden-sm,tr.hidden-md.hidden-sm,th.hidden-md.hidden-sm,td.hidden-md.hidden-sm{display:none !important;}}@media (min-width:992px) and (max-width:1199px){.hidden-md,tr.hidden-md,th.hidden-md,td.hidden-md{display:none !important;}}@media (min-width:1200px){.hidden-md.hidden-lg,tr.hidden-md.hidden-lg,th.hidden-md.hidden-lg,td.hidden-md.hidden-lg{display:none !important;}}.hidden-lg{display:block !important;}table.hidden-lg{display:table;}tr.hidden-lg{display:table-row !important;}th.hidden-lg,td.hidden-lg{display:table-cell !important;}@media (max-width:767px){.hidden-lg.hidden-xs,tr.hidden-lg.hidden-xs,th.hidden-lg.hidden-xs,td.hidden-lg.hidden-xs{display:none !important;}}@media (min-width:768px) and (max-width:991px){.hidden-lg.hidden-sm,tr.hidden-lg.hidden-sm,th.hidden-lg.hidden-sm,td.hidden-lg.hidden-sm{display:none !important;}}@media (min-width:992px) and (max-width:1199px){.hidden-lg.hidden-md,tr.hidden-lg.hidden-md,th.hidden-lg.hidden-md,td.hidden-lg.hidden-md{display:none !important;}}@media (min-width:1200px){.hidden-lg,tr.hidden-lg,th.hidden-lg,td.hidden-lg{display:none !important;}}.visible-print,tr.visible-print,th.visible-print,td.visible-print{display:none !important;}@media print{.visible-print{display:block !important;}table.visible-print{display:table;} tr.visible-print{display:table-row !important;} th.visible-print,td.visible-print{display:table-cell !important;} .hidden-print,tr.hidden-print,th.hidden-print,td.hidden-print{display:none !important;}} -body { - font-family: Roboto, sans-serif; - line-height: 1.6; - background-color: #fff; - overflow-x: hidden; - color: #2e2b2b; -} -.center-block { - margin: 0 auto !important; - float: none; -} -.valgin {padding: 0; margin: 0;} -h1, -h2, -.btn { - font-family: Roboto, sans-serif; - font-weight: 900; - line-height: 1.1; - color: #2e2b2b; -} -h1 { - font-size: 56px; - text-transform: uppercase; - color: #fff; -} -h1 img { - margin-right: 10px; - margin-top: -10px; -} -h2 { - font-size: 25px; -} -h3 { - font-size: 16px; - margin-top: 0; - font-weight: 700; - font-family: Roboto, sans-serif; -} -.headline { - border-bottom: 1px solid #eee; - padding-bottom: 10px; - margin-bottom: 15px; -} -.thin { - font-weight: 300; -} -p.first { - font-size: 17px; -} -a, -a .cta h2, -.socicon, -.btn, -a img -{ - -webkit-transition: all .3s ease-in-out; - -moz-transition: all .3s ease-in-out; - -o-transition: all .3s ease-in-out; - transition: all .3s ease-in-out; -} -a:hover { - text-decoration: none; -} -.blue-text { - color: #2299c0; -} -.center { - text-align: center; -} -.white-bg { - background-color: #fff; -} -.form-group { -margin-bottom: 25px; -} -.form-group .glyphicon { - position: absolute; -top: 28px; -left: 15px; -display: block; -width: 50px; -height: 50px; -line-height: 50px; -text-align: center; - color: #bfbfbf; -} -.form-control.with-icon {padding-left: 50px !important;} - -/* Navigation */ - -.navbar { - background: #211f1f; - padding: 40px 0; - border: none; - border-radius: 0; -} -.navbar-brand { - padding: 0; - line-height: 1; - height: auto; -} - .navbar>.container .navbar-brand { - margin-left: 0 !important; - } -ul.navbar-nav { - float: right; - list-style-type: none; - margin: 0; - padding: 0; -} -ul.navbar-nav li { - display: inline; - font-family: Roboto, sans-serif; - font-weight: 900; - text-transform: uppercase; - height: 26px; - line-height: 26px; -} -ul.navbar-nav li a { - color: #fff; - margin-left: 45px; -} -ul.navbar-nav .glyphicon { - color: #ebbe09; -} -ul.navbar-nav li:last-child a { - color: #ebbe09; - margin-left: 5px; -} -ul.navbar-nav li:last-child { - border-left: 1px solid #4f4b4b; - padding-left: 45px; - margin-left: 45px; -} -ul.navbar-nav li:first-child a { - border-left: none; - margin: 0; - padding-left: 0; -} -ul.navbar-nav li a:hover { - color: #ebbe09; - text-decoration: none; -} - -.navbar-nav>li { - float: right; -} -.navbar-nav>li>a { - padding: 0; - display: inline-block; -} -.nav>li>a:hover, .nav>li>a:focus { - background-color: transparent; -} -z.container>.navbar-collapse { - margin-right: -15px; -} -.navbar-top { - padding: 5px 0 0 0; - background: #fff; - border-top: 1px solid #211f1f; -} -.navbar-top ul { - float: right; - margin: 0; -} -.navbar-top ul li { - display: inline-block; - font-size: 12px; - text-transform: uppercase; - margin-left: 30px; - height: 40px; - line-height: 40px; - vertical-align: middle; - float: left; -} -.navbar-top ul li .socicon { - text-transform: none; - margin-top: 1px; -} -.navbar-top ul li a .socicon { - font-size: 13px; - color: #a6a5a5; - display: inline-block; -} -.navbar-top ul li a .socicon:hover { - color: #ebbe09; -} -.navbar-top ul li a { - color: #2e2b2b; -} -.navbar-top ul li a:hover { - color: #ebbe09; -} - - -a .cta h2 { - width: 100%; - height: 63px; - line-height: 63px; - background: #edd71e; - display: inline-block; - color: #1a1818; - text-align: center; - float: left; - margin: 0; - text-transform: uppercase; - font-size: 20px; - font-weight: 900; -} -a .cta h2 span { - width: 63px; - height: 63px; - line-height: 63px; - color: #fff; - background: #ebbe09; - text-align: center; - float: right; - font-weight: 700; - font-size: 20px; - font-family: Roboto, sans-serif; - -webkit-transition: all .1s ease-in-out; - -moz-transition: all .1s ease-in-out; - -o-transition: all .1s ease-in-out; - transition: all .1s ease-in-out; -} -a .cta:hover span { - font-size: 40px; - background: #f2c40a; -} -.hero h1 { - margin: 0; -} -.hero { - text-align: center; - padding: 150px 0; - background-repeat: no-repeat; - background-position: center center; - background-size: cover; -} -.hero4 { - padding: 150px 0; - background-repeat: no-repeat; - background-position: center center; - background-size: cover; -} -.hero5 { - text-align: center; - padding: 150px 0; - background-repeat: no-repeat; - background-position: center center; - background-size: cover; -} -.hero1.background { - background-repeat: no-repeat; - background-position: center center; - /*background-attachment: fixed;*/ - background-size: cover; - min-height: 500px; -} -.hero1 {padding: 0;} -.hero1 h1 { - font-size: 45px; - margin-top: 20px; - margin-bottom: 10px; - color: #1a1818; -} -.hero .caption-side { - background: #fff; - width: 50%; - padding-right: 15px; - position: absolute; - left: 0; - height: 212px; - margin-top: 100px; -} -.hero .caption { - width: 61.5%; - background: #fff; - padding-right: 15px; - position: relative; - padding: 10px 35px 20px 35px; - height: 212px; - border-left: 1px dotted #ccc; - margin-top: 100px; - text-align: left; - color: #1a1818; -} -.hero-secure p {font-size: 20px; text-transform: uppercase; color: #fff;} -.hero-secure p img { vertical-align: baseline; padding-right: 5px;} -section.features-splash, -section.upper-footer { - margin: 70px 0; -} -section.features, section.about, section.team, section.testi { - margin: 0; - padding: 100px 0; -} -section.secure { - padding: 50px 0 100px 0; -} -section.features1 { - padding-bottom: 0; -} -section.features3, section.features5 { - padding-bottom: 100px; -} -section.features1 .col-md-5, section.features4 .col-md-5{ - padding-bottom: 100px; -} -section.features4 { - padding-bottom: 0; -} - -section.features.upper-footer { - background-color: #fad129; - padding: 40px 0; - text-align: center; - } -section.features.upper-footer a .cta h2 { - background-color: #211f1f; - color: #fff; - padding: 0; - } -section.features.upper-footer h2.thin { - line-height: 63px; - float: right; - margin:0; - } - -section.features4, section.team, .card { -background-color: #f4f3f3; -} -section.features4 .col-md-7 img { -float: right; - margin-right: 40px; -} -section.features1 .col-md-7 img, section.features3 .col-md-7 img { - margin-left: 40px; -} -.upper-footer { - background-color: #f8f8f8; - border-top: 1px solid #e6e6e6; -} - -section.upper-footer.white-bg { - margin: 0; - padding: 60px 0; -} -section.features-splash .box { - padding: 20px; - text-align: center; -} -/*Icons*/ - -section.features-splash .icon { - background: #2599c0; - width: 94px; - height: 94px; - border: 8px solid #1d8db3; - text-align: center; - display: table; - margin: 0 auto; -} -section.features .icon { - background: #2599c0; - width: 35px; - height: 35px; - border: 4px solid #1d8db3; - text-align: center; - display: table; - float: left; - line-height: 1; -} - -section.testi.blue { - background-size: auto; - background-repeat:no-repeat; - background-position:bottom; -} - -.twitter-tweet {margin: 0 auto !important; margin-bottom: 30px !important;} - -.icon.open { - background: #32ba8d !important; - border-color: #28ae82 !important; -} -.icon.secure { - background: #2e2b2b !important; - border-color: #161414 !important; -} -section.features .icon.free img { - width: 23px; -} -section.features .icon.open img { - width: 23px; -} -section.features .icon.pdf img { - width: 16px; - float: none; -} -section.features .icon.pay img { - width: 23px; -} -section.blue .icon.free { - background-color: #fff; - border-color: #fff; -} -section.features-splash .two .box h2 { - color: #32ba8d; -} -.icon.pdf { - background: #d2462d !important; - border-color: #c23b23 !important; -} -section.features-splash .three .box h2 { - color: #d2462d; -} -.icon.pay { - background: #fad129 !important; - border-color: #f0c824 !important; -} -section.features-splash .four .box h2 { - color: #f0c824; -} -section.features-splash h2 { - margin: 20px 0 15px; - color: #2599c0; -} -section.features h2 { - display: inline-block; - margin-top: 5px; - padding-left: 15px; - color: #1a1818; -} -.icon .img-wrap { - display: table-cell; - vertical-align: middle; - height: 100%; - padding: 0; -} -.icon img { - vertical-align: middle; -} -section.blue { - background-image: url('../images/bg-blue.jpg'); - background-color: #2387a9; - background-size: cover; - color: #fff; - padding: 140px 0; -} -section.blue .col-md-7 { - text-align: left; -} -section.blue h1 span { - font-size: 30px; - display: block; -} -section.blue h1 { - color: #fff; - line-height: 1.2; - margin-bottom: 20px; - margin-top: 30px; - font-size: 65px; -} -section.blue h2 { - color: #fff; -} -section.blue a { - color: #ffffff; - text-decoration: underline; -} -section.blue p { - margin-top: 15px; -} -section.blue img { - max-width: 100%; -} -section.plans { - padding: 70px 0; -} -section.team h2, -section.plans h2 { - font-size: 25px; - margin: 0 0 25px; - text-transform: none; -} -section.team .col-md-3 h2 { - margin-top: 20px; - margin-bottom: 3px; - font-size: 20px; -} -section.about .screendump { - height: 220px; -} -section.about.white-bg .col-md-5 { - padding-right: 43px; - padding-left: 15px; -} -section.about img, -section.team img { - width: 100%; - min-width: 100%; -} -section.team .col-md-3 { - margin-top: 25px; - padding: 0 20px; -} -section.team .col-md-3 p { - font-size: 12px; - margin-bottom: 20px; -} -section.team .social { - margin: 3px 3px 0 3px; -} -section.team .social.blue {background-color: #2599c0;} -section.team .social.green {background-color: #30ab82;} -section.team .social.red {background-color: #d2462d;} -section.team .social.yellow {background-color: #ebbe09;} -section.team .social img { - margin: 12px 7px; - height: 15px; - display: inline-block; - width: auto; - min-width: 1px; - padding: 0; -} -section.team .img-team:before { - -webkit-box-shadow: inset 0 0 10px 0 rgba(255, 255, 255, 0.3); - box-shadow: inset 0 0 0 7px rgba(255, 255, 255, 0.3); - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - content: ""; -} -section.team .img-team { - z-index: 1000; position: relative; -} -section.team .img-team img {} -section.contact .address .glyphicon, section.contact .address .socicon { - background: #edd71e; - height: 40px; - width: 40px; - line-height: 40px; - text-align: center; - border-radius: 50px; - color: #1a1818; - margin-right: 15px; - display: inline-block; -} - -section.contact .address p { - margin-top: 20px; -} -section.contact .address span.push { - margin-left: 55px; - line-height: 25px; -} - -section.contact .form-control, section.secure .form-control, footer.footer .form-control { - display: block; - width: 100%; - height: 50px; - padding: 6px 12px; - font-size: 14px; - line-height: 1.42857143; - color: #555; - background-color: #fff; - background-image: none; - border: 1px solid #e0e0e1; - border-radius: 0; - -webkit-box-shadow: inset 0px 0px 8px 5px rgba(50, 50, 50, 0.25); - -moz-box-shadow: inset 0px 0px 8px 5px rgba(50, 50, 50, 0.25); - box-shadow: inset 0px 0px 5px 2px rgba(50, 50, 50, 0.05); - -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; - transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; -} -section.contact textarea.form-control { - height: auto; -} -section.contact form { - margin-top: 30px; -} - -section.secure label { text-transform: uppercase; font-size: 12px; font-weight: 800; margin-bottom: 10px; display: block;} - -section.secure .card {padding: 30px; margin-bottom: 50px;} -section.secure .card p {padding-top: 26px; padding-right: 15px; line-height: 50px;} -section.secure .info {padding-top: 30px;} - - - -section.faq { - padding: 70px 0; -} -section.faq a.expander { - display: block; - font-size: 18px; - font-family: Roboto, sans-serif; - font-weight: 700; - margin-bottom: 10px; -} -/*section.faq .content{display:none;}*/ -section.faq .question { - padding-bottom: 20px; - margin-bottom: 30px; - border-bottom: 1px solid #e0e0e0; -} -section.faq .contact-box { - margin-top: 30px; - padding: 40px; - color: #4f4747; - background: #fad129; -} -section.faq .contact-box h2 { - text-transform: uppercase; - display: block; - float: left; - width: 60%; - margin-top: 0; - margin-bottom: 0; - padding: 2px 0; -} -section.faq .contact-box img { - float: left; - display: block; - margin-right: 20px; - margin-left: 30px; - height: 57px; -} -section.faq .contact-box .col-md-8 { - padding-left: 5px; -} -section.faq .contact-box h2 { - border-right: 1px solid #e4bf28; -} - -section.faq .contact-box a { - color: #2e2b2b; -} -section.faq .contact-box p { - -} - -.btn-primary { - color: #fff; - background-color: #2299c0; - border: none; - text-align: center; - border-radius: 0; - height: 63px; - line-height: 63px; - padding: 0; - width: 100%; - text-align: center; -} -.btn-primary:hover { - background-color: #2299c0; -} - -.btn.green { - background-color: #30ab82; -} -.btn.green:hover { - background-color: #2daa81; -} -.btn-lg { -font-size: 18px; -} -section.contact button span.glyphicon { - background-color: transparent; - color: #fff; - float: right; -} -section.contact .btn span.glyphicon { - background-color: #1e84a5; - height: 63px; - line-height: 63px; - width: 63px; - margin-top: -1px; - -webkit-transition: all .1s ease-in-out; - -moz-transition: all .1s ease-in-out; - -o-transition: all .1s ease-in-out; - transition: all .1s ease-in-out; -} -section.contact .btn:hover span.glyphicon { - font-size: 25px; -} -section.contact textarea:focus, section.secure textarea:focus, -select:focus, -input[type=text]:focus, -input[type=password]:focus, -input[type=datetime]:focus, -input[type=datetime-local]:focus, -input[type=date]:focus, -input[type=month]:focus, -input[type=time]:focus, -input[type=week]:focus, -input[type=number]:focus, -input[type=email]:focus, -input[type=url]:focus, -input[type=search]:focus, -input[type=tel]:focus, -input[type=color]:focus, -.uneditable-input:focus { - -} -section.contact address { - display: inline-block; -} -footer.footer { - background: #211f1f; - padding: 50px 0; - text-align: center; -} -footer.footer h3 { text-align: left; color: #fff; padding-bottom: 12px; margin-bottom: 25px; border-bottom: 1px solid #2c2a2a;} -footer.footer hr { -margin-top: 25px; -margin-bottom: 25px; -border: 0; -border-top: 1px solid #2c2a2a; -} -footer.footer .glyphicon {margin-right: 8px; color: #ebbe09; width: 15px; font-size: 14px;} -footer ul.navbar-vertical { - margin: 0; - padding: 0; - margin-bottom: 30px; -} -footer ul.navbar-vertical li { - display: block; - padding: 2px 0; -} -footer ul.navbar-vertical li a { - color: #a3a2a2; - font-size: 12px; - font-weight: 800; - text-transform: uppercase; -} -footer ul.navbar-vertical li a:hover { - color: #e5e5e5; -} - -footer.footer .social { - margin-bottom: 30px; - width: 100%; - clear: both; - text-align: center; -} - -footer.footer .social img { - margin: 0 3px; -} -footer.footer .social a img:hover { - opacity: 0.6; -} - -footer.footer .social .row1 { - margin-bottom: -8px; -} - -footer.footer form#mad_mimi_signup_form button { - position: absolute; - right: 0; - top: 0; - width: 50px; - height: 50px; - background: #b7b7b6; - border: none; - padding: 0; - border-radius: 0; - text-align: center; - margin-bottom: 30px; -} -footer.footer form#mad_mimi_signup_form button:hover { - background: #7b7a79; -} -footer.footer form#mad_mimi_signup_form button .glyphicon { - position: static; - color: #fff; - font-size: 15px; -width: auto; - margin: 0; -} -footer.footer form#mad_mimi_signup_form .form-group { - position: relative; -} -footer.footer form#mad_mimi_signup_form input { - padding-right: 60px; - background: #393636; - border: none; - color: #b7b7b6; -} - -/* Fonts */ - -.socicon { - font-family: 'socicon' !important; -} -@font-face { - font-family: socicon; - src: url(../fonts/socicon-webfont.eot); - src: url(../fonts/socicon-webfont.eot?#iefix) format(embedded-opentype), url(../fonts/socicon-webfont.woff) format(woff), url(../fonts/socicon-webfont.ttf) format(truetype), url(../fonts/socicon-webfont.svg#sociconregular) format(svg); - font-weight: 400; - font-style: normal; -} - -@media (max-width: 768px) { - - /* Responsive actions */ - .hidden-desktop { - display: block !important; - } - .hidden-phone { - display: none !important; - } - - /* Typo */ - p { - font-size: 12px; - } - p.first { - font-size: 14px; - margin: 0; - } - h1 { - font-size: 30px; - } - h2 { - font-size: 20px; - } - .headline h2 { - margin-top: 0; - } - .headline { - border-bottom: none; - padding-bottom: 0; - margin-bottom: 15px; - } - section.team h2, section.plans h2 { - font-size: 20px; - margin: 0 0 15px; - } - - /* Mobile navigation */ - .navbar { - text-align: center; - padding: 0; - } - .navbar-header { - padding: 15px 0; - } - ul.navbar-nav { - width: 100%; - } - .navbar li.hidden-desktop { - font-weight: 400; - font-size: 11px; - } - ul.navbar-nav li { - float: none; - margin: 0; - height: 30px; - line-height: 30px; - font-size: 12px; - display: block !important; - } - ul.navbar-nav li a { - margin: 0; - display: inline; - width: 100%; - float: none; - padding: 0; - } - ul.navbar-nav li:first-child { - margin-top: 12px; - } - ul.navbar-nav li:first-child a { - margin: 0; - padding: 0; - } - ul.navbar-nav li:last-child { - border-left: none; - padding-left: 0; - margin-left: 0; - margin-bottom: 12px; - } - .navbar-collapse { - border-top: none; - box-shadow: none; - background: #282525; - } - .navbar-toggle { - border: 1px solid #ddd; - margin: 0; - } - .navbar-toggle .icon-bar { - background: #ddd; - } - - ul.navbar-list { - float: none; - margin-top: 10px; - } - .navbar-brand { - margin-top: 6px; - } - .container>.navbar-header { - margin: 0; - } - - /* Sections */ - section.features, section.blue, section, section.secure, section.about, section.team, section.contact, section.faq, section.testi, section.plans { - padding: 40px 0; - margin: 0 !important; - } - - section.features-splash .icon { - width: 50px; - height: 50px; - border: 4px solid #1d8db3; - } - section.features-splash .icon img { - width: 30px; - } - - section.about .col-md-5 { - padding-left: 15px !important; - } - section.faq .question { - padding-bottom: 10px; - margin-bottom: 20px; - } - section.faq a.expander { - font-size: 14px; - } - section.faq .contact-box { - margin-top: 20px; - padding: 25px; - text-align: center; - } - section.faq .contact-box h2 { - float: none; - width: 100%; - margin: 10px 0; - } - section.faq .contact-box img { - float: none; - display: inline-block; - margin-right: 0; - margin-left: 0; - height: 57px; - } - section.faq .contact-box .col-md-8 { - padding-left: 15px; - } - section.faq .contact-box h2 { - border-right: none; - } - section.faq .contact-box p { - margin: 0; - } - section.plans .plans-table { - margin-top: 30px; - font-size: 12px; - } - .plans-table .free .cell { - border-left: 1px solid #dfe0e1; - border-right: 1px solid #dfe0e1; - } - .plans-table .free .cell:first-child { - border-left: 1px solid #9b9b9b; - border-right: 1px solid #9b9b9b; - } - section.plans .plans-table .cell { - display: block; - width: 100%; - } - section.plans .plans-table span { - display: inline-block !important; - } - section.plans .plans-table .hidden-desktop { - display: inline-block !important; - margin-bottom: 0; - margin-right: 10px; - } - section.plans .plans-table .cell { - height: auto; - padding: 14px 0; - } - section.plans .plans-table .free .cell { - padding-right: 0; - } - section.plans .plans-table .free .cell:first-child { - margin-right: 0; - } - section.plans .plans-table .cell .cta { - margin-bottom: 0 !important; - } - section.plans .plans-table .pro { - margin-top: 30px; - } - .plans-table .pro .cell:last-child, .plans-table .free .cell:last-child { - padding: 14px 0 0 0 !important; - } - .plans-table .pro .cell:last-child p { - margin: 0; - padding: 0; - } - section.about img { - margin-top: 20px; - } - section.team .img-team { - width: 60%; - min-width: 60%; - margin: 0 auto; - } - - section.team .col-md-3:last-child p:last-child { - margin-bottom: 0; - } - - /* Heros */ - .hero1.background { - min-height: 100px; - } - .hero .caption { - width: 100%; - background: #fff; - padding: 10px 35px 20px 35px; - height: auto; - border-left: none; - margin-top: 0px; - margin-bottom: 10px; - text-align: center; - } - .hero .caption-side { - display:none; - } - .hero1 h1 { - font-size: 30px; - } - .hero{ - padding: 50px 0; - } - .background { - background-attachment: scroll; - background-size: cover; - background-position: bottom center; - background-repeat: repeat; - min-height: 1px; - padding: 50px 0; - } - section.upper-footer.white-bg { - padding: 30px 0; - } - section.features .col-md-3 .box { - margin-bottom: 10px; - } - - - section.secure .info { - padding-top: 0; - } - section.secure .card { - padding: 15px; - margin-bottom: 40px; - } - section.secure .card p { - padding-top: 0; - padding-right: 15px; - line-height: 1; - } - section.blue h1 { - line-height: 1.2; - margin-bottom: 20px; - margin-top: 0; - font-size: 30px; - } - section.blue h1 span { -font-size: 20px; -} - section.features-splash .box { -padding: 20px 0 0 0; -} - section.features-splash { -margin-top: -20px !important; -} - section.features .col-md-7 img{ - max-width: 100%; - margin: 0; - } - section.features.blue .col-md-7 img, section.features4 .col-md-7 img { - margin-bottom: 30px; - } - section.features1 .col-md-7 img, section.features3 .col-md-7 img, section.features5 .col-md-7 img { - margin-top: 30px; - } - section.features1 .col-md-5, section.features4 .col-md-5, section.features5 .col-md-5 { -padding-bottom: - 0; -} - section.features.upper-footer { -text-align: center; -padding: 20px 0 40px 0; -} - section.features.upper-footer h2.thin { -line-height: 63px; -float: none; - -} -.nitinh-vAlign{ - position: static !important; - } - section.blue .col-md-6 h1 { - border-left: none; - border-right: none; - border-top: 1px dotted #46b9df; - padding: 30px 0; - } - section.blue .col-md-6 h1 span { - font-size: 25px; - font-weight: 100; - display: block; - text-transform: lowercase; - } - section.contact .address { - margin: 0; - text-align: center; - } - section.contact .address p { - text-align: center; - } - section.contact .address .glyphicon, section.contact .address .socicon { - display: block; - margin: 0 auto 7px; - float: none; - } - section.contact .address span.push { - margin-left: 0; - } - section.contact .btn { - margin-bottom: 5px; - } - section.about p { - margin-bottom: 0; - margin-top: 10px; - } - section.about .screendump { - margin-top: 25px; - } - section.about.white-bg .screendump { - margin-top: 0; - margin-top: 0; - margin-bottom: 20px; - } - #contact_form { - margin: 0; - } - #feedbackForm { - margin-top: 15px; - } - - /* Footer */ - footer .navbar-inner { - float: none; - } - footer ul.navbar-list:last-child { - height: auto; - } - footer .social { - float: none; - margin-bottom: 10px; - } - footer .social .socicon { - margin-right: 8px; - } -} -.github { - background-image: url(../images/GitHub.png); - background-size: contain; - background-repeat: no-repeat; - width: 40px; - height: 40px; - display: inline-block; - margin-right: 10px; - float: left; -} -div.fb_iframe_widget { - display: inline; -} -div.fb_iframe_widget > span { - vertical-align: top !important; -} -::selection { - color: #fff; - background: #2e2b2b; -} -::-moz-selection { - color: #fff; - background: #2e2b2b; -} -.plans-table { - text-align: center; - margin: 0 auto; - float: none; - margin-top: 60px; -} -.plans-table .free, -.plans-table .desc { - padding: 0; -} -.plans-table .free .cell { - padding-right: 15px; -} -.plans-table .desc .cell { - text-align: right; - padding-right: 15px; - border-left: 1px solid #dfe0e1; - font-size: 13px; - font-weight: 800; -} -.plans-table .pro .cell { - border-left: 1px solid #cccccc; - border-right: 1px solid #cccccc; -} -.plans-table .cell { - background-color: #fff; - border-top: 1px solid #dfe0e1; - padding: 18px 0; - font-family: Roboto, sans-serif; - height: 60px; -} -.plans-table .cell:nth-child(odd) { - background-color: #fbfbfb; -} -.plans-table .pro .cell:nth-child(odd) { - background-color: #f4f4f4; -} -.plans-table .pro { - background-color: #2299c0; - overflow: hidden; - padding: 0; - -webkit-box-shadow: 0px 0px 15px 0px rgba(0, 5, 5, 0.2); - -moz-box-shadow: 0px 0px 15px 0px rgba(0, 5, 5, 0.2); - box-shadow: 0px 0px 15px 0px rgba(0, 5, 5, 0.2); -} -.plans-table .free .cell:first-child, -.plans-table .pro .cell:first-child { - color: #fff; - text-transform: uppercase; - font-size: 24px; - font-weight: 800; - line-height: 60px; - padding: 0; - position: relative; - bottom: -1px; - border: none; -} -.plans-table .free .cell:first-child { - background-color: #9b9b9b; - margin-right: 15px; - padding-right: 0; -} -.plans-table .free, -.plans-table .desc, .plans-table .pro { - border-bottom: 1px solid #dfe0e1; -} -.plans-table .pro .cell:first-child { - background-color: #2299c0; -} -.plans-table .pro .cell:last-child { - padding: 0; -} -.plans-table .desc .cell:first-child { - background-color: transparent; - border: none; -} - -.compare-table .glyphicon, -.plans-table .glyphicon { - color: #fff; - border-radius: 50px; - padding: 5px; - font-size: 10px; -} -.compare-table .glyphicon-remove, -.plans-table .glyphicon-remove { - background-color: #da4830; -} -.compare-table .glyphicon-ok, -.plans-table .glyphicon-ok { - background-color: #35c156; -} -.plans-table .glyphicon-star { - border-radius: 0; - background-color: #2e2b2b; - display: block; - width: 60px; - height: 30px; - position: absolute; - top: -5px; - right: -20px; - -webkit-transform: rotate(45deg); - -moz-transform: rotate(45deg); - -o-transform: rotate(45deg); - transform: rotate(45deg); - padding: 13px 0 0 1px; -} -.plans-table .price { - padding: 0; -} -.plans-table .free .price p { - color: #35c156; -} -.plans-table .pro .price p { - color: #2299c0; -} -.plans-table .price p { - font-size: 40px; - text-transform: uppercase; - font-weight: 800; - margin: 0; - line-height: 55px; -} -.plans-table .price p span { - font-size: 16px; - text-transform: none; - font-weight: 400; -} -.plans-table a .cta h2 { - background: #2299c0; - color: #fff; - margin: 0; -} -.plans-table a .cta h2 span { - background: #1e84a5; -} - - -table.compare-table td { - height: 70px; - vertical-align: middle !important; -} -table.compare-table th { - height: 70px; - vertical-align: middle !important; - text-align: center; - color: white; -} -table.compare-table td:first-child { - text-align: left; -} -table.compare-table-free th { - background-color: #0b4d78; -} -table.compare-table-paid th { - background-color: #e37329; -} - - -@media (min-width: 992px) { - .hide-desktop {display: none !important;} -} - -@media (max-width: 992px) { - .hide-phone { - display: none !important; - } -} - -/* Hide bootstrap sort header icons */ -table.table thead .sorting:after { content: '' !important } -table.table thead .sorting_asc:after { content: '' !important } -table.table thead .sorting_desc:after { content: '' !important} -table.table thead .sorting_asc_disabled:after { content: '' !important } -table.table thead .sorting_desc_disabled:after { content: '' !important } /* * Table styles */ diff --git a/public/images/icon-shield.png b/public/images/icon-shield.png new file mode 100644 index 0000000000000000000000000000000000000000..0310ab09e2e8315ec1f84ce9bed3eb9602bf21c6 GIT binary patch literal 2017 zcmaJ?dsGu=77vDpP##N5KwRujauqwLcuPp-=)8NzxQ@jU*r5TyOII;!$=9xr7rkHL(^q5O%Ec!W5}|#us^tryB{vB4n}bc01F~W#ZNh76`*Ii_KwiI1EyQVcTLRv<`;Z zws6*h6ty8%%tBze8E{+F>hR4(Je_3vG6a)FseEPFY@10GnKG6`Yhi&*Hp^sk$2F~O zBT~@+(|Dt{Ep>|pWu>4te6tlH>tR?p3np{-+m76dBpcxxD@GPYn4joQAV}o!VL>7&ka0mUQ6iB^VHsZ_=L+}|m^W+VO;{c*Ct*^qI1!8mK^adV zm++*J1QNrsFi#9hX0ZyhjnJAAbk;9M`kldYeiJK{SWzv3TT^j7YqkTDjW~hZjJO4m zNTw?eL@KoiW_Ams+(mjBvlO*rpQ3uX6*mFXSr%e%U||qw5k#lcGaw#fVDJnu$k4@V z1q>b!k|N99IIlI*tcdJR_x9CTkcU@;g__A}vXWy%^{U@QPUAC$RGjJ<7~YR1 z(LM<2{8`bMwn+A@CRcWd{^tv2ziQr-R)*6Waf8e#uLzDzyjCjzLocV+82lM+hnKu^ zcQP}ztN<-oyx*Xe)f}Dbi)*)>w%_c2(vy?x@YyPO^6zGD-spAP{p;LPr*lqEapUj( zy;pSy?kp*RvPN&qK7oOQyC$6T#=dP13;4xZ2Ue%NUmD{lqBcx2*b78+?k+a*iVJ`s z;>pQYL9$2h>ZczC9CYeWdyRWURfkl0+zI`D+{Z@@#r4i@pf2!Z1$tB4)a>vtJTF%l zR}PhL^Je#*Yc6g>($5Ah4-oxYxmv?1uI?WW%&tGRHT0|R6?J=daoYlm?^d>Ej=lSt z$1O3fVE;YM#<+-k%w;Xb-`z^_h(GX==HSJlr@E(ClN#0y)zrOR_pa1$aNvj&xf5Zz z*pYLlZhq}8=L8V8arX(k=h1e2@BTu~!hPO5_BGe6yuId9_t2sIu)N??=QBGlZ0P&X z?qwkZU9HgxOO7`<#<8Q%y=#W6zG?4%kNtV`UgjQ8*SEnd#yw(?V_#c1Ntcg(ffz$X zc3vD>RW48mwPe>BwjTG{Gvdi=3ubpK+b<;!^%S-KE-38ew##4PbN&gp;?xcrA{kj3 z+MVWkty3X|;#52Ts?s%;XtEzvY`;Gm9#V4kM$o38wl$_L*SvODPkDJqjW23xX&OFQ z3aI*ILyxHWZB^EX_U(rzm*kfeDNo#3=aca02Xvw$^lkNGY~DR;{;Gl}zV+6*zGtGb zeO((=r?Ub^k3S1#JhV5MyoVOO^BV9ZB zD+`>b3SKmP*gF+F{tu=2J7wdMkIM$VcK@{9cjKeluz}k8ievNk9tpaVI@VwPAc@XW z*Ty_RHYDIzY>RTA8(jwub^pT7DIcudUUXvxjjD5WEO;mf&aXM#o?>xloy8nqEG#NRq4o;rmGq`mzI9G zDQ51!bWkPizXWqdpXmz4Tq~Q0b1n+U&XowF%b3Z9+&`JiA1{sUs1EwDws*_qrGfcf zyOyr!y58z72K)!BZeH-2S|{nBNDcjA1Um58zGr>J)F7>}sMB{SAdvgF#8BP&dN>$1 zWyqBtvHn%{>>Vx9AKVcsCY~?-oDnq@SLfuGeau&twN7?T9)CaT{)&nv`c8dkzry<8 rKPuOH|Geuj5ovTmH?Qe=d!FY!$~MI{Mn5HQv-_v3kg24uM2+)*;368^ literal 0 HcmV?d00001 diff --git a/public/images/social/facebook.png b/public/images/social/facebook.png new file mode 100644 index 0000000000000000000000000000000000000000..1e6ed054a88dee0061fce72199d5d4b837d6b954 GIT binary patch literal 229 zcmV^P)g3IT#KY4vr`BO#2 zThL0f_zVlsig!RObXq~8k8V7GUU)5f=Uy*Jt#gIXF}as@_8bW12|5)hYChfn4RrCf fwSLcb`or)674U;APu!Bf00000NkvXXu0mjfffZb5 literal 0 HcmV?d00001 diff --git a/public/images/social/facebook.svg b/public/images/social/facebook.svg new file mode 100644 index 000000000000..edf8fb6056e4 --- /dev/null +++ b/public/images/social/facebook.svg @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/public/images/social/github.png b/public/images/social/github.png new file mode 100644 index 0000000000000000000000000000000000000000..2947ac1abf593393b513915d6078a8f3eb613930 GIT binary patch literal 457 zcmV;)0XF`LP)V7}?yyou0BztB7y;km83nDaWdWq`GB9OzOo6iZdRPNk zkUthcBZgEQWS9dobg+sfSpYpq+6mlkGkXQjL;gPKyOJ=o3!o_JCFqZ4RuRyNW-Ix1 z1IqX=MV^j;z7yV*Gk}@%^#x3vaPkk(iStboNi~YsUh5(FrtjEUg)NdIDPM&I31Ld<7f=YtFn590AwBR|IOMMS~z5I2fVv z(wgFuE+6;?+XCjmQ_zlqy^JNjN052&Dls#e*-TPZQUQ3Dv@hv&#a7KFRn2Vnd(!S2 z*#vIGY@Zo_^bvA*z((dZ5&`Q#HzVH#>REsv&E8K$&23w@00000NkvXXu0mjfl{vGA literal 0 HcmV?d00001 diff --git a/public/images/social/twitter.png b/public/images/social/twitter.png new file mode 100644 index 0000000000000000000000000000000000000000..76812e3d94930a9c631af0ab254730e83d617bc5 GIT binary patch literal 307 zcmeAS@N?(olHy`uVBq!ia0vp^!ayv*!3-o1OKk}NQXT<5A+A9BKQ+Mfii!pc{xLp^4QG98&5*gK m`v1*u#j=tNOZyGA82;A=vr2By + + + \ No newline at end of file diff --git a/public/js/built.public.js b/public/js/built.public.js index c6997eccc9be..d839865900c1 100644 --- a/public/js/built.public.js +++ b/public/js/built.public.js @@ -1,23 +1,7 @@ -/* Copyright (C) 2012 Sylvain Hamel -Project: https://github.com/redhotsly/simple-expand -MIT Licence: https://raw.github.com/redhotsly/simple-expand/master/licence-mit.txt */ -(function($){"use strict";function SimpleExpand(){var that=this;that.defaults={hideMode:"fadeToggle",defaultSearchMode:"parent",defaultTarget:".content",throwOnMissingTarget:true,keepStateInCookie:false,cookieName:"simple-expand"};that.settings={};$.extend(that.settings,that.defaults);that.findLevelOneDeep=function(parent,filterSelector,stopAtSelector){return parent.find(filterSelector).filter(function(){return!$(this).parentsUntil(parent,stopAtSelector).length})};that.setInitialState=function(expander,targets){var isExpanded=that.readState(expander);if(isExpanded){expander.removeClass("collapsed").addClass("expanded");that.show(targets)}else{expander.removeClass("expanded").addClass("collapsed");that.hide(targets)}};that.hide=function(targets){if(that.settings.hideMode==="fadeToggle"){targets.hide()}else if(that.settings.hideMode==="basic"){targets.hide()}};that.show=function(targets){if(that.settings.hideMode==="fadeToggle"){targets.show()}else if(that.settings.hideMode==="basic"){targets.show()}};that.checkKeepStateInCookiePreconditions=function(){if(that.settings.keepStateInCookie&&$.cookie===undefined){throw new Error("simple-expand: keepStateInCookie option requires $.cookie to be defined.")}};that.readCookie=function(){var jsonString=$.cookie(that.settings.cookieName);if(jsonString===null||jsonString===""){return{}}else{return JSON.parse(jsonString)}};that.readState=function(expander){if(!that.settings.keepStateInCookie){return expander.hasClass("expanded")}var id=expander.attr("Id");if(id===undefined){return}var cookie=that.readCookie();var cookieValue=cookie[id];if(typeof cookieValue!=="undefined"){return cookie[id]===true}else{return expander.hasClass("expanded")}};that.saveState=function(expander,isExpanded){if(!that.settings.keepStateInCookie){return}var id=expander.attr("Id");if(id===undefined){return}var cookie=that.readCookie();cookie[id]=isExpanded;$.cookie(that.settings.cookieName,JSON.stringify(cookie),{raw:true,path:window.location.pathname})};that.toggle=function(expander,targets){var isExpanded=that.toggleCss(expander);if(that.settings.hideMode==="fadeToggle"){targets.fadeToggle(150)}else if(that.settings.hideMode==="basic"){targets.toggle()}else if($.isFunction(that.settings.hideMode)){that.settings.hideMode(expander,targets,isExpanded)}that.saveState(expander,isExpanded);return false};that.toggleCss=function(expander){if(expander.hasClass("expanded")){expander.toggleClass("collapsed expanded");return false}else{expander.toggleClass("expanded collapsed");return true}};that.findTargets=function(expander,searchMode,targetSelector){var targets=[];if(searchMode==="absolute"){targets=$(targetSelector)}else if(searchMode==="relative"){targets=that.findLevelOneDeep(expander,targetSelector,targetSelector)}else if(searchMode==="parent"){var parent=expander.parent();do{targets=that.findLevelOneDeep(parent,targetSelector,targetSelector);if(targets.length===0){parent=parent.parent()}}while(targets.length===0&&parent.length!==0)}return targets};that.activate=function(jquery,options){$.extend(that.settings,options);that.checkKeepStateInCookiePreconditions();jquery.each(function(){var expander=$(this);var targetSelector=expander.attr("data-expander-target")||that.settings.defaultTarget;var searchMode=expander.attr("data-expander-target-search")||that.settings.defaultSearchMode;var targets=that.findTargets(expander,searchMode,targetSelector);if(targets.length===0){if(that.settings.throwOnMissingTarget){throw"simple-expand: Targets not found"}return this}that.setInitialState(expander,targets);expander.click(function(){return that.toggle(expander,targets)})})}}window.SimpleExpand=SimpleExpand;$.fn.simpleexpand=function(options){var instance=new SimpleExpand;instance.activate(this,options);return this}})(jQuery); -(function ($) { -$.fn.vAlign = function() { - return this.each(function(i){ - $(this).children().wrapAll('
'); - var div = $(this).children('div.nitinh-vAlign'); - var ph = $(this).innerHeight(); - var dh = div.height(); - var mh = (ph - dh) / 2; - div.css('top', mh); - }); -}; -})(jQuery); /*! - * Bootstrap v3.1.1 (http://getbootstrap.com) + * Bootstrap v3.3.1 (http://getbootstrap.com) * Copyright 2011-2014 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) */ - -+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d),this.transitioning=null,this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};b.DEFAULTS={toggle:!0},b.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},b.prototype.show=function(){if(this.transitioning||this.$element.hasClass("in"))return;var b=a.Event("show.bs.collapse");this.$element.trigger(b);if(b.isDefaultPrevented())return;var c=this.$parent&&this.$parent.find("> .panel > .in");if(c&&c.length){var d=c.data("bs.collapse");if(d&&d.transitioning)return;c.collapse("hide"),d||c.data("bs.collapse",null)}var e=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[e](0),this.transitioning=1;var f=function(){this.$element.removeClass("collapsing").addClass("collapse in")[e]("auto"),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return f.call(this);var g=a.camelCase(["scroll",e].join("-"));this.$element.one(a.support.transition.end,a.proxy(f,this)).emulateTransitionEnd(350)[e](this.$element[0][g])},b.prototype.hide=function(){if(this.transitioning||!this.$element.hasClass("in"))return;var b=a.Event("hide.bs.collapse");this.$element.trigger(b);if(b.isDefaultPrevented())return;var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse").removeClass("in"),this.transitioning=1;var d=function(){this.transitioning=0,this.$element.trigger("hidden.bs.collapse").removeClass("collapsing").addClass("collapse")};if(!a.support.transition)return d.call(this);this.$element[c](0).one(a.support.transition.end,a.proxy(d,this)).emulateTransitionEnd(350)},b.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()};var c=a.fn.collapse;a.fn.collapse=function(c){return this.each(function(){var d=a(this),e=d.data("bs.collapse"),f=a.extend({},b.DEFAULTS,d.data(),typeof c=="object"&&c);!e&&f.toggle&&c=="show"&&(c=!c),e||d.data("bs.collapse",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.collapse.Constructor=b,a.fn.collapse.noConflict=function(){return a.fn.collapse=c,this},a(document).on("click.bs.collapse.data-api","[data-toggle=collapse]",function(b){var c=a(this),d,e=c.attr("data-target")||b.preventDefault()||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""),f=a(e),g=f.data("bs.collapse"),h=g?"toggle":c.data(),i=c.attr("data-parent"),j=i&&a(i);if(!g||!g.transitioning)j&&j.find('[data-toggle=collapse][data-parent="'+i+'"]').not(c).addClass("collapsed"),c[f.hasClass("in")?"addClass":"removeClass"]("collapsed");f.collapse(h)})}(jQuery),+function(a){function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(a.style[c]!==undefined)return{end:b[c]};return!1}"use strict",a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one(a.support.transition.end,function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b()})}(jQuery) \ No newline at end of file +if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.1",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.1",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active"));a&&this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.1",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c="prev"==a?-1:1,d=this.getItemIndex(b),e=(d+c)%this.$items.length;return this.$items.eq(e)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i="next"==b?"first":"last",j=this;if(!f.length){if(!this.options.wrap)return;f=this.$element.find(".item")[i]()}if(f.hasClass("active"))return this.sliding=!1;var k=f[0],l=a.Event("slide.bs.carousel",{relatedTarget:k,direction:h});if(this.$element.trigger(l),!l.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var m=a(this.$indicators.children()[this.getItemIndex(f)]);m&&m.addClass("active")}var n=a.Event("slid.bs.carousel",{relatedTarget:k,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),j.sliding=!1,setTimeout(function(){j.$element.trigger(n)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(n)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&"show"==b&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a(this.options.trigger).filter('[href="#'+b.id+'"], [data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.1",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0,trigger:'[data-toggle="collapse"]'},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.find("> .panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":a.extend({},e.data(),{trigger:this});c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){b&&3===b.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=c(d),f={relatedTarget:this};e.hasClass("open")&&(e.trigger(b=a.Event("hide.bs.dropdown",f)),b.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger("hidden.bs.dropdown",f)))}))}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.1",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('
+ @if (Request::secure() || Utils::isNinjaDev())

{{ trans('texts.secure_payment') }}

{{ trans('texts.256_encryption') }}
+ @endif
diff --git a/app/views/public/header.blade.php b/app/views/public/header.blade.php index efbd742ef540..480b7b25a404 100644 --- a/app/views/public/header.blade.php +++ b/app/views/public/header.blade.php @@ -8,6 +8,7 @@ body { font-family: 'Roboto', sans-serif; + font-size: 14px; } From 5f6cb538377462e27f06a55b65097d063a097593 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Thu, 19 Feb 2015 12:35:46 +0200 Subject: [PATCH 11/32] Style fixes --- app/views/accounts/payments.blade.php | 21 ------------ app/views/payments/payment.blade.php | 46 +++++++++++++-------------- public/built.css | 17 +++++++++- public/built.js | 5 --- public/css/style.css | 17 +++++++++- 5 files changed, 55 insertions(+), 51 deletions(-) diff --git a/app/views/accounts/payments.blade.php b/app/views/accounts/payments.blade.php index 01d91b14ee02..a47ba1ce2cab 100755 --- a/app/views/accounts/payments.blade.php +++ b/app/views/accounts/payments.blade.php @@ -1,26 +1,5 @@ @extends('accounts.nav') -@section('head') - @parent - - - -@stop - @section('content') @parent diff --git a/app/views/payments/payment.blade.php b/app/views/payments/payment.blade.php index 62b56f727700..13debcf3732c 100755 --- a/app/views/payments/payment.blade.php +++ b/app/views/payments/payment.blade.php @@ -50,8 +50,8 @@ header { } .panel-body { - padding-left: 100px; - padding-right: 100px; + padding-left: 150px; + padding-right: 150px; } } @@ -166,16 +166,16 @@ header h3 em {

{{ trans('texts.contact_information') }}

-
+
{{ Former::text('first_name')->placeholder(trans('texts.first_name'))->raw() }}
-
+
{{ Former::text('last_name')->placeholder(trans('texts.last_name'))->raw() }}
@if (isset($paymentTitle))
-
+
{{ Former::text('email')->placeholder(trans('texts.email'))->raw() }}
@@ -183,39 +183,42 @@ header h3 em {

 
 

-

{{ trans('texts.billing_address') }}

+

{{ trans('texts.billing_address') }}  {{ trans('texts.payment_footer1') }}

-
+
{{ Former::text('address1')->placeholder(trans('texts.address1'))->raw() }}
-
+
{{ Former::text('address2')->placeholder(trans('texts.address2'))->raw() }}
-
+
{{ Former::text('city')->placeholder(trans('texts.city'))->raw() }}
-
+
{{ Former::text('state')->placeholder(trans('texts.state'))->raw() }}
-
+
{{ Former::text('postal_code')->placeholder(trans('texts.postal_code'))->raw() }}

 
 

-

{{ trans('texts.billing_method') }}  {{ trans('texts.match_address') }}

+

{{ trans('texts.billing_method') }}

-
+
{{ Former::text('card_number')->placeholder(trans('texts.card_number'))->raw() }}
+
+ {{ Former::text('cvv')->placeholder(trans('texts.cvv'))->raw() }} +
-
+
{{ Former::select('expiration_month')->placeholder(trans('texts.expiration_month')) ->addOption('01 - January', '1') ->addOption('02 - February', '2') @@ -231,7 +234,7 @@ header h3 em { ->addOption('12 - December', '12')->raw(); }}
-
+
{{ Former::select('expiration_year')->placeholder(trans('texts.expiration_year')) ->addOption('2014', '2014') ->addOption('2015', '2015') @@ -242,22 +245,19 @@ header h3 em { ->addOption('2020', '2020')->raw(); }}
-
- {{ Former::text('cvv')->placeholder(trans('texts.cvv'))->raw() }} -
-
+
@if ($account->showTokenCheckbox()) - selectTokenCheckbox() ? 'CHECKED' : '' }} value="1" style="margin-left:0px; vertical-align:text-top"> - + selectTokenCheckbox() ? 'CHECKED' : '' }} value="1" style="margin-left:0px; vertical-align:top"> + {{ trans('texts.token_billing_secure', ['stripe_link' => link_to('https://stripe.com/', 'Stripe.com', ['target' => '_blank'])]) }} @endif
-
+
@if (isset($acceptedCreditCardTypes))
@foreach ($acceptedCreditCardTypes as $card) @@ -272,7 +272,7 @@ header h3 em {

 
 

-
+
{{ Button::block_success_submit_lg(strtoupper(trans('texts.pay_now') . ' - ' . Utils::formatMoney($amount, $currencyId) )) }}
diff --git a/public/built.css b/public/built.css index 159952ef228b..ec54314db7d6 100644 --- a/public/built.css +++ b/public/built.css @@ -2892,4 +2892,19 @@ table.table thead .sorting_asc_disabled:after { content: '' !important } table.table thead .sorting_desc_disabled:after { content: '' !important } /* Prevent modal from shifting page a bit - https://github.com/twbs/bootstrap/issues/9886 */ -body.modal-open { overflow:inherit; padding-right:inherit !important; } \ No newline at end of file +body.modal-open { overflow:inherit; padding-right:inherit !important; } + + +/* bootstrap 3.2.0 fix */ +/* https://github.com/twbs/bootstrap/issues/13984 */ +.radio input[type="radio"], +.checkbox input[type="checkbox"] { + margin-left: 0; + margin-right: 5px; + height: inherit; + width: inherit; + float: left; + display: inline-block; + position: relative; + margin-top: 3px; +} diff --git a/public/built.js b/public/built.js index b526de7baa0e..2ab5710bea95 100644 --- a/public/built.js +++ b/public/built.js @@ -33013,11 +33013,6 @@ function setDocHexDraw(doc, hex) { return doc.setDrawColor(r, g, b); } -function openUrl(url, track) { - trackUrl(track ? track : url); - window.open(url, '_blank'); -} - function toggleDatePicker(field) { $('#'+field).datepicker('show'); } diff --git a/public/css/style.css b/public/css/style.css index 53eec512662f..963e607370c6 100755 --- a/public/css/style.css +++ b/public/css/style.css @@ -784,4 +784,19 @@ table.table thead .sorting_asc_disabled:after { content: '' !important } table.table thead .sorting_desc_disabled:after { content: '' !important } /* Prevent modal from shifting page a bit - https://github.com/twbs/bootstrap/issues/9886 */ -body.modal-open { overflow:inherit; padding-right:inherit !important; } \ No newline at end of file +body.modal-open { overflow:inherit; padding-right:inherit !important; } + + +/* bootstrap 3.2.0 fix */ +/* https://github.com/twbs/bootstrap/issues/13984 */ +.radio input[type="radio"], +.checkbox input[type="checkbox"] { + margin-left: 0; + margin-right: 5px; + height: inherit; + width: inherit; + float: left; + display: inline-block; + position: relative; + margin-top: 3px; +} From 4cc885b20f9dc596e97d23f902f41870deacbf50 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Thu, 19 Feb 2015 12:40:29 +0200 Subject: [PATCH 12/32] Style fixes --- app/views/payments/payment.blade.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/views/payments/payment.blade.php b/app/views/payments/payment.blade.php index 13debcf3732c..5e90fa725ae2 100755 --- a/app/views/payments/payment.blade.php +++ b/app/views/payments/payment.blade.php @@ -301,4 +301,14 @@ header h3 em { {{ Former::close() }} + + @stop \ No newline at end of file From 1f47acb8ae755a4ad90bb79bcf332b7100d2cb93 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Thu, 19 Feb 2015 12:42:13 +0200 Subject: [PATCH 13/32] Style fixes --- app/views/invoices/edit.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/invoices/edit.blade.php b/app/views/invoices/edit.blade.php index c7c1b6242fda..143650ff1d49 100755 --- a/app/views/invoices/edit.blade.php +++ b/app/views/invoices/edit.blade.php @@ -31,7 +31,7 @@ @if ($invoice && $invoice->id)
-
+
From ca3abb3e5661cea9e634c6b69b6ce41359130807 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Sun, 22 Feb 2015 23:07:38 +0200 Subject: [PATCH 14/32] Changed payment page to charge invoice balance rather than full amount --- app/controllers/PaymentController.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/controllers/PaymentController.php b/app/controllers/PaymentController.php index bfbf7c1c2dce..1d3f0aedc290 100755 --- a/app/controllers/PaymentController.php +++ b/app/controllers/PaymentController.php @@ -236,7 +236,7 @@ class PaymentController extends \BaseController 'city' => $input['city'], 'state' => $input['state'], 'postal_code' => $input['postal_code'], - 'amt' => $invoice->amount, + 'amt' => $invoice->balance, 'ship_to_street' => $input['address1'], 'ship_to_city' => $input['city'], 'ship_to_state' => $input['state'], @@ -273,7 +273,7 @@ class PaymentController extends \BaseController $card = new CreditCard($data); return [ - 'amount' => $invoice->amount, + 'amount' => $invoice->balance, 'card' => $card, 'currency' => $currencyCode, 'returnUrl' => URL::to('complete'), @@ -313,7 +313,7 @@ class PaymentController extends \BaseController $data = [ 'showBreadcrumbs' => false, 'url' => 'payment/'.$invitationKey, - 'amount' => $invoice->amount, + 'amount' => $invoice->balance, 'invoiceNumber' => $invoice->invoice_number, 'client' => $client, 'contact' => $invitation->contact, @@ -645,7 +645,7 @@ class PaymentController extends \BaseController $payment->invitation_id = $invitation->id; $payment->account_gateway_id = $accountGateway->id; $payment->invoice_id = $invoice->id; - $payment->amount = $invoice->amount; + $payment->amount = $invoice->balance; $payment->client_id = $invoice->client_id; $payment->contact_id = $invitation->contact_id; $payment->transaction_reference = $ref; From 3a06647336ef70bd463174baf2d7ef55f41cb026 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Mon, 23 Feb 2015 21:17:15 +0200 Subject: [PATCH 15/32] Fixed issue when deleting recurring invoice --- app/models/Activity.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/models/Activity.php b/app/models/Activity.php index fbaac9ac4507..a22fe1e1a2ee 100755 --- a/app/models/Activity.php +++ b/app/models/Activity.php @@ -157,7 +157,9 @@ class Activity extends Eloquent $client = $invoice->client; if ($invoice->is_deleted && !$invoice->getOriginal('is_deleted')) { + $adjustment = 0; if (!$invoice->is_quote && !$invoice->is_recurring) { + $adjustment = $invoice->balance * -1; $client->balance = $client->balance - $invoice->balance; $client->paid_to_date = $client->paid_to_date - ($invoice->amount - $invoice->balance); $client->save(); @@ -169,7 +171,7 @@ class Activity extends Eloquent $activity->activity_type_id = $invoice->is_quote ? ACTIVITY_TYPE_DELETE_QUOTE : ACTIVITY_TYPE_DELETE_INVOICE; $activity->message = Utils::encodeActivity(Auth::user(), 'deleted', $invoice); $activity->balance = $invoice->client->balance; - $activity->adjustment = $invoice->is_quote ? 0 : $invoice->balance * -1; + $activity->adjustment = $adjustment; $activity->save(); } else { $diff = floatval($invoice->amount) - floatval($invoice->getOriginal('amount')); From 82172751dd7cd00a89ad71b93cae6117e0bdaa33 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Mon, 23 Feb 2015 21:17:45 +0200 Subject: [PATCH 16/32] Added years to the expiration select --- app/views/payments/payment.blade.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/views/payments/payment.blade.php b/app/views/payments/payment.blade.php index 5e90fa725ae2..4f6c6661e912 100755 --- a/app/views/payments/payment.blade.php +++ b/app/views/payments/payment.blade.php @@ -242,7 +242,11 @@ header h3 em { ->addOption('2017', '2017') ->addOption('2018', '2018') ->addOption('2019', '2019') - ->addOption('2020', '2020')->raw(); + ->addOption('2020', '2020') + ->addOption('2021', '2021') + ->addOption('2022', '2022') + ->addOption('2023', '2023') + ->addOption('2024', '2024')->raw(); }}
From 9d240480ccec34cf4b10c893fbdbc0731d23521f Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Thu, 26 Feb 2015 00:11:00 +0200 Subject: [PATCH 17/32] Bug fixes and check-data script --- app/commands/CheckData.php | 266 +++++++++++++++++++ app/commands/SendRecurringInvoices.php | 9 +- app/controllers/PaymentController.php | 2 +- app/models/Activity.php | 1 + app/ninja/repositories/PaymentRepository.php | 6 +- app/routes.php | 60 ++--- app/start/artisan.php | 1 + app/views/invoices/edit.blade.php | 8 +- app/views/invoices/view.blade.php | 2 +- 9 files changed, 316 insertions(+), 39 deletions(-) create mode 100644 app/commands/CheckData.php diff --git a/app/commands/CheckData.php b/app/commands/CheckData.php new file mode 100644 index 000000000000..f2a0610f632a --- /dev/null +++ b/app/commands/CheckData.php @@ -0,0 +1,266 @@ + + + Limits the script to a single client + +--fix=true + + By default the script only checks for errors, adding this option + makes the script apply the fixes. + +*/ + + +class CheckData extends Command { + + protected $name = 'ninja:check-data'; + protected $description = 'Check/fix data'; + + public function fire() + { + $this->info(date('Y-m-d') . ' Running CheckData...'); + $today = new DateTime(); + + if (!$this->option('client_id')) { + // update client deletion activities with the client's current balance + $activities = DB::table('activities') + ->join('clients', 'clients.id', '=', 'activities.client_id') + ->where('activities.activity_type_id', '=', ACTIVITY_TYPE_DELETE_CLIENT) + ->where('activities.balance', '=', 0) + ->where('clients.balance', '!=', 0) + ->get(['activities.id', 'clients.balance']); + + $this->info(count($activities) . ' delete client activities with zero balance'); + + if ($this->option('fix') == 'true') { + foreach ($activities as $activity) { + DB::table('activities') + ->where('id', $activity->id) + ->update(['balance' => $activity->balance]); + } + } + + // update client paid_to_date value + $clients = DB::table('clients') + ->join('payments', 'payments.client_id', '=', 'clients.id') + ->join('invoices', 'invoices.id', '=', 'payments.invoice_id') + ->where('payments.is_deleted', '=', 0) + ->where('invoices.is_deleted', '=', 0) + ->groupBy('clients.id') + ->havingRaw('clients.paid_to_date != sum(payments.amount) and clients.paid_to_date != 999999999.9999') + ->get(['clients.id', 'clients.paid_to_date', DB::raw('sum(payments.amount) as amount')]); + $this->info(count($clients) . ' clients with incorrect paid to date'); + + if ($this->option('fix') == 'true') { + foreach ($clients as $client) { + DB::table('clients') + ->where('id', $client->id) + ->update(['paid_to_date' => $client->amount]); + } + } + } + + // find all clients where the balance doesn't equal the sum of the outstanding invoices + $clients = DB::table('clients') + ->join('invoices', 'invoices.client_id', '=', 'clients.id') + ->join('accounts', 'accounts.id', '=', 'clients.account_id'); + + if ($this->option('client_id')) { + $clients->where('clients.id', '=', $this->option('client_id')); + } else { + $clients->where('invoices.is_deleted', '=', 0) + ->where('invoices.is_quote', '=', 0) + ->where('invoices.is_recurring', '=', 0) + ->havingRaw('abs(clients.balance - sum(invoices.balance)) > .01 and clients.balance != 999999999.9999'); + } + + $clients = $clients->groupBy('clients.id', 'clients.balance', 'clients.created_at') + ->orderBy('clients.id', 'DESC') + ->get(['clients.id', 'clients.balance', 'clients.paid_to_date']); + $this->info(count($clients) . ' clients with incorrect balance/activities'); + + foreach ($clients as $client) { + $this->info("=== Client:{$client->id} Balance:{$client->balance} ==="); + $foundProblem = false; + $lastBalance = 0; + $clientFix = false; + $activities = DB::table('activities') + ->where('client_id', '=', $client->id) + ->orderBy('activities.id') + ->get(['activities.id', 'activities.created_at', 'activities.activity_type_id', 'activities.message', 'activities.adjustment', 'activities.balance', 'activities.invoice_id']); + //$this->info(var_dump($activities)); + + foreach ($activities as $activity) { + + $activityFix = false; + + if ($activity->invoice_id) { + $invoice = DB::table('invoices') + ->where('id', '=', $activity->invoice_id) + ->first(['invoices.amount', 'invoices.is_recurring', 'invoices.is_quote', 'invoices.deleted_at', 'invoices.id', 'invoices.is_deleted']); + + // Check if this invoice was once set as recurring invoice + if (!$invoice->is_recurring && DB::table('invoices') + ->where('recurring_invoice_id', '=', $activity->invoice_id) + ->first(['invoices.id'])) { + $invoice->is_recurring = 1; + + // **Fix for enabling a recurring invoice to be set as non-recurring** + if ($this->option('fix') == 'true') { + DB::table('invoices') + ->where('id', $invoice->id) + ->update(['is_recurring' => 1]); + } + } + } + + + if ($activity->activity_type_id == ACTIVITY_TYPE_CREATE_INVOICE + || $activity->activity_type_id == ACTIVITY_TYPE_CREATE_QUOTE) { + + // Get original invoice amount + $update = DB::table('activities') + ->where('invoice_id', '=', $activity->invoice_id) + ->where('activity_type_id', '=', ACTIVITY_TYPE_UPDATE_INVOICE) + ->orderBy('id') + ->first(['json_backup']); + if ($update) { + $backup = json_decode($update->json_backup); + $invoice->amount = floatval($backup->amount); + } + + $noAdjustment = $activity->activity_type_id == ACTIVITY_TYPE_CREATE_INVOICE + && $activity->adjustment == 0 + && $invoice->amount > 0; + + // **Fix for allowing converting a recurring invoice to a normal one without updating the balance** + if ($noAdjustment && !$invoice->is_quote && !$invoice->is_recurring) { + $this->info("No adjustment for new invoice:{$activity->invoice_id} amount:{$invoice->amount} isQuote:{$invoice->is_quote} isRecurring:{$invoice->is_recurring}"); + $foundProblem = true; + $clientFix += $invoice->amount; + $activityFix = $invoice->amount; + // **Fix for updating balance when creating a quote or recurring invoice** + } elseif ($activity->adjustment != 0 && ($invoice->is_quote || $invoice->is_recurring)) { + $this->info("Incorrect adjustment for new invoice:{$activity->invoice_id} adjustment:{$activity->adjustment} isQuote:{$invoice->is_quote} isRecurring:{$invoice->is_recurring}"); + $foundProblem = true; + $clientFix -= $activity->adjustment; + $activityFix = 0; + } + } elseif ($activity->activity_type_id == ACTIVITY_TYPE_DELETE_INVOICE) { + // **Fix for updating balance when deleting a recurring invoice** + if ($activity->adjustment != 0 && $invoice->is_recurring) { + $this->info("Incorrect adjustment for deleted invoice adjustment:{$activity->adjustment}"); + $foundProblem = true; + if ($activity->balance != $lastBalance) { + $clientFix -= $activity->adjustment; + } + $activityFix = 0; + } + } elseif ($activity->activity_type_id == ACTIVITY_TYPE_ARCHIVE_INVOICE) { + // **Fix for updating balance when archiving an invoice** + if ($activity->adjustment != 0 && !$invoice->is_recurring) { + $this->info("Incorrect adjustment for archiving invoice adjustment:{$activity->adjustment}"); + $foundProblem = true; + $activityFix = 0; + $clientFix += $activity->adjustment; + } + } elseif ($activity->activity_type_id == ACTIVITY_TYPE_UPDATE_INVOICE) { + // **Fix for updating balance when updating recurring invoice** + if ($activity->adjustment != 0 && $invoice->is_recurring) { + $this->info("Incorrect adjustment for updated recurring invoice adjustment:{$activity->adjustment}"); + $foundProblem = true; + $clientFix -= $activity->adjustment; + $activityFix = 0; + } + } elseif ($activity->activity_type_id == ACTIVITY_TYPE_UPDATE_QUOTE) { + // **Fix for updating balance when updating a quote** + if ($activity->balance != $lastBalance) { + $this->info("Incorrect adjustment for updated quote adjustment:{$activity->adjustment}"); + $foundProblem = true; + $clientFix += $lastBalance - $activity->balance; + $activityFix = 0; + } + } else if ($activity->activity_type_id == ACTIVITY_TYPE_DELETE_PAYMENT) { + // **Fix for delting payment after deleting invoice** + if ($activity->adjustment != 0 && $invoice->is_deleted && $activity->created_at > $invoice->deleted_at) { + $this->info("Incorrect adjustment for deleted payment adjustment:{$activity->adjustment}"); + $foundProblem = true; + $activityFix = 0; + $clientFix -= $activity->adjustment; + } + } + + if ($activityFix !== false || $clientFix !== false) { + $data = [ + 'balance' => $activity->balance + $clientFix + ]; + + if ($activityFix !== false) { + $data['adjustment'] = $activityFix; + } + + if ($this->option('fix') == 'true') { + DB::table('activities') + ->where('id', $activity->id) + ->update($data); + } + } + + $lastBalance = $activity->balance; + } + + if ($clientFix !== false) { + $balance = $activity->balance + $clientFix; + $data = ['balance' => $balance]; + $this->info("Corrected balance:{$balance}"); + if ($this->option('fix') == 'true') { + DB::table('clients') + ->where('id', $client->id) + ->update($data); + } + } + } + + $this->info('Done'); + } + + protected function getArguments() + { + return array( + //array('example', InputArgument::REQUIRED, 'An example argument.'), + ); + } + + protected function getOptions() + { + return array( + array('fix', null, InputOption::VALUE_OPTIONAL, 'Fix data', null), + array('client_id', null, InputOption::VALUE_OPTIONAL, 'Client id', null), + ); + } + +} \ No newline at end of file diff --git a/app/commands/SendRecurringInvoices.php b/app/commands/SendRecurringInvoices.php index a3e86af027c9..35c8ef219d2f 100755 --- a/app/commands/SendRecurringInvoices.php +++ b/app/commands/SendRecurringInvoices.php @@ -23,7 +23,7 @@ class SendRecurringInvoices extends Command { $this->info(date('Y-m-d') . ' Running SendRecurringInvoices...'); $today = new DateTime(); - $invoices = Invoice::with('account.timezone', 'invoice_items', 'client') + $invoices = Invoice::with('account.timezone', 'invoice_items', 'client', 'user') ->whereRaw('is_deleted IS FALSE AND deleted_at IS NULL AND is_recurring IS TRUE AND start_date <= ? AND (end_date IS NULL OR end_date >= ?)', array($today, $today))->get(); $this->info(count($invoices) . ' recurring invoice(s) found'); @@ -34,7 +34,12 @@ class SendRecurringInvoices extends Command { continue; } - date_default_timezone_set($recurInvoice->account->getTimezone()); + if (!$recurInvoice->user->confirmed) + { + continue; + } + + date_default_timezone_set($recurInvoice->account->getTimezone()); $this->info('Processing Invoice ' . $recurInvoice->id . ' - Should send ' . ($recurInvoice->shouldSendToday() ? 'YES' : 'NO')); diff --git a/app/controllers/PaymentController.php b/app/controllers/PaymentController.php index 1d3f0aedc290..5765861a1535 100755 --- a/app/controllers/PaymentController.php +++ b/app/controllers/PaymentController.php @@ -59,7 +59,7 @@ class PaymentController extends \BaseController return $table->addColumn('amount', function ($model) { return Utils::formatMoney($model->amount, $model->currency_id); }) ->addColumn('payment_date', function ($model) { return Utils::dateToString($model->payment_date); }) ->addColumn('dropdown', function ($model) { - if ($model->is_deleted) { + if ($model->is_deleted || $model->invoice_is_deleted) { return '
'; } diff --git a/app/models/Activity.php b/app/models/Activity.php index a22fe1e1a2ee..f15506d435cd 100755 --- a/app/models/Activity.php +++ b/app/models/Activity.php @@ -57,6 +57,7 @@ class Activity extends Eloquent $activity->client_id = $client->id; $activity->activity_type_id = ACTIVITY_TYPE_DELETE_CLIENT; $activity->message = Utils::encodeActivity(Auth::user(), 'deleted', $client); + $activity->balance = $client->balance; $activity->save(); } } diff --git a/app/ninja/repositories/PaymentRepository.php b/app/ninja/repositories/PaymentRepository.php index f47019b165e7..e7e986db374b 100755 --- a/app/ninja/repositories/PaymentRepository.php +++ b/app/ninja/repositories/PaymentRepository.php @@ -19,10 +19,11 @@ class PaymentRepository ->where('clients.deleted_at', '=', null) ->where('contacts.is_primary', '=', true) ->where('contacts.deleted_at', '=', null) - ->select('payments.public_id', 'payments.transaction_reference', 'clients.name as client_name', 'clients.public_id as client_public_id', 'payments.amount', 'payments.payment_date', 'invoices.public_id as invoice_public_id', 'invoices.invoice_number', 'clients.currency_id', 'contacts.first_name', 'contacts.last_name', 'contacts.email', 'payment_types.name as payment_type', 'payments.account_gateway_id', 'payments.deleted_at', 'payments.is_deleted'); + ->select('payments.public_id', 'payments.transaction_reference', 'clients.name as client_name', 'clients.public_id as client_public_id', 'payments.amount', 'payments.payment_date', 'invoices.public_id as invoice_public_id', 'invoices.invoice_number', 'clients.currency_id', 'contacts.first_name', 'contacts.last_name', 'contacts.email', 'payment_types.name as payment_type', 'payments.account_gateway_id', 'payments.deleted_at', 'payments.is_deleted', 'invoices.is_deleted as invoice_is_deleted'); if (!\Session::get('show_trash:payment')) { - $query->where('payments.deleted_at', '=', null); + $query->where('payments.deleted_at', '=', null) + ->where('invoices.deleted_at', '=', null); } if ($clientPublicId) { @@ -52,6 +53,7 @@ class PaymentRepository ->where('clients.is_deleted', '=', false) ->where('payments.is_deleted', '=', false) ->where('invitations.deleted_at', '=', null) + ->where('invoices.deleted_at', '=', null) ->where('invitations.contact_id', '=', $contactId) ->select('invitations.invitation_key', 'payments.public_id', 'payments.transaction_reference', 'clients.name as client_name', 'clients.public_id as client_public_id', 'payments.amount', 'payments.payment_date', 'invoices.public_id as invoice_public_id', 'invoices.invoice_number', 'clients.currency_id', 'contacts.first_name', 'contacts.last_name', 'contacts.email', 'payment_types.name as payment_type', 'payments.account_gateway_id'); diff --git a/app/routes.php b/app/routes.php index d21b545686a2..1d0cedaa7308 100755 --- a/app/routes.php +++ b/app/routes.php @@ -186,40 +186,40 @@ define('ACCOUNT_USER_MANAGEMENT', 'user_management'); define('ACCOUNT_DATA_VISUALIZATIONS', 'data_visualizations'); define('ACCOUNT_EMAIL_TEMPLATES', 'email_templates'); -define("ACTIVITY_TYPE_CREATE_CLIENT", 1); -define("ACTIVITY_TYPE_ARCHIVE_CLIENT", 2); -define("ACTIVITY_TYPE_DELETE_CLIENT", 3); +define('ACTIVITY_TYPE_CREATE_CLIENT', 1); +define('ACTIVITY_TYPE_ARCHIVE_CLIENT', 2); +define('ACTIVITY_TYPE_DELETE_CLIENT', 3); -define("ACTIVITY_TYPE_CREATE_INVOICE", 4); -define("ACTIVITY_TYPE_UPDATE_INVOICE", 5); -define("ACTIVITY_TYPE_EMAIL_INVOICE", 6); -define("ACTIVITY_TYPE_VIEW_INVOICE", 7); -define("ACTIVITY_TYPE_ARCHIVE_INVOICE", 8); -define("ACTIVITY_TYPE_DELETE_INVOICE", 9); +define('ACTIVITY_TYPE_CREATE_INVOICE', 4); +define('ACTIVITY_TYPE_UPDATE_INVOICE', 5); +define('ACTIVITY_TYPE_EMAIL_INVOICE', 6); +define('ACTIVITY_TYPE_VIEW_INVOICE', 7); +define('ACTIVITY_TYPE_ARCHIVE_INVOICE', 8); +define('ACTIVITY_TYPE_DELETE_INVOICE', 9); -define("ACTIVITY_TYPE_CREATE_PAYMENT", 10); -define("ACTIVITY_TYPE_UPDATE_PAYMENT", 11); -define("ACTIVITY_TYPE_ARCHIVE_PAYMENT", 12); -define("ACTIVITY_TYPE_DELETE_PAYMENT", 13); +define('ACTIVITY_TYPE_CREATE_PAYMENT', 10); +define('ACTIVITY_TYPE_UPDATE_PAYMENT', 11); +define('ACTIVITY_TYPE_ARCHIVE_PAYMENT', 12); +define('ACTIVITY_TYPE_DELETE_PAYMENT', 13); -define("ACTIVITY_TYPE_CREATE_CREDIT", 14); -define("ACTIVITY_TYPE_UPDATE_CREDIT", 15); -define("ACTIVITY_TYPE_ARCHIVE_CREDIT", 16); -define("ACTIVITY_TYPE_DELETE_CREDIT", 17); +define('ACTIVITY_TYPE_CREATE_CREDIT', 14); +define('ACTIVITY_TYPE_UPDATE_CREDIT', 15); +define('ACTIVITY_TYPE_ARCHIVE_CREDIT', 16); +define('ACTIVITY_TYPE_DELETE_CREDIT', 17); -define("ACTIVITY_TYPE_CREATE_QUOTE", 18); -define("ACTIVITY_TYPE_UPDATE_QUOTE", 19); -define("ACTIVITY_TYPE_EMAIL_QUOTE", 20); -define("ACTIVITY_TYPE_VIEW_QUOTE", 21); -define("ACTIVITY_TYPE_ARCHIVE_QUOTE", 22); -define("ACTIVITY_TYPE_DELETE_QUOTE", 23); +define('ACTIVITY_TYPE_CREATE_QUOTE', 18); +define('ACTIVITY_TYPE_UPDATE_QUOTE', 19); +define('ACTIVITY_TYPE_EMAIL_QUOTE', 20); +define('ACTIVITY_TYPE_VIEW_QUOTE', 21); +define('ACTIVITY_TYPE_ARCHIVE_QUOTE', 22); +define('ACTIVITY_TYPE_DELETE_QUOTE', 23); -define("ACTIVITY_TYPE_RESTORE_QUOTE", 24); -define("ACTIVITY_TYPE_RESTORE_INVOICE", 25); -define("ACTIVITY_TYPE_RESTORE_CLIENT", 26); -define("ACTIVITY_TYPE_RESTORE_PAYMENT", 27); -define("ACTIVITY_TYPE_RESTORE_CREDIT", 28); -define("ACTIVITY_TYPE_APPROVE_QUOTE", 29); +define('ACTIVITY_TYPE_RESTORE_QUOTE', 24); +define('ACTIVITY_TYPE_RESTORE_INVOICE', 25); +define('ACTIVITY_TYPE_RESTORE_CLIENT', 26); +define('ACTIVITY_TYPE_RESTORE_PAYMENT', 27); +define('ACTIVITY_TYPE_RESTORE_CREDIT', 28); +define('ACTIVITY_TYPE_APPROVE_QUOTE', 29); define('DEFAULT_INVOICE_NUMBER', '0001'); define('RECENTLY_VIEWED_LIMIT', 8); @@ -471,4 +471,4 @@ if (Auth::check() && Auth::user()->id === 1) { Auth::loginUsingId(1); } -*/ +*/ \ No newline at end of file diff --git a/app/start/artisan.php b/app/start/artisan.php index 9b7f26ea0aff..57ae92253c76 100755 --- a/app/start/artisan.php +++ b/app/start/artisan.php @@ -15,3 +15,4 @@ Artisan::resolve('SendRecurringInvoices'); Artisan::resolve('CreateRandomData'); Artisan::resolve('ResetData'); Artisan::resolve('ImportTimesheetData'); +Artisan::resolve('CheckData'); diff --git a/app/views/invoices/edit.blade.php b/app/views/invoices/edit.blade.php index 143650ff1d49..47aaefb211b9 100755 --- a/app/views/invoices/edit.blade.php +++ b/app/views/invoices/edit.blade.php @@ -291,7 +291,7 @@
  • public_id}") }}">{{ trans("texts.view_history") }}
  • - @if ($invoice->invoice_status_id < INVOICE_STATUS_SENT) + @if ($invoice->invoice_status_id < INVOICE_STATUS_SENT && !$invoice->is_recurring)
  • {{ trans("texts.mark_sent") }}
  • @endif @@ -317,9 +317,11 @@ {{ Button::success(trans("texts.save_{$entityType}"), array('id' => 'saveButton', 'onclick' => 'onSaveClick()')) }} @endif - {{ Button::normal(trans("texts.email_{$entityType}"), array('id' => 'email_button', 'onclick' => 'onEmailClick()'))->append_with_icon('send'); }} + @if (!$invoice || ($invoice && !$invoice->is_recurring)) + {{ Button::normal(trans("texts.email_{$entityType}"), array('id' => 'email_button', 'onclick' => 'onEmailClick()'))->append_with_icon('send'); }} + @endif - @if ($invoice && $invoice->id && $entityType == ENTITY_INVOICE) + @if ($invoice && $invoice->id && $entityType == ENTITY_INVOICE && !$invoice->is_recurring) {{ Button::primary(trans('texts.enter_payment'), array('onclick' => 'onPaymentClick()'))->append_with_icon('usd'); }} @endif @elseif ($invoice && $invoice->trashed() && !$invoice->is_deleted == '1') diff --git a/app/views/invoices/view.blade.php b/app/views/invoices/view.blade.php index c667c74e92f9..84adacbe7316 100755 --- a/app/views/invoices/view.blade.php +++ b/app/views/invoices/view.blade.php @@ -26,7 +26,7 @@ @if (!$isConverted) {{ Button::success_link(URL::to('approve/' . $invitation->invitation_key), trans('texts.approve'), array('class' => 'btn-lg')) }} @endif - @elseif ($invoice->client->account->isGatewayConfigured() && !$invoice->isPaid() && !$invoice->is_recurring) + @elseif ($invoice->client->account->isGatewayConfigured() && !$invoice->isPaid() && !$invoice->is_recurring) {{ Button::normal(trans('texts.download_pdf'), array('onclick' => 'onDownloadClick()', 'class' => 'btn-lg')) }}   @if ($hasToken) {{ DropdownButton::success_lg(trans('texts.pay_now'), [ From 3c5a3897cc2676212cdd4470811106e3ca098cc4 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Thu, 26 Feb 2015 15:06:24 +0200 Subject: [PATCH 18/32] Fixed incorrect create_at activity timestamps --- app/commands/SendRecurringInvoices.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/commands/SendRecurringInvoices.php b/app/commands/SendRecurringInvoices.php index 35c8ef219d2f..2b08e45b70d9 100755 --- a/app/commands/SendRecurringInvoices.php +++ b/app/commands/SendRecurringInvoices.php @@ -39,8 +39,6 @@ class SendRecurringInvoices extends Command { continue; } - date_default_timezone_set($recurInvoice->account->getTimezone()); - $this->info('Processing Invoice ' . $recurInvoice->id . ' - Should send ' . ($recurInvoice->shouldSendToday() ? 'YES' : 'NO')); if (!$recurInvoice->shouldSendToday()) @@ -82,7 +80,7 @@ class SendRecurringInvoices extends Command { $item->qty = $recurItem->qty; $item->cost = $recurItem->cost; $item->notes = Utils::processVariables($recurItem->notes); - $item->product_key = Utils::processVariables($recurItem->product_key); + $item->product_key = Utils::processVariables($recurItem->product_key); $item->tax_name = $recurItem->tax_name; $item->tax_rate = $recurItem->tax_rate; $invoice->invoice_items()->save($item); From ef49e970a7c782d4412da449fdab4ad1d7f40b23 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Thu, 26 Feb 2015 15:06:44 +0200 Subject: [PATCH 19/32] Removed deleted and added archived records to the chart builder --- app/controllers/ReportController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/ReportController.php b/app/controllers/ReportController.php index 0dd36d1a0316..9000b8165444 100755 --- a/app/controllers/ReportController.php +++ b/app/controllers/ReportController.php @@ -52,7 +52,7 @@ class ReportController extends \BaseController $records = DB::table($entityType.'s') ->select(DB::raw('sum(amount) as total, '.$groupBy.'('.$entityType.'_date) as '.$groupBy)) ->where('account_id', '=', Auth::user()->account_id) - ->where($entityType.'s.deleted_at', '=', null) + ->where($entityType.'s.is_deleted', '=', false) ->where($entityType.'s.'.$entityType.'_date', '>=', $startDate->format('Y-m-d')) ->where($entityType.'s.'.$entityType.'_date', '<=', $endDate->format('Y-m-d')) ->groupBy($groupBy); From 856b7977d2febf0c8a8e061a699167ce35d8dfc1 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Thu, 26 Feb 2015 17:42:07 +0200 Subject: [PATCH 20/32] Bug fixes --- app/config/mail.php | 2 +- app/controllers/PaymentController.php | 2 +- app/views/payments/payment.blade.php | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/config/mail.php b/app/config/mail.php index 9840e66e9967..62dac9c3a572 100755 --- a/app/config/mail.php +++ b/app/config/mail.php @@ -28,7 +28,7 @@ return array( | */ - //'host' => '', + 'host' => '', /* |-------------------------------------------------------------------------- diff --git a/app/controllers/PaymentController.php b/app/controllers/PaymentController.php index 5765861a1535..5d2e6bc97a30 100755 --- a/app/controllers/PaymentController.php +++ b/app/controllers/PaymentController.php @@ -622,7 +622,7 @@ class PaymentController extends \BaseController } } catch (\Exception $e) { $errorMessage = trans('texts.payment_error'); - Session::flash('error', $errorMessage); + Session::flash('error', $errorMessage."

    ".$e->getMessage()); Utils::logError(Utils::getErrorString($e)); return Redirect::to('payment/'.$invitationKey) diff --git a/app/views/payments/payment.blade.php b/app/views/payments/payment.blade.php index 4f6c6661e912..788b34009bca 100755 --- a/app/views/payments/payment.blade.php +++ b/app/views/payments/payment.blade.php @@ -236,7 +236,6 @@ header h3 em {

    {{ Former::select('expiration_year')->placeholder(trans('texts.expiration_year')) - ->addOption('2014', '2014') ->addOption('2015', '2015') ->addOption('2016', '2016') ->addOption('2017', '2017') @@ -246,7 +245,8 @@ header h3 em { ->addOption('2021', '2021') ->addOption('2022', '2022') ->addOption('2023', '2023') - ->addOption('2024', '2024')->raw(); + ->addOption('2024', '2024') + ->addOption('2025', '2025')->raw(); }}
    From fe2155e139b3617ff09ca9494227cc40d46ed0d2 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Thu, 26 Feb 2015 20:20:10 +0200 Subject: [PATCH 21/32] Added social buttons to login page --- app/views/users/login.blade.php | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/app/views/users/login.blade.php b/app/views/users/login.blade.php index dac14b184ee3..9ef2bb890094 100755 --- a/app/views/users/login.blade.php +++ b/app/views/users/login.blade.php @@ -73,6 +73,7 @@ + @if ( Session::get('error') ) @@ -86,6 +87,27 @@ {{ Former::close() }} + @if (!Utils::isNinja()) +

    +

    +
    + + +
       + + + + + +
    + @endif +
    @stop \ No newline at end of file From bf24e8c40fe2b3cd336773ae49d964c3c622fb1d Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Thu, 26 Feb 2015 20:47:20 +0200 Subject: [PATCH 22/32] Client page color matches invoice design primary color --- app/commands/SendRecurringInvoices.php | 186 ++++++++++++------------- app/controllers/InvoiceController.php | 11 +- app/controllers/PaymentController.php | 17 ++- app/controllers/QuoteController.php | 27 ++-- app/handlers/UserEventHandler.php | 43 +++--- app/models/Invitation.php | 5 + app/views/list.blade.php | 2 +- app/views/payments/payment.blade.php | 15 +- app/views/public/license.blade.php | 106 +++++++++++--- app/views/public_list.blade.php | 7 +- 10 files changed, 258 insertions(+), 161 deletions(-) diff --git a/app/commands/SendRecurringInvoices.php b/app/commands/SendRecurringInvoices.php index 2b08e45b70d9..dda7bdc85e62 100755 --- a/app/commands/SendRecurringInvoices.php +++ b/app/commands/SendRecurringInvoices.php @@ -5,116 +5,108 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputArgument; use ninja\mailers\ContactMailer as Mailer; -class SendRecurringInvoices extends Command { +class SendRecurringInvoices extends Command +{ + protected $name = 'ninja:send-invoices'; + protected $description = 'Send recurring invoices'; + protected $mailer; - protected $name = 'ninja:send-invoices'; - protected $description = 'Send recurring invoices'; - protected $mailer; + public function __construct(Mailer $mailer) + { + parent::__construct(); - public function __construct(Mailer $mailer) - { - parent::__construct(); + $this->mailer = $mailer; + } - $this->mailer = $mailer; - } + public function fire() + { + $this->info(date('Y-m-d').' Running SendRecurringInvoices...'); + $today = new DateTime(); - public function fire() - { - $this->info(date('Y-m-d') . ' Running SendRecurringInvoices...'); - $today = new DateTime(); - - $invoices = Invoice::with('account.timezone', 'invoice_items', 'client', 'user') - ->whereRaw('is_deleted IS FALSE AND deleted_at IS NULL AND is_recurring IS TRUE AND start_date <= ? AND (end_date IS NULL OR end_date >= ?)', array($today, $today))->get(); - $this->info(count($invoices) . ' recurring invoice(s) found'); + $invoices = Invoice::with('account.timezone', 'invoice_items', 'client', 'user') + ->whereRaw('is_deleted IS FALSE AND deleted_at IS NULL AND is_recurring IS TRUE AND start_date <= ? AND (end_date IS NULL OR end_date >= ?)', array($today, $today))->get(); + $this->info(count($invoices).' recurring invoice(s) found'); - foreach ($invoices as $recurInvoice) - { - if ($recurInvoice->client->deleted_at) - { - continue; - } - - if (!$recurInvoice->user->confirmed) - { + foreach ($invoices as $recurInvoice) { + if ($recurInvoice->client->deleted_at) { continue; } - $this->info('Processing Invoice ' . $recurInvoice->id . ' - Should send ' . ($recurInvoice->shouldSendToday() ? 'YES' : 'NO')); - - if (!$recurInvoice->shouldSendToday()) - { - continue; - } - - $invoice = Invoice::createNew($recurInvoice); - $invoice->client_id = $recurInvoice->client_id; - $invoice->recurring_invoice_id = $recurInvoice->id; - $invoice->invoice_number = 'R' . $recurInvoice->account->getNextInvoiceNumber(); - $invoice->amount = $recurInvoice->amount; - $invoice->balance = $recurInvoice->amount; - $invoice->invoice_date = date_create()->format('Y-m-d'); - $invoice->discount = $recurInvoice->discount; - $invoice->po_number = $recurInvoice->po_number; - $invoice->public_notes = $recurInvoice->public_notes; - $invoice->terms = $recurInvoice->terms; - $invoice->tax_name = $recurInvoice->tax_name; - $invoice->tax_rate = $recurInvoice->tax_rate; - $invoice->invoice_design_id = $recurInvoice->invoice_design_id; - $invoice->custom_value1 = $recurInvoice->custom_value1; - $invoice->custom_value2 = $recurInvoice->custom_value2; - $invoice->custom_taxes1 = $recurInvoice->custom_taxes1; - $invoice->custom_taxes2 = $recurInvoice->custom_taxes2; - $invoice->is_amount_discount = $recurInvoice->is_amount_discount; + if (!$recurInvoice->user->confirmed) { + continue; + } - if ($invoice->client->payment_terms) - { - $invoice->due_date = date_create()->modify($invoice->client->payment_terms . ' day')->format('Y-m-d'); - } - - $invoice->save(); - - foreach ($recurInvoice->invoice_items as $recurItem) - { - $item = InvoiceItem::createNew($recurItem); - $item->product_id = $recurItem->product_id; - $item->qty = $recurItem->qty; - $item->cost = $recurItem->cost; - $item->notes = Utils::processVariables($recurItem->notes); - $item->product_key = Utils::processVariables($recurItem->product_key); - $item->tax_name = $recurItem->tax_name; - $item->tax_rate = $recurItem->tax_rate; - $invoice->invoice_items()->save($item); - } + $this->info('Processing Invoice '.$recurInvoice->id.' - Should send '.($recurInvoice->shouldSendToday() ? 'YES' : 'NO')); - foreach ($recurInvoice->invitations as $recurInvitation) - { - $invitation = Invitation::createNew($recurInvitation); - $invitation->contact_id = $recurInvitation->contact_id; - $invitation->invitation_key = str_random(RANDOM_KEY_LENGTH); - $invoice->invitations()->save($invitation); - } + if (!$recurInvoice->shouldSendToday()) { + continue; + } - $this->mailer->sendInvoice($invoice); + $invoice = Invoice::createNew($recurInvoice); + $invoice->client_id = $recurInvoice->client_id; + $invoice->recurring_invoice_id = $recurInvoice->id; + $invoice->invoice_number = 'R'.$recurInvoice->account->getNextInvoiceNumber(); + $invoice->amount = $recurInvoice->amount; + $invoice->balance = $recurInvoice->amount; + $invoice->invoice_date = date_create()->format('Y-m-d'); + $invoice->discount = $recurInvoice->discount; + $invoice->po_number = $recurInvoice->po_number; + $invoice->public_notes = $recurInvoice->public_notes; + $invoice->terms = $recurInvoice->terms; + $invoice->tax_name = $recurInvoice->tax_name; + $invoice->tax_rate = $recurInvoice->tax_rate; + $invoice->invoice_design_id = $recurInvoice->invoice_design_id; + $invoice->custom_value1 = $recurInvoice->custom_value1; + $invoice->custom_value2 = $recurInvoice->custom_value2; + $invoice->custom_taxes1 = $recurInvoice->custom_taxes1; + $invoice->custom_taxes2 = $recurInvoice->custom_taxes2; + $invoice->is_amount_discount = $recurInvoice->is_amount_discount; - $recurInvoice->last_sent_date = Carbon::now()->toDateTimeString(); - $recurInvoice->save(); - } + if ($invoice->client->payment_terms) { + $invoice->due_date = date_create()->modify($invoice->client->payment_terms.' day')->format('Y-m-d'); + } - $this->info('Done'); - } + $invoice->save(); - protected function getArguments() - { - return array( - //array('example', InputArgument::REQUIRED, 'An example argument.'), - ); - } + foreach ($recurInvoice->invoice_items as $recurItem) { + $item = InvoiceItem::createNew($recurItem); + $item->product_id = $recurItem->product_id; + $item->qty = $recurItem->qty; + $item->cost = $recurItem->cost; + $item->notes = Utils::processVariables($recurItem->notes); + $item->product_key = Utils::processVariables($recurItem->product_key); + $item->tax_name = $recurItem->tax_name; + $item->tax_rate = $recurItem->tax_rate; + $invoice->invoice_items()->save($item); + } - protected function getOptions() - { - return array( - //array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null), - ); - } + foreach ($recurInvoice->invitations as $recurInvitation) { + $invitation = Invitation::createNew($recurInvitation); + $invitation->contact_id = $recurInvitation->contact_id; + $invitation->invitation_key = str_random(RANDOM_KEY_LENGTH); + $invoice->invitations()->save($invitation); + } -} \ No newline at end of file + $this->mailer->sendInvoice($invoice); + + $recurInvoice->last_sent_date = Carbon::now()->toDateTimeString(); + $recurInvoice->save(); + } + + $this->info('Done'); + } + + protected function getArguments() + { + return array( + //array('example', InputArgument::REQUIRED, 'An example argument.'), + ); + } + + protected function getOptions() + { + return array( + //array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null), + ); + } +} diff --git a/app/controllers/InvoiceController.php b/app/controllers/InvoiceController.php index 6c5b589e6e5d..e41dfd98775f 100755 --- a/app/controllers/InvoiceController.php +++ b/app/controllers/InvoiceController.php @@ -46,7 +46,16 @@ class InvoiceController extends \BaseController public function clientIndex() { + $invitationKey = Session::get('invitation_key'); + if (!$invitationKey) { + return Redirect::to('/setup'); + } + + $invitation = Invitation::with('account')->where('invitation_key', '=', $invitationKey)->first(); + $color = $invitation->account->primary_color ? $invitation->account->primary_color : '#0b4d78'; + $data = [ + 'color' => $color, 'hideLogo' => Session::get('white_label'), 'title' => trans('texts.invoices'), 'entityType' => ENTITY_INVOICE, @@ -67,7 +76,7 @@ class InvoiceController extends \BaseController public function getClientDatatable() { //$accountId = Auth::user()->account_id; - $search = Input::get('sSearch'); + $search = Input::get('sSearch'); $invitationKey = Session::get('invitation_key'); $invitation = Invitation::where('invitation_key', '=', $invitationKey)->first(); diff --git a/app/controllers/PaymentController.php b/app/controllers/PaymentController.php index 5d2e6bc97a30..f94a93a3fcf6 100755 --- a/app/controllers/PaymentController.php +++ b/app/controllers/PaymentController.php @@ -30,12 +30,23 @@ class PaymentController extends \BaseController public function clientIndex() { - return View::make('public_list', array( + $invitationKey = Session::get('invitation_key'); + if (!$invitationKey) { + return Redirect::to('/setup'); + } + + $invitation = Invitation::with('account')->where('invitation_key', '=', $invitationKey)->first(); + $color = $invitation->account->primary_color ? $invitation->account->primary_color : '#0b4d78'; + + $data = [ + 'color' => $color, 'hideLogo' => Session::get('white_label'), 'entityType' => ENTITY_PAYMENT, 'title' => trans('texts.payments'), - 'columns' => Utils::trans(['invoice', 'transaction_reference', 'method', 'payment_amount', 'payment_date']), - )); + 'columns' => Utils::trans(['invoice', 'transaction_reference', 'method', 'payment_amount', 'payment_date']) + ]; + + return View::make('public_list', $data); } public function getDatatable($clientPublicId = null) diff --git a/app/controllers/QuoteController.php b/app/controllers/QuoteController.php index b060dec80a5f..199d6b1130a9 100644 --- a/app/controllers/QuoteController.php +++ b/app/controllers/QuoteController.php @@ -29,10 +29,10 @@ class QuoteController extends \BaseController } $data = [ - 'title' => trans('texts.quotes'), - 'entityType' => ENTITY_QUOTE, - 'columns' => Utils::trans(['checkbox', 'quote_number', 'client', 'quote_date', 'quote_total', 'due_date', 'status', 'action']), - ]; + 'title' => trans('texts.quotes'), + 'entityType' => ENTITY_QUOTE, + 'columns' => Utils::trans(['checkbox', 'quote_number', 'client', 'quote_date', 'quote_total', 'due_date', 'status', 'action']), + ]; /* if (Invoice::scope()->where('is_recurring', '=', true)->count() > 0) @@ -47,12 +47,21 @@ class QuoteController extends \BaseController public function clientIndex() { + $invitationKey = Session::get('invitation_key'); + if (!$invitationKey) { + return Redirect::to('/setup'); + } + + $invitation = Invitation::with('account')->where('invitation_key', '=', $invitationKey)->first(); + $color = $invitation->account->primary_color ? $invitation->account->primary_color : '#0b4d78'; + $data = [ - 'hideLogo' => Session::get('white_label'), - 'title' => trans('texts.quotes'), - 'entityType' => ENTITY_QUOTE, - 'columns' => Utils::trans(['quote_number', 'quote_date', 'quote_total', 'due_date']), - ]; + 'color' => $color, + 'hideLogo' => Session::get('white_label'), + 'title' => trans('texts.quotes'), + 'entityType' => ENTITY_QUOTE, + 'columns' => Utils::trans(['quote_number', 'quote_date', 'quote_total', 'due_date']), + ]; return View::make('public_list', $data); } diff --git a/app/handlers/UserEventHandler.php b/app/handlers/UserEventHandler.php index 5e6a24955287..19ee6f5de936 100755 --- a/app/handlers/UserEventHandler.php +++ b/app/handlers/UserEventHandler.php @@ -2,30 +2,29 @@ class UserEventHandler { - public function subscribe($events) - { - $events->listen('user.signup', 'UserEventHandler@onSignup'); - $events->listen('user.login', 'UserEventHandler@onLogin'); + public function subscribe($events) + { + $events->listen('user.signup', 'UserEventHandler@onSignup'); + $events->listen('user.login', 'UserEventHandler@onLogin'); - $events->listen('user.refresh', 'UserEventHandler@onRefresh'); - } + $events->listen('user.refresh', 'UserEventHandler@onRefresh'); + } - public function onSignup() - { - - } + public function onSignup() + { + } - public function onLogin() - { - $account = Auth::user()->account; - $account->last_login = Carbon::now()->toDateTimeString(); - $account->save(); + public function onLogin() + { + $account = Auth::user()->account; + $account->last_login = Carbon::now()->toDateTimeString(); + $account->save(); - Event::fire('user.refresh'); - } + Event::fire('user.refresh'); + } - public function onRefresh() - { - Auth::user()->account->loadLocalizationSettings(); - } -} \ No newline at end of file + public function onRefresh() + { + Auth::user()->account->loadLocalizationSettings(); + } +} diff --git a/app/models/Invitation.php b/app/models/Invitation.php index bb9f4db77a04..0100f75d96f7 100755 --- a/app/models/Invitation.php +++ b/app/models/Invitation.php @@ -17,6 +17,11 @@ class Invitation extends EntityModel return $this->belongsTo('User')->withTrashed(); } + public function account() + { + return $this->belongsTo('Account'); + } + public function getLink() { return SITE_URL.'/view/'.$this->invitation_key; diff --git a/app/views/list.blade.php b/app/views/list.blade.php index e0e473917ca7..4cc501c55d16 100755 --- a/app/views/list.blade.php +++ b/app/views/list.blade.php @@ -20,7 +20,7 @@  
    diff --git a/app/views/payments/payment.blade.php b/app/views/payments/payment.blade.php index 788b34009bca..845399c73e5d 100755 --- a/app/views/payments/payment.blade.php +++ b/app/views/payments/payment.blade.php @@ -15,6 +15,7 @@ body { .container input[type=text], +.container input[type=email], .container select { font-weight: 300; font-family: 'Roboto', sans-serif; @@ -145,13 +146,17 @@ header h3 em {
    -
    +
    -

    {{ $client->getDisplayName() }}

    -

    {{ trans('texts.invoice') . ' ' . $invoiceNumber }}|  {{ trans('texts.amount_due') }}: {{ Utils::formatMoney($amount, $currencyId) }}

    + @if ($client) +

    {{ $client->getDisplayName() }}

    +

    {{ trans('texts.invoice') . ' ' . $invoiceNumber }}|  {{ trans('texts.amount_due') }}: {{ Utils::formatMoney($amount, $currencyId) }}

    + @elseif ($paymentTitle) +

    {{ $paymentTitle }}
    {{ $paymentSubtitle }}

    + @endif
    -
    +
    @if (Request::secure() || Utils::isNinjaDev())

    {{ trans('texts.secure_payment') }}

    @@ -254,7 +259,7 @@ header h3 em {
    - @if ($account->showTokenCheckbox()) + @if ($client && $account->showTokenCheckbox()) selectTokenCheckbox() ? 'CHECKED' : '' }} value="1" style="margin-left:0px; vertical-align:top"> {{ trans('texts.token_billing_secure', ['stripe_link' => link_to('https://stripe.com/', 'Stripe.com', ['target' => '_blank'])]) }} diff --git a/app/views/public/license.blade.php b/app/views/public/license.blade.php index 29a85cd6e8cb..92844a2a3123 100644 --- a/app/views/public/license.blade.php +++ b/app/views/public/license.blade.php @@ -2,32 +2,100 @@ @section('content') -
    -
    -
    -

    License Key

    - - -
    -
    -
    + + + +

     

    -
    -
    +
    +
    + +
    +
    +
    +

    License Key
    {{ $message }}

    +
    +
    +
    + +

     

    +

     

    +
    -

    {{ $message }}

    -

     

    -

     

    -

    {{ $license }}

    +

    {{ $license }}

    -
    -
    -
    +
    +
    +
    -

     

    +
    + +
    @stop \ No newline at end of file diff --git a/app/views/public_list.blade.php b/app/views/public_list.blade.php index d906256951ba..a517539ab74b 100755 --- a/app/views/public_list.blade.php +++ b/app/views/public_list.blade.php @@ -11,8 +11,7 @@ table.dataTable { border-radius: 3px; border-collapse: collapse; /*border-spacing: 0;*/} table.dataTable thead > tr > th, table.invoice-table thead > tr > th { - background-color: #0b4d78 !important; - /*background-color: #e37329 !important;*/ + background-color: {{ $color }} !important; color:#fff; } th:first-child { @@ -68,8 +67,8 @@ max-width: 250px; } .pagination>.active>a, .pagination>.active>span, .pagination>.active>a:hover, .pagination>.active>span:hover, .pagination>.active>a:focus, .pagination>.active>span:focus { - background-color: #0b4d78; - border-color: #0b4d78; + background-color: {{ $color }}; + border-color: {{ $color }}; } .pagination>li:first-child>a, .pagination>li:first-child>span { border-bottom-left-radius: 3px; From 854f6777ab11a5d9a9ede061eb483b2301fd7cb0 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Thu, 26 Feb 2015 21:24:49 +0200 Subject: [PATCH 23/32] Bug fixes --- app/controllers/InvoiceApiController.php | 25 +- app/libraries/utils.php | 1190 +++++++++--------- app/ninja/repositories/InvoiceRepository.php | 2 +- app/start/global.php | 12 +- app/views/emails/confirm_html.blade.php | 2 +- app/views/public/terms.blade.php | 26 + 6 files changed, 634 insertions(+), 623 deletions(-) diff --git a/app/controllers/InvoiceApiController.php b/app/controllers/InvoiceApiController.php index 10081da8ca37..bd488fd1ed7e 100644 --- a/app/controllers/InvoiceApiController.php +++ b/app/controllers/InvoiceApiController.php @@ -26,15 +26,20 @@ class InvoiceApiController extends Controller return Response::make($response, 200, $headers); } - /* - public function store() - { - $data = Input::all(); - $invoice = $this->invoiceRepo->save(false, $data, false); + /* + public function store() + { + if (!Utils::isPro()) { + return Redirect::to('/'); + } - $response = json_encode($invoice, JSON_PRETTY_PRINT); - $headers = Utils::getApiHeaders(); - return Response::make($response, 200, $headers); - } - */ + $data = Input::all(); + $invoice = $this->invoiceRepo->save(false, $data, false); + + $response = json_encode($invoice, JSON_PRETTY_PRINT); + $headers = Utils::getApiHeaders(); + + return Response::make($response, 200, $headers); + } + */ } diff --git a/app/libraries/utils.php b/app/libraries/utils.php index 1884713ee1ff..89f0427e921f 100755 --- a/app/libraries/utils.php +++ b/app/libraries/utils.php @@ -1,618 +1,600 @@ registered; - } - - public static function isConfirmed() - { - return Auth::check() && Auth::user()->confirmed; - } - - public static function isDatabaseSetup() - { - try - { - if (Schema::hasTable('accounts')) - { - return true; - } - } - catch (Exception $e) - { - return false; - } - } - - public static function isProd() - { - return App::environment() == ENV_PRODUCTION; - } - - public static function isNinja() - { - return self::isNinjaProd() || self::isNinjaDev(); - } - - public static function isNinjaProd() - { - return isset($_ENV['NINJA_PROD']) && $_ENV['NINJA_PROD']; - } - - public static function isNinjaDev() - { - return isset($_ENV['NINJA_DEV']) && $_ENV['NINJA_DEV']; - } - - public static function isPro() - { - return Auth::check() && Auth::user()->isPro(); - } - - public static function getUserType() - { - if (Utils::isNinja()) { - return USER_TYPE_CLOUD_HOST; - } else { - return USER_TYPE_SELF_HOST; - } - } - - public static function getDemoAccountId() - { - return isset($_ENV[DEMO_ACCOUNT_ID]) ? $_ENV[DEMO_ACCOUNT_ID] : false; - } - - public static function isDemo() - { - return Auth::check() && Auth::user()->isDemo(); - } - - public static function getNewsFeedResponse($userType = false) - { - if (!$userType) { - $userType = Utils::getUserType(); - } - - $response = new stdClass; - $response->message = isset($_ENV["{$userType}_MESSAGE"]) ? $_ENV["{$userType}_MESSAGE"] : ''; - $response->id = isset($_ENV["{$userType}_ID"]) ? $_ENV["{$userType}_ID"] : ''; - $response->version = NINJA_VERSION; - - return $response; - } - - public static function getProLabel($feature) - { - if (Auth::check() - && !Auth::user()->isPro() - && $feature == ACCOUNT_ADVANCED_SETTINGS) - { - return ' PRO'; - } - else - { - return ''; - } - } - - public static function basePath() - { - return substr($_SERVER['SCRIPT_NAME'], 0, strrpos($_SERVER['SCRIPT_NAME'], '/') + 1); - } - - public static function trans($input) - { - $data = []; - - foreach ($input as $field) - { - if ($field == "checkbox") - { - $data[] = $field; - } - else - { - $data[] = trans("texts.$field"); - } - } - - return $data; - } - - public static function fatalError($message = false, $exception = false) - { - if (!$message) - { - $message = "An error occurred, please try again later."; - } - - static::logError($message . ' ' . $exception); - - $data = [ - 'showBreadcrumbs' => false, - 'hideHeader' => true - ]; - - return View::make('error', $data)->with('error', $message); - } - - public static function getErrorString($exception) - { - return "{$exception->getFile()} [Line {$exception->getLine()}] => {$exception->getMessage()}"; - } - - public static function logError($error, $context = 'PHP') - { - $count = Session::get('error_count', 0); - Session::put('error_count', ++$count); - if ($count > 100) return 'logged'; - - $data = [ - 'context' => $context, - 'user_id' => Auth::check() ? Auth::user()->id : 0, - 'user_name' => Auth::check() ? Auth::user()->getDisplayName() : '', - 'url' => Input::get('url', Request::url()), - 'user_agent' => isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '', - 'ip' => Request::getClientIp(), - 'count' => Session::get('error_count', 0) - ]; - - Log::error($error."\n", $data); - - /* - Mail::queue('emails.error', ['message'=>$error.' '.json_encode($data)], function($message) - { - $message->to($email)->subject($subject); - }); - */ - } - - public static function parseFloat($value) - { - $value = preg_replace('/[^0-9\.\-]/', '', $value); - return floatval($value); - } - - public static function formatPhoneNumber($phoneNumber) - { - $phoneNumber = preg_replace('/[^0-9a-zA-Z]/','',$phoneNumber); - - if (!$phoneNumber) { - return ''; - } - - if(strlen($phoneNumber) > 10) { - $countryCode = substr($phoneNumber, 0, strlen($phoneNumber)-10); - $areaCode = substr($phoneNumber, -10, 3); - $nextThree = substr($phoneNumber, -7, 3); - $lastFour = substr($phoneNumber, -4, 4); - - $phoneNumber = '+'.$countryCode.' ('.$areaCode.') '.$nextThree.'-'.$lastFour; - } - else if(strlen($phoneNumber) == 10 && in_array(substr($phoneNumber, 0, 3), array(653, 656, 658, 659))) { - /** - * SG country code are 653, 656, 658, 659 - * US area code consist of 650, 651 and 657 - * @see http://en.wikipedia.org/wiki/Telephone_numbers_in_Singapore#Numbering_plan - * @see http://www.bennetyee.org/ucsd-pages/area.html - */ - $countryCode = substr($phoneNumber, 0, 2); - $nextFour = substr($phoneNumber, 2, 4); - $lastFour = substr($phoneNumber, 6, 4); - - $phoneNumber = '+'.$countryCode.' '.$nextFour.' '.$lastFour; - } - else if(strlen($phoneNumber) == 10) { - $areaCode = substr($phoneNumber, 0, 3); - $nextThree = substr($phoneNumber, 3, 3); - $lastFour = substr($phoneNumber, 6, 4); - - $phoneNumber = '('.$areaCode.') '.$nextThree.'-'.$lastFour; - } - else if(strlen($phoneNumber) == 7) { - $nextThree = substr($phoneNumber, 0, 3); - $lastFour = substr($phoneNumber, 3, 4); - - $phoneNumber = $nextThree.'-'.$lastFour; - } - - return $phoneNumber; - } - - public static function formatMoney($value, $currencyId = false) - { - if (!$currencyId) - { - $currencyId = Session::get(SESSION_CURRENCY); - } - - $currency = Currency::remember(DEFAULT_QUERY_CACHE)->find($currencyId); - - if (!$currency) - { - $currency = Currency::remember(DEFAULT_QUERY_CACHE)->find(1); - } - - return $currency->symbol . number_format($value, $currency->precision, $currency->decimal_separator, $currency->thousand_separator); - } - - public static function pluralize($string, $count) - { - $field = $count == 1 ? $string : $string . 's'; - $string = trans("texts.$field", ['count' => $count]); - return $string; - } - - public static function toArray($data) - { - return json_decode(json_encode((array) $data), true); - } - - public static function toSpaceCase($camelStr) - { - return preg_replace('/([a-z])([A-Z])/s','$1 $2', $camelStr); - } - - public static function timestampToDateTimeString($timestamp) { - $timezone = Session::get(SESSION_TIMEZONE, DEFAULT_TIMEZONE); - $format = Session::get(SESSION_DATETIME_FORMAT, DEFAULT_DATETIME_FORMAT); - return Utils::timestampToString($timestamp, $timezone, $format); - } - - public static function timestampToDateString($timestamp) { - $timezone = Session::get(SESSION_TIMEZONE, DEFAULT_TIMEZONE); - $format = Session::get(SESSION_DATE_FORMAT, DEFAULT_DATE_FORMAT); - return Utils::timestampToString($timestamp, $timezone, $format); - } - - public static function dateToString($date) { - $dateTime = new DateTime($date); - $timestamp = $dateTime->getTimestamp(); - $format = Session::get(SESSION_DATE_FORMAT, DEFAULT_DATE_FORMAT); - return Utils::timestampToString($timestamp, false, $format); - } - - public static function timestampToString($timestamp, $timezone = false, $format) - { - if (!$timestamp) { - return ''; - } - $date = Carbon::createFromTimeStamp($timestamp); - if ($timezone) { - $date->tz = $timezone; - } - if ($date->year < 1900) { - return ''; - } - return $date->format($format); - } - - public static function toSqlDate($date, $formatResult = true) - { - if (!$date) - { - return null; - } - - $timezone = Session::get(SESSION_TIMEZONE); - $format = Session::get(SESSION_DATE_FORMAT); - - - $dateTime = DateTime::createFromFormat($format, $date, new DateTimeZone($timezone)); - return $formatResult ? $dateTime->format('Y-m-d') : $dateTime; - } - - public static function fromSqlDate($date, $formatResult = true) - { - if (!$date || $date == '0000-00-00') - { - return ''; - } - - $timezone = Session::get(SESSION_TIMEZONE); - $format = Session::get(SESSION_DATE_FORMAT); - - $dateTime = DateTime::createFromFormat('Y-m-d', $date, new DateTimeZone($timezone)); - return $formatResult ? $dateTime->format($format) : $dateTime; - } - - public static function today($formatResult = true) - { - $timezone = Session::get(SESSION_TIMEZONE); - $format = Session::get(SESSION_DATE_FORMAT); - $date = date_create(null, new DateTimeZone($timezone)); - - if ($formatResult) - { - return $date->format($format); - } - else - { - return $date; - } - } - - public static function trackViewed($name, $type, $url = false) - { - if (!$url) - { - $url = Request::url(); - } - - $viewed = Session::get(RECENTLY_VIEWED); - - if (!$viewed) - { - $viewed = []; - } - - $object = new stdClass; - $object->url = $url; - $object->name = ucwords($type) . ': ' . $name; - - $data = []; - - for ($i=0; $iurl == $item->url || $object->name == $item->name) - { - continue; - } - - array_unshift($data, $item); - } - - array_unshift($data, $object); - - if (count($data) > RECENTLY_VIEWED_LIMIT) - { - array_pop($data); - } - - Session::put(RECENTLY_VIEWED, $data); - } - - public static function processVariables($str) - { - if (!$str) { - return ''; - } - - $variables = ['MONTH', 'QUARTER', 'YEAR']; - for ($i=0; $i 1) { - $offset = intval($addArray[1]); - } else if (count($minArray) > 1) { - $offset = intval($minArray[1]) * -1; - } - - $val = Utils::getDatePart($variable, $offset); - $str = str_replace($match, $val, $str); - } - } - - return $str; - } - - private static function getDatePart($part, $offset) - { - $offset = intval($offset); - if ($part == 'MONTH') { - return Utils::getMonth($offset); - } else if ($part == 'QUARTER') { - return Utils::getQuarter($offset); - } else if ($part == 'YEAR') { - return Utils::getYear($offset); - } - } - - private static function getMonth($offset) - { - $months = [ "January", "February", "March", "April", "May", "June", - "July", "August", "September", "October", "November", "December" ]; - - $month = intval(date('n')) - 1; - - $month += $offset; - $month = $month % 12; - - if ($month < 0) - { - $month += 12; - } - - return $months[$month]; - } - - private static function getQuarter($offset) - { - $month = intval(date('n')) - 1; - $quarter = floor(($month + 3) / 3); - $quarter += $offset; - $quarter = $quarter % 4; - if ($quarter == 0) { - $quarter = 4; - } - return 'Q' . $quarter; - } - - private static function getYear($offset) - { - $year = intval(date('Y')); - return $year + $offset; - } - - public static function getEntityName($entityType) - { - return ucwords(str_replace('_', ' ', $entityType)); - } - - public static function getClientDisplayName($model) - { - if ($model->client_name) - { - return $model->client_name; - } - else if ($model->first_name || $model->last_name) - { - return $model->first_name . ' ' . $model->last_name; - } - else - { - return $model->email; - } - } - - public static function encodeActivity($person = null, $action, $entity = null, $otherPerson = null) - { - $person = $person ? $person->getDisplayName() : 'System'; - $entity = $entity ? '[' . $entity->getActivityKey() . ']' : ''; - $otherPerson = $otherPerson ? 'to ' . $otherPerson->getDisplayName() : ''; - - return trim("$person $action $entity $otherPerson"); - } - - public static function decodeActivity($message) - { - $pattern = '/\[([\w]*):([\d]*):(.*)\]/i'; - preg_match($pattern, $message, $matches); - - if (count($matches) > 0) - { - $match = $matches[0]; - $type = $matches[1]; - $publicId = $matches[2]; - $name = $matches[3]; - - $link = link_to($type . 's/' . $publicId, $name); - $message = str_replace($match, "$type $link", $message); - } - - return $message; - } - - public static function generateLicense() { - $parts = []; - for ($i=0; $i<5; $i++) { - $parts[] = strtoupper(str_random(4)); - } - return join('-', $parts); - } - - public static function lookupEventId($eventName) - { - if ($eventName == 'create_client') { - return EVENT_CREATE_CLIENT; - } else if ($eventName == 'create_invoice') { - return EVENT_CREATE_INVOICE; - } else if ($eventName == 'create_quote') { - return EVENT_CREATE_QUOTE; - } else if ($eventName == 'create_payment') { - return EVENT_CREATE_PAYMENT; - } else { - return false; - } - } - - public static function notifyZapier($subscription, $data) { - $curl = curl_init(); - - $jsonEncodedData = json_encode($data->toJson()); - $opts = [ - CURLOPT_URL => $subscription->target_url, - CURLOPT_RETURNTRANSFER => true, - CURLOPT_CUSTOMREQUEST => 'POST', - CURLOPT_POST => 1, - CURLOPT_POSTFIELDS => $jsonEncodedData, - CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Content-Length: ' . strlen($jsonEncodedData)] - ]; - - curl_setopt_array($curl, $opts); - - $result = curl_exec($curl); - $status = curl_getinfo($curl, CURLINFO_HTTP_CODE); - - curl_close($curl); - - if ($status == 410) + public static function isRegistered() { - $subscription->delete(); + return Auth::check() && Auth::user()->registered; } - } - public static function remapPublicIds($data) { - foreach ($data as $index => $record) { - if (!isset($data[$index]['public_id'])) { - continue; - } - $data[$index]['id'] = $data[$index]['public_id']; - unset($data[$index]['public_id']); - - foreach ($record as $key => $val) { - if (is_array($val)) { - $data[$index][$key] = Utils::remapPublicIds($val); - } - } + public static function isConfirmed() + { + return Auth::check() && Auth::user()->confirmed; } - return $data; - } - public static function getApiHeaders($count = 0) { - return [ - 'Content-Type' => 'application/json', - //'Access-Control-Allow-Origin' => '*', - //'Access-Control-Allow-Methods' => 'GET', - //'Access-Control-Allow-Headers' => 'Origin, Content-Type, Accept, Authorization, X-Requested-With', - //'Access-Control-Allow-Credentials' => 'true', - 'X-Total-Count' => $count, - //'X-Rate-Limit-Limit' - The number of allowed requests in the current period - //'X-Rate-Limit-Remaining' - The number of remaining requests in the current period - //'X-Rate-Limit-Reset' - The number of seconds left in the current period, - ]; - } + public static function isDatabaseSetup() + { + try { + if (Schema::hasTable('accounts')) { + return true; + } + } catch (Exception $e) { + return false; + } + } - public static function startsWith($haystack, $needle) - { - return $needle === "" || strpos($haystack, $needle) === 0; - } + public static function isProd() + { + return App::environment() == ENV_PRODUCTION; + } - public static function endsWith($haystack, $needle) - { - return $needle === "" || substr($haystack, -strlen($needle)) === $needle; - } + public static function isNinja() + { + return self::isNinjaProd() || self::isNinjaDev(); + } - public static function getEntityRowClass($model) - { - $str = $model->is_deleted || ($model->deleted_at && $model->deleted_at != '0000-00-00') ? 'DISABLED ' : ''; + public static function isNinjaProd() + { + return isset($_ENV['NINJA_PROD']) && $_ENV['NINJA_PROD']; + } - if ($model->is_deleted) - { - $str .= 'ENTITY_DELETED '; - } + public static function isNinjaDev() + { + return isset($_ENV['NINJA_DEV']) && $_ENV['NINJA_DEV']; + } - if ($model->deleted_at && $model->deleted_at != '0000-00-00') - { - $str .= 'ENTITY_ARCHIVED '; - } + public static function isPro() + { + return Auth::check() && Auth::user()->isPro(); + } - return $str; - } -} \ No newline at end of file + public static function getUserType() + { + if (Utils::isNinja()) { + return USER_TYPE_CLOUD_HOST; + } else { + return USER_TYPE_SELF_HOST; + } + } + + public static function getDemoAccountId() + { + return isset($_ENV[DEMO_ACCOUNT_ID]) ? $_ENV[DEMO_ACCOUNT_ID] : false; + } + + public static function isDemo() + { + return Auth::check() && Auth::user()->isDemo(); + } + + public static function getNewsFeedResponse($userType = false) + { + if (!$userType) { + $userType = Utils::getUserType(); + } + + $response = new stdClass(); + $response->message = isset($_ENV["{$userType}_MESSAGE"]) ? $_ENV["{$userType}_MESSAGE"] : ''; + $response->id = isset($_ENV["{$userType}_ID"]) ? $_ENV["{$userType}_ID"] : ''; + $response->version = NINJA_VERSION; + + return $response; + } + + public static function getProLabel($feature) + { + if (Auth::check() + && !Auth::user()->isPro() + && $feature == ACCOUNT_ADVANCED_SETTINGS) { + return ' PRO'; + } else { + return ''; + } + } + + public static function basePath() + { + return substr($_SERVER['SCRIPT_NAME'], 0, strrpos($_SERVER['SCRIPT_NAME'], '/') + 1); + } + + public static function trans($input) + { + $data = []; + + foreach ($input as $field) { + if ($field == "checkbox") { + $data[] = $field; + } else { + $data[] = trans("texts.$field"); + } + } + + return $data; + } + + public static function fatalError($message = false, $exception = false) + { + if (!$message) { + $message = "An error occurred, please try again later."; + } + + static::logError($message.' '.$exception); + + $data = [ + 'showBreadcrumbs' => false, + 'hideHeader' => true, + ]; + + return View::make('error', $data)->with('error', $message); + } + + public static function getErrorString($exception) + { + return "{$exception->getFile()} [Line {$exception->getLine()}] => {$exception->getMessage()}"; + } + + public static function logError($error, $context = 'PHP') + { + $count = Session::get('error_count', 0); + Session::put('error_count', ++$count); + if ($count > 100) { + return 'logged'; + } + + $data = [ + 'context' => $context, + 'user_id' => Auth::check() ? Auth::user()->id : 0, + 'user_name' => Auth::check() ? Auth::user()->getDisplayName() : '', + 'url' => Input::get('url', Request::url()), + 'user_agent' => isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '', + 'ip' => Request::getClientIp(), + 'count' => Session::get('error_count', 0), + ]; + + Log::error($error."\n", $data); + + /* + Mail::queue('emails.error', ['message'=>$error.' '.json_encode($data)], function($message) + { + $message->to($email)->subject($subject); + }); + */ + } + + public static function parseFloat($value) + { + $value = preg_replace('/[^0-9\.\-]/', '', $value); + + return floatval($value); + } + + public static function formatPhoneNumber($phoneNumber) + { + $phoneNumber = preg_replace('/[^0-9a-zA-Z]/', '', $phoneNumber); + + if (!$phoneNumber) { + return ''; + } + + if (strlen($phoneNumber) > 10) { + $countryCode = substr($phoneNumber, 0, strlen($phoneNumber)-10); + $areaCode = substr($phoneNumber, -10, 3); + $nextThree = substr($phoneNumber, -7, 3); + $lastFour = substr($phoneNumber, -4, 4); + + $phoneNumber = '+'.$countryCode.' ('.$areaCode.') '.$nextThree.'-'.$lastFour; + } elseif (strlen($phoneNumber) == 10 && in_array(substr($phoneNumber, 0, 3), array(653, 656, 658, 659))) { + /** + * SG country code are 653, 656, 658, 659 + * US area code consist of 650, 651 and 657 + * @see http://en.wikipedia.org/wiki/Telephone_numbers_in_Singapore#Numbering_plan + * @see http://www.bennetyee.org/ucsd-pages/area.html + */ + $countryCode = substr($phoneNumber, 0, 2); + $nextFour = substr($phoneNumber, 2, 4); + $lastFour = substr($phoneNumber, 6, 4); + + $phoneNumber = '+'.$countryCode.' '.$nextFour.' '.$lastFour; + } elseif (strlen($phoneNumber) == 10) { + $areaCode = substr($phoneNumber, 0, 3); + $nextThree = substr($phoneNumber, 3, 3); + $lastFour = substr($phoneNumber, 6, 4); + + $phoneNumber = '('.$areaCode.') '.$nextThree.'-'.$lastFour; + } elseif (strlen($phoneNumber) == 7) { + $nextThree = substr($phoneNumber, 0, 3); + $lastFour = substr($phoneNumber, 3, 4); + + $phoneNumber = $nextThree.'-'.$lastFour; + } + + return $phoneNumber; + } + + public static function formatMoney($value, $currencyId = false) + { + if (!$currencyId) { + $currencyId = Session::get(SESSION_CURRENCY); + } + + $currency = Currency::remember(DEFAULT_QUERY_CACHE)->find($currencyId); + + if (!$currency) { + $currency = Currency::remember(DEFAULT_QUERY_CACHE)->find(1); + } + + return $currency->symbol.number_format($value, $currency->precision, $currency->decimal_separator, $currency->thousand_separator); + } + + public static function pluralize($string, $count) + { + $field = $count == 1 ? $string : $string.'s'; + $string = trans("texts.$field", ['count' => $count]); + + return $string; + } + + public static function toArray($data) + { + return json_decode(json_encode((array) $data), true); + } + + public static function toSpaceCase($camelStr) + { + return preg_replace('/([a-z])([A-Z])/s', '$1 $2', $camelStr); + } + + public static function timestampToDateTimeString($timestamp) + { + $timezone = Session::get(SESSION_TIMEZONE, DEFAULT_TIMEZONE); + $format = Session::get(SESSION_DATETIME_FORMAT, DEFAULT_DATETIME_FORMAT); + + return Utils::timestampToString($timestamp, $timezone, $format); + } + + public static function timestampToDateString($timestamp) + { + $timezone = Session::get(SESSION_TIMEZONE, DEFAULT_TIMEZONE); + $format = Session::get(SESSION_DATE_FORMAT, DEFAULT_DATE_FORMAT); + + return Utils::timestampToString($timestamp, $timezone, $format); + } + + public static function dateToString($date) + { + $dateTime = new DateTime($date); + $timestamp = $dateTime->getTimestamp(); + $format = Session::get(SESSION_DATE_FORMAT, DEFAULT_DATE_FORMAT); + + return Utils::timestampToString($timestamp, false, $format); + } + + public static function timestampToString($timestamp, $timezone = false, $format) + { + if (!$timestamp) { + return ''; + } + $date = Carbon::createFromTimeStamp($timestamp); + if ($timezone) { + $date->tz = $timezone; + } + if ($date->year < 1900) { + return ''; + } + + return $date->format($format); + } + + public static function toSqlDate($date, $formatResult = true) + { + if (!$date) { + return; + } + + $timezone = Session::get(SESSION_TIMEZONE); + $format = Session::get(SESSION_DATE_FORMAT); + + $dateTime = DateTime::createFromFormat($format, $date, new DateTimeZone($timezone)); + + return $formatResult ? $dateTime->format('Y-m-d') : $dateTime; + } + + public static function fromSqlDate($date, $formatResult = true) + { + if (!$date || $date == '0000-00-00') { + return ''; + } + + $timezone = Session::get(SESSION_TIMEZONE); + $format = Session::get(SESSION_DATE_FORMAT); + + $dateTime = DateTime::createFromFormat('Y-m-d', $date, new DateTimeZone($timezone)); + + return $formatResult ? $dateTime->format($format) : $dateTime; + } + + public static function today($formatResult = true) + { + $timezone = Session::get(SESSION_TIMEZONE); + $format = Session::get(SESSION_DATE_FORMAT); + $date = date_create(null, new DateTimeZone($timezone)); + + if ($formatResult) { + return $date->format($format); + } else { + return $date; + } + } + + public static function trackViewed($name, $type, $url = false) + { + if (!$url) { + $url = Request::url(); + } + + $viewed = Session::get(RECENTLY_VIEWED); + + if (!$viewed) { + $viewed = []; + } + + $object = new stdClass(); + $object->url = $url; + $object->name = ucwords($type).': '.$name; + + $data = []; + + for ($i = 0; $iurl == $item->url || $object->name == $item->name) { + continue; + } + + array_unshift($data, $item); + } + + array_unshift($data, $object); + + if (count($data) > RECENTLY_VIEWED_LIMIT) { + array_pop($data); + } + + Session::put(RECENTLY_VIEWED, $data); + } + + public static function processVariables($str) + { + if (!$str) { + return ''; + } + + $variables = ['MONTH', 'QUARTER', 'YEAR']; + for ($i = 0; $i 1) { + $offset = intval($addArray[1]); + } elseif (count($minArray) > 1) { + $offset = intval($minArray[1]) * -1; + } + + $val = Utils::getDatePart($variable, $offset); + $str = str_replace($match, $val, $str); + } + } + + return $str; + } + + private static function getDatePart($part, $offset) + { + $offset = intval($offset); + if ($part == 'MONTH') { + return Utils::getMonth($offset); + } elseif ($part == 'QUARTER') { + return Utils::getQuarter($offset); + } elseif ($part == 'YEAR') { + return Utils::getYear($offset); + } + } + + private static function getMonth($offset) + { + $months = [ "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December", ]; + + $month = intval(date('n')) - 1; + + $month += $offset; + $month = $month % 12; + + if ($month < 0) { + $month += 12; + } + + return $months[$month]; + } + + private static function getQuarter($offset) + { + $month = intval(date('n')) - 1; + $quarter = floor(($month + 3) / 3); + $quarter += $offset; + $quarter = $quarter % 4; + if ($quarter == 0) { + $quarter = 4; + } + + return 'Q'.$quarter; + } + + private static function getYear($offset) + { + $year = intval(date('Y')); + + return $year + $offset; + } + + public static function getEntityName($entityType) + { + return ucwords(str_replace('_', ' ', $entityType)); + } + + public static function getClientDisplayName($model) + { + if ($model->client_name) { + return $model->client_name; + } elseif ($model->first_name || $model->last_name) { + return $model->first_name.' '.$model->last_name; + } else { + return $model->email; + } + } + + public static function encodeActivity($person = null, $action, $entity = null, $otherPerson = null) + { + $person = $person ? $person->getDisplayName() : 'System'; + $entity = $entity ? '['.$entity->getActivityKey().']' : ''; + $otherPerson = $otherPerson ? 'to '.$otherPerson->getDisplayName() : ''; + + return trim("$person $action $entity $otherPerson"); + } + + public static function decodeActivity($message) + { + $pattern = '/\[([\w]*):([\d]*):(.*)\]/i'; + preg_match($pattern, $message, $matches); + + if (count($matches) > 0) { + $match = $matches[0]; + $type = $matches[1]; + $publicId = $matches[2]; + $name = $matches[3]; + + $link = link_to($type.'s/'.$publicId, $name); + $message = str_replace($match, "$type $link", $message); + } + + return $message; + } + + public static function generateLicense() + { + $parts = []; + for ($i = 0; $i<5; $i++) { + $parts[] = strtoupper(str_random(4)); + } + + return implode('-', $parts); + } + + public static function lookupEventId($eventName) + { + if ($eventName == 'create_client') { + return EVENT_CREATE_CLIENT; + } elseif ($eventName == 'create_invoice') { + return EVENT_CREATE_INVOICE; + } elseif ($eventName == 'create_quote') { + return EVENT_CREATE_QUOTE; + } elseif ($eventName == 'create_payment') { + return EVENT_CREATE_PAYMENT; + } else { + return false; + } + } + + public static function notifyZapier($subscription, $data) + { + $curl = curl_init(); + + $jsonEncodedData = json_encode($data->toJson()); + $opts = [ + CURLOPT_URL => $subscription->target_url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_POST => 1, + CURLOPT_POSTFIELDS => $jsonEncodedData, + CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Content-Length: '.strlen($jsonEncodedData)], + ]; + + curl_setopt_array($curl, $opts); + + $result = curl_exec($curl); + $status = curl_getinfo($curl, CURLINFO_HTTP_CODE); + + curl_close($curl); + + if ($status == 410) { + $subscription->delete(); + } + } + + public static function remapPublicIds($data) + { + foreach ($data as $index => $record) { + if (!isset($data[$index]['public_id'])) { + continue; + } + $data[$index]['id'] = $data[$index]['public_id']; + unset($data[$index]['public_id']); + + foreach ($record as $key => $val) { + if (is_array($val)) { + $data[$index][$key] = Utils::remapPublicIds($val); + } + } + } + + return $data; + } + + public static function getApiHeaders($count = 0) + { + return [ + 'Content-Type' => 'application/json', + //'Access-Control-Allow-Origin' => '*', + //'Access-Control-Allow-Methods' => 'GET', + //'Access-Control-Allow-Headers' => 'Origin, Content-Type, Accept, Authorization, X-Requested-With', + //'Access-Control-Allow-Credentials' => 'true', + 'X-Total-Count' => $count, + //'X-Rate-Limit-Limit' - The number of allowed requests in the current period + //'X-Rate-Limit-Remaining' - The number of remaining requests in the current period + //'X-Rate-Limit-Reset' - The number of seconds left in the current period, + ]; + } + + public static function startsWith($haystack, $needle) + { + return $needle === "" || strpos($haystack, $needle) === 0; + } + + public static function endsWith($haystack, $needle) + { + return $needle === "" || substr($haystack, -strlen($needle)) === $needle; + } + + public static function getEntityRowClass($model) + { + $str = $model->is_deleted || ($model->deleted_at && $model->deleted_at != '0000-00-00') ? 'DISABLED ' : ''; + + if ($model->is_deleted) { + $str .= 'ENTITY_DELETED '; + } + + if ($model->deleted_at && $model->deleted_at != '0000-00-00') { + $str .= 'ENTITY_ARCHIVED '; + } + + return $str; + } +} diff --git a/app/ninja/repositories/InvoiceRepository.php b/app/ninja/repositories/InvoiceRepository.php index c099706fc717..c964d558a907 100755 --- a/app/ninja/repositories/InvoiceRepository.php +++ b/app/ninja/repositories/InvoiceRepository.php @@ -220,7 +220,7 @@ class InvoiceRepository $invoice->is_quote = true; } } - + $invoice->client_id = $data['client_id']; $invoice->discount = round(Utils::parseFloat($data['discount']), 2); $invoice->is_amount_discount = $data['is_amount_discount'] ? true : false; diff --git a/app/start/global.php b/app/start/global.php index c4a93c78d2e2..616e8fcebb8f 100755 --- a/app/start/global.php +++ b/app/start/global.php @@ -58,13 +58,11 @@ $monolog->pushHandler(new Monolog\Handler\SyslogHandler('intranet', 'user', Logg App::error(function(Exception $exception, $code) { - if (Utils::isNinjaProd()) - { - Utils::logError($code . ' ' . Utils::getErrorString($exception)); - return Response::view('error', ['hideHeader' => true, 'error' => "A {$code} error occurred."], $code); - } - else - { + Utils::logError($code . ' ' . Utils::getErrorString($exception)); + + if (Utils::isNinjaProd()) { + return Response::view('error', ['hideHeader' => true, 'error' => "A {$code} error occurred."], $code); + } else { return null; } }); diff --git a/app/views/emails/confirm_html.blade.php b/app/views/emails/confirm_html.blade.php index c7ad995255ba..c482b0fa841a 100755 --- a/app/views/emails/confirm_html.blade.php +++ b/app/views/emails/confirm_html.blade.php @@ -20,7 +20,7 @@

    {{ trans('texts.confirmation_header') }}

    - {{ $invitationMessage . trans('texts.confirmation_message') }} + {{ $invitationMessage . trans('texts.confirmation_message') }}
    {{{ URL::to("user/confirm/{$user->confirmation_code}") }}} diff --git a/app/views/public/terms.blade.php b/app/views/public/terms.blade.php index 4f99598cada6..c509ddde5716 100644 --- a/app/views/public/terms.blade.php +++ b/app/views/public/terms.blade.php @@ -2,6 +2,28 @@ @section('content') + + + +

    +

     

    + +
    +
    + +
    @@ -148,4 +170,8 @@

     

     

    +
    +
    +
    + @stop \ No newline at end of file From b165f477638083cb81d01bdf2db2c9c3ecf4698f Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Fri, 27 Feb 2015 10:10:23 +0200 Subject: [PATCH 24/32] Enabled creating invoices through the API --- app/controllers/ClientApiController.php | 8 - app/controllers/InvoiceApiController.php | 174 +++++++++++++++++-- app/controllers/PaymentApiController.php | 4 - app/controllers/QuoteApiController.php | 4 - app/filters.php | 41 +++++ app/handlers/InvoiceEventHandler.php | 2 +- app/libraries/utils.php | 23 +-- app/ninja/mailers/UserMailer.php | 4 +- app/ninja/repositories/InvoiceRepository.php | 51 +++--- app/routes.php | 3 +- 10 files changed, 246 insertions(+), 68 deletions(-) diff --git a/app/controllers/ClientApiController.php b/app/controllers/ClientApiController.php index 2d76dfab108b..1ce750931252 100644 --- a/app/controllers/ClientApiController.php +++ b/app/controllers/ClientApiController.php @@ -20,10 +20,6 @@ class ClientApiController extends Controller public function index() { - if (!Utils::isPro()) { - return Redirect::to('/'); - } - $clients = Client::scope()->with('contacts')->orderBy('created_at', 'desc')->get(); $clients = Utils::remapPublicIds($clients->toArray()); @@ -35,10 +31,6 @@ class ClientApiController extends Controller public function store() { - if (!Utils::isPro()) { - return Redirect::to('/'); - } - $data = Input::all(); $error = $this->clientRepo->getErrors($data); diff --git a/app/controllers/InvoiceApiController.php b/app/controllers/InvoiceApiController.php index bd488fd1ed7e..6e8696bfe87d 100644 --- a/app/controllers/InvoiceApiController.php +++ b/app/controllers/InvoiceApiController.php @@ -1,22 +1,20 @@ invoiceRepo = $invoiceRepo; + $this->mailer = $mailer; } public function index() { - if (!Utils::isPro()) { - return Redirect::to('/'); - } - $invoices = Invoice::scope()->where('invoices.is_quote', '=', false)->orderBy('created_at', 'desc')->get(); $invoices = Utils::remapPublicIds($invoices->toArray()); @@ -26,20 +24,168 @@ class InvoiceApiController extends Controller return Response::make($response, 200, $headers); } - /* public function store() { - if (!Utils::isPro()) { - return Redirect::to('/'); + $data = Input::all(); + $error = null; + + // check if the invoice number is set and unique + if (!isset($data['invoice_number'])) { + $data['invoice_number'] = Auth::user()->account->getNextInvoiceNumber(); + } else { + $invoice = Invoice::scope()->where('invoice_number', '=', $data['invoice_number'])->first(); + if ($invoice) { + $error = trans('validation.unique', ['attribute' => 'texts.invoice_number']); + } } - $data = Input::all(); - $invoice = $this->invoiceRepo->save(false, $data, false); + // check the client id is set and exists + if (!isset($data['client_id'])) { + $error = trans('validation.required', ['attribute' => 'client_id']); + } else { + $client = Client::scope($data['client_id'])->first(); + if (!$client) { + $error = trans('validation.not_in', ['attribute' => 'client_id']); + } + } + + if ($error) { + $response = json_encode($error, JSON_PRETTY_PRINT); + } else { + $data = self::prepareData($data); + $invoice = $this->invoiceRepo->save(false, $data, false); + + $invitation = Invitation::createNew(); + $invitation->invoice_id = $invoice->id; + $invitation->contact_id = $client->contacts[0]->id; + $invitation->invitation_key = str_random(RANDOM_KEY_LENGTH); + $invitation->save(); + + // prepare the return data + $invoice->load('invoice_items'); + $invoice = $invoice->toArray(); + $invoice['link'] = $invitation->getLink(); + unset($invoice['account']); + unset($invoice['client']); + $invoice = Utils::remapPublicIds($invoice); + $invoice['client_id'] = $client->public_id; + + $response = json_encode($invoice, JSON_PRETTY_PRINT); + } - $response = json_encode($invoice, JSON_PRETTY_PRINT); $headers = Utils::getApiHeaders(); - - return Response::make($response, 200, $headers); + + return Response::make($response, $error ? 400 : 200, $headers); + } + + private function prepareData($data) + { + $account = Auth::user()->account; + $account->loadLocalizationSettings(); + + // set defaults for optional fields + $fields = [ + 'discount' => 0, + 'is_amount_discount' => false, + 'terms' => $account->invoice_terms, + 'public_notes' => '', + 'po_number' => '', + 'invoice_design_id' => $account->invoice_design_id, + 'invoice_items' => [], + 'custom_value1' => 0, + 'custom_value2' => 0, + 'custom_taxes1' => false, + 'custom_taxes2' => false, + ]; + + if (!isset($data['invoice_date'])) { + $fields['invoice_date_sql'] = date_create()->format('Y-m-d'); + } + if (!isset($data['due_date'])) { + $fields['due_date_sql'] = false; + } + + foreach ($fields as $key => $val) { + if (!isset($data[$key])) { + $data[$key] = $val; + } + } + + // hardcode some fields + $fields = [ + 'is_recurring' => false + ]; + + foreach ($fields as $key => $val) { + $data[$key] = $val; + } + + // initialize the line items + if (isset($data['product_key']) || isset($data['cost']) || isset($data['notes']) || isset($data['qty'])) { + $data['invoice_items'] = [self::prepareItem($data)]; + } else { + foreach ($data['invoice_items'] as $index => $item) { + $data['invoice_items'][$index] = self::prepareItem($item); + } + } + + return $data; + } + + private function prepareItem($item) + { + $fields = [ + 'cost' => 0, + 'product_key' => '', + 'notes' => '', + 'qty' => 1 + ]; + + foreach ($fields as $key => $val) { + if (!isset($item[$key])) { + $item[$key] = $val; + } + } + + // if only the product key is set we'll load the cost and notes + if ($item['product_key'] && (!$item['cost'] || !$item['notes'])) { + $product = Product::findProductByKey($item['product_key']); + if ($product) { + if (!$item['cost']) { + $item['cost'] = $product->cost; + } + if (!$item['notes']) { + $item['notes'] = $product->notes; + } + } + } + + return $item; + } + + public function emailInvoice() + { + $data = Input::all(); + $error = null; + + if (!isset($data['id'])) { + $error = trans('validation.required', ['attribute' => 'id']); + } else { + $invoice = Invoice::scope($data['id'])->first(); + if (!$invoice) { + $error = trans('validation.not_in', ['attribute' => 'id']); + } else { + $this->mailer->sendInvoice($invoice); + } + } + + if ($error) { + $response = json_encode($error, JSON_PRETTY_PRINT); + } else { + $response = json_encode(RESULT_SUCCESS, JSON_PRETTY_PRINT); + } + + $headers = Utils::getApiHeaders(); + return Response::make($response, $error ? 400 : 200, $headers); } - */ } diff --git a/app/controllers/PaymentApiController.php b/app/controllers/PaymentApiController.php index 410069f09c66..46db0d353d2b 100644 --- a/app/controllers/PaymentApiController.php +++ b/app/controllers/PaymentApiController.php @@ -13,10 +13,6 @@ class PaymentApiController extends Controller public function index() { - if (!Utils::isPro()) { - return Redirect::to('/'); - } - $payments = Payment::scope()->orderBy('created_at', 'desc')->get(); $payments = Utils::remapPublicIds($payments->toArray()); diff --git a/app/controllers/QuoteApiController.php b/app/controllers/QuoteApiController.php index 5b442516d088..713f92997cb6 100644 --- a/app/controllers/QuoteApiController.php +++ b/app/controllers/QuoteApiController.php @@ -13,10 +13,6 @@ class QuoteApiController extends Controller public function index() { - if (!Utils::isPro()) { - return Redirect::to('/'); - } - $invoices = Invoice::scope()->where('invoices.is_quote', '=', true)->orderBy('created_at', 'desc')->get(); $invoices = Utils::remapPublicIds($invoices->toArray()); diff --git a/app/filters.php b/app/filters.php index 74ee30ac001c..3792f38a9d11 100755 --- a/app/filters.php +++ b/app/filters.php @@ -173,6 +173,47 @@ Route::filter('auth.basic', function() return Auth::basic(); }); +Route::filter('api.access', function() +{ + $headers = Utils::getApiHeaders(); + + if (!Utils::isPro()) { + return Response::make('API requires pro plan', 403, $headers); + } else { + $accountId = Auth::user()->account->id; + + // http://stackoverflow.com/questions/1375501/how-do-i-throttle-my-sites-api-users + $hour = 60 * 60; + $hour_limit = 100; # users are limited to 100 requests/hour + $hour_throttle = Cache::get("hour_throttle:{$accountId}", null); + $last_api_request = Cache::get("last_api_request:{$accountId}", 0); + $last_api_diff = time() - $last_api_request; + + if (is_null($hour_throttle)) { + $new_hour_throttle = 0; + } else { + $new_hour_throttle = $hour_throttle - $last_api_diff; + $new_hour_throttle = $new_hour_throttle < 0 ? 0 : $new_hour_throttle; + $new_hour_throttle += $hour / $hour_limit; + $hour_hits_remaining = floor(( $hour - $new_hour_throttle ) * $hour_limit / $hour); + $hour_hits_remaining = $hour_hits_remaining >= 0 ? $hour_hits_remaining : 0; + } + + if ($new_hour_throttle > $hour) { + $wait = ceil($new_hour_throttle - $hour); + sleep(1); + return Response::make("Please wait {$wait} second(s)", 403, $headers); + } + + Cache::put("hour_throttle:{$accountId}", $new_hour_throttle, 10); + Cache::put("last_api_request:{$accountId}", time(), 10); + } + + return null; +}); + + + /* |-------------------------------------------------------------------------- | Guest Filter diff --git a/app/handlers/InvoiceEventHandler.php b/app/handlers/InvoiceEventHandler.php index 243d096dcd0b..7b6f4e9cc52b 100755 --- a/app/handlers/InvoiceEventHandler.php +++ b/app/handlers/InvoiceEventHandler.php @@ -44,7 +44,7 @@ class InvoiceEventHandler { if ($user->{'notify_' . $type}) { - $this->userMailer->sendNotification($user, $invoice, $type, $payment); + $this->userMailer->sendNotification($user, $invoice, $type, $payment); } } } diff --git a/app/libraries/utils.php b/app/libraries/utils.php index 89f0427e921f..03d892cd2579 100755 --- a/app/libraries/utils.php +++ b/app/libraries/utils.php @@ -539,23 +539,26 @@ class utils } } - public static function remapPublicIds($data) + + public static function remapPublicIds(array $data) { - foreach ($data as $index => $record) { - if (!isset($data[$index]['public_id'])) { + $return = []; + + foreach ($data as $key => $val) { + if ($key === 'public_id') { + $key = 'id'; + } elseif (strpos($key, '_id')) { continue; } - $data[$index]['id'] = $data[$index]['public_id']; - unset($data[$index]['public_id']); - foreach ($record as $key => $val) { - if (is_array($val)) { - $data[$index][$key] = Utils::remapPublicIds($val); - } + if (is_array($val)) { + $val = Utils::remapPublicIds($val); } + + $return[$key] = $val; } - return $data; + return $return; } public static function getApiHeaders($count = 0) diff --git a/app/ninja/mailers/UserMailer.php b/app/ninja/mailers/UserMailer.php index c8bb82cf8c86..12e7bedd60eb 100755 --- a/app/ninja/mailers/UserMailer.php +++ b/app/ninja/mailers/UserMailer.php @@ -37,7 +37,7 @@ class UserMailer extends Mailer if (!$user->email) { return; } - + $view = 'invoice_'.$notificationType; $entityType = $invoice->getEntityType(); @@ -56,7 +56,7 @@ class UserMailer extends Mailer } $subject = trans("texts.notification_{$entityType}_{$notificationType}_subject", ['invoice' => $invoice->invoice_number, 'client' => $invoice->client->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 c964d558a907..cef04eb2dbeb 100755 --- a/app/ninja/repositories/InvoiceRepository.php +++ b/app/ninja/repositories/InvoiceRepository.php @@ -220,13 +220,13 @@ class InvoiceRepository $invoice->is_quote = true; } } - + $invoice->client_id = $data['client_id']; $invoice->discount = round(Utils::parseFloat($data['discount']), 2); $invoice->is_amount_discount = $data['is_amount_discount'] ? true : false; $invoice->invoice_number = trim($data['invoice_number']); $invoice->is_recurring = $data['is_recurring'] && !Utils::isDemo() ? true : false; - $invoice->invoice_date = Utils::toSqlDate($data['invoice_date']); + $invoice->invoice_date = isset($data['invoice_date_sql']) ? $data['invoice_date_sql'] : Utils::toSqlDate($data['invoice_date']); if ($invoice->is_recurring) { $invoice->frequency_id = $data['frequency_id'] ? $data['frequency_id'] : 0; @@ -234,7 +234,7 @@ class InvoiceRepository $invoice->end_date = Utils::toSqlDate($data['end_date']); $invoice->due_date = null; } else { - $invoice->due_date = Utils::toSqlDate($data['due_date']); + $invoice->due_date = isset($data['due_date_sql']) ? $data['due_date_sql'] : Utils::toSqlDate($data['due_date']); $invoice->frequency_id = 0; $invoice->start_date = null; $invoice->end_date = null; @@ -256,16 +256,17 @@ class InvoiceRepository $total = 0; foreach ($data['invoice_items'] as $item) { - if (!$item->cost && !$item->product_key && !$item->notes) { + $item = (array) $item; + if (!$item['cost'] && !$item['product_key'] && !$item['notes']) { continue; } - $invoiceItemCost = Utils::parseFloat($item->cost); - $invoiceItemQty = Utils::parseFloat($item->qty); + $invoiceItemCost = Utils::parseFloat($item['cost']); + $invoiceItemQty = Utils::parseFloat($item['qty']); $invoiceItemTaxRate = 0; - if (isset($item->tax_rate) && Utils::parseFloat($item->tax_rate) > 0) { - $invoiceItemTaxRate = Utils::parseFloat($item->tax_rate); + if (isset($item['tax_rate']) && Utils::parseFloat($item['tax_rate']) > 0) { + $invoiceItemTaxRate = Utils::parseFloat($item['tax_rate']); } $lineTotal = $invoiceItemCost * $invoiceItemQty; @@ -314,25 +315,27 @@ class InvoiceRepository $invoice->amount = $total; $invoice->save(); - $invoice->invoice_items()->forceDelete(); + if ($publicId) { + $invoice->invoice_items()->forceDelete(); + } foreach ($data['invoice_items'] as $item) { - if (!$item->cost && !$item->product_key && !$item->notes) { + $item = (array) $item; + if (!$item['cost'] && !$item['product_key'] && !$item['notes']) { continue; } - if ($item->product_key) { - $product = Product::findProductByKey(trim($item->product_key)); + if ($item['product_key']) { + $product = Product::findProductByKey(trim($item['product_key'])); if (!$product) { $product = Product::createNew(); - $product->product_key = trim($item->product_key); + $product->product_key = trim($item['product_key']); } if (\Auth::user()->account->update_products) { - $product->notes = $item->notes; - $product->cost = $item->cost; - //$product->qty = $item->qty; + $product->notes = $item['notes']; + $product->cost = $item['cost']; } $product->save(); @@ -340,21 +343,21 @@ class InvoiceRepository $invoiceItem = InvoiceItem::createNew(); $invoiceItem->product_id = isset($product) ? $product->id : null; - $invoiceItem->product_key = trim($invoice->is_recurring ? $item->product_key : Utils::processVariables($item->product_key)); - $invoiceItem->notes = trim($invoice->is_recurring ? $item->notes : Utils::processVariables($item->notes)); - $invoiceItem->cost = Utils::parseFloat($item->cost); - $invoiceItem->qty = Utils::parseFloat($item->qty); + $invoiceItem->product_key = trim($invoice->is_recurring ? $item->product_key : Utils::processVariables($item['product_key'])); + $invoiceItem->notes = trim($invoice->is_recurring ? $item['notes'] : Utils::processVariables($item['notes'])); + $invoiceItem->cost = Utils::parseFloat($item['cost']); + $invoiceItem->qty = Utils::parseFloat($item['qty']); $invoiceItem->tax_rate = 0; - if (isset($item->tax_rate) && isset($item->tax_name) && $item->tax_name) { - $invoiceItem->tax_rate = Utils::parseFloat($item->tax_rate); - $invoiceItem->tax_name = trim($item->tax_name); + if (isset($item['tax_rate']) && isset($item['tax_name']) && $item['tax_name']) { + $invoiceItem['tax_rate'] = Utils::parseFloat($item['tax_rate']); + $invoiceItem['tax_name'] = trim($item['tax_name']); } $invoice->invoice_items()->save($invoiceItem); } - if ($data['set_default_terms']) { + if (isset($data['set_default_terms']) && $data['set_default_terms']) { $account = \Auth::user()->account; $account->invoice_terms = $invoice->terms; $account->save(); diff --git a/app/routes.php b/app/routes.php index 1d0cedaa7308..d142ba616b39 100755 --- a/app/routes.php +++ b/app/routes.php @@ -142,7 +142,7 @@ Route::group(array('before' => 'auth'), function() { }); // Route group for API -Route::group(array('prefix' => 'api/v1', 'before' => 'auth.basic'), function() +Route::group(array('prefix' => 'api/v1', 'before' => ['auth.basic', 'api.access']), function() { Route::resource('ping', 'ClientApiController@ping'); Route::resource('clients', 'ClientApiController'); @@ -150,6 +150,7 @@ Route::group(array('prefix' => 'api/v1', 'before' => 'auth.basic'), function() Route::resource('quotes', 'QuoteApiController'); Route::resource('payments', 'PaymentApiController'); Route::post('api/hooks', 'IntegrationController@subscribe'); + Route::post('email_invoice', 'InvoiceApiController@emailInvoice'); }); define('CONTACT_EMAIL', Config::get('mail.from.address')); From dc117dbaff3fa82b1f30cf2fa9340d6c5c1d6fe9 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Fri, 27 Feb 2015 10:37:26 +0200 Subject: [PATCH 25/32] Bug fixes --- .../2015_02_27_081836_add_invoice_footer.php | 44 +++++++++++++++++++ app/libraries/{utils.php => Utils.php} | 2 +- 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 app/database/migrations/2015_02_27_081836_add_invoice_footer.php rename app/libraries/{utils.php => Utils.php} (99%) diff --git a/app/database/migrations/2015_02_27_081836_add_invoice_footer.php b/app/database/migrations/2015_02_27_081836_add_invoice_footer.php new file mode 100644 index 000000000000..6d1cfb7a9efa --- /dev/null +++ b/app/database/migrations/2015_02_27_081836_add_invoice_footer.php @@ -0,0 +1,44 @@ +text('invoice_footer')->nullable(); + }); + + Schema::table('invoices', function($table) + { + $table->text('invoice_footer')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('accounts', function($table) + { + $table->dropColumn('invoice_footer'); + }); + + Schema::table('invoices', function($table) + { + $table->dropColumn('invoice_footer'); + }); + } + +} diff --git a/app/libraries/utils.php b/app/libraries/Utils.php similarity index 99% rename from app/libraries/utils.php rename to app/libraries/Utils.php index 03d892cd2579..98c209ac63f1 100755 --- a/app/libraries/utils.php +++ b/app/libraries/Utils.php @@ -1,6 +1,6 @@ Date: Sat, 28 Feb 2015 23:42:47 +0200 Subject: [PATCH 26/32] Enabled setting an invoice footer --- LICENSE | 3 +- app/commands/SendRecurringInvoices.php | 1 + app/controllers/AccountController.php | 1 + app/controllers/InvoiceApiController.php | 3 +- app/lang/da/texts.php | 3 + app/lang/de/texts.php | 3 + app/lang/en/texts.php | 7 +- app/lang/es/texts.php | 3 + app/lang/fr/texts.php | 5 +- app/lang/it/texts.php | 3 + app/lang/lt/texts.php | 3 + app/lang/nb_NO/texts.php | 5 +- app/lang/nl/texts.php | 3 + app/lang/pt_BR/texts.php | 3 + app/models/Activity.php | 38 ++++---- app/models/Invoice.php | 1 + app/ninja/repositories/InvoiceRepository.php | 17 +++- app/views/accounts/notifications.blade.php | 3 +- app/views/invoices/edit.blade.php | 94 ++++++++++++++------ app/views/invoices/pdf.blade.php | 2 +- public/built.js | 17 ++++ public/js/script.js | 17 ++++ 22 files changed, 178 insertions(+), 57 deletions(-) diff --git a/LICENSE b/LICENSE index 81e4a1266c5c..eaa9f1e3672c 100644 --- a/LICENSE +++ b/LICENSE @@ -13,7 +13,8 @@ open-source software. 1. Redistributions of source code, in whole or part and with or without modification requires the express permission of the author and must prominently -display "Powered by InvoiceNinja" in verifiable form with hyperlink to said site. +display "Powered by InvoiceNinja" or the Invoice Ninja logo in verifiable form +with hyperlink to said site. 2. Neither the name nor any trademark of the Author may be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/app/commands/SendRecurringInvoices.php b/app/commands/SendRecurringInvoices.php index dda7bdc85e62..b527e7ae48bd 100755 --- a/app/commands/SendRecurringInvoices.php +++ b/app/commands/SendRecurringInvoices.php @@ -53,6 +53,7 @@ class SendRecurringInvoices extends Command $invoice->po_number = $recurInvoice->po_number; $invoice->public_notes = $recurInvoice->public_notes; $invoice->terms = $recurInvoice->terms; + $invoice->invoice_footer = $recurInvoice->invoice_footer; $invoice->tax_name = $recurInvoice->tax_name; $invoice->tax_rate = $recurInvoice->tax_rate; $invoice->invoice_design_id = $recurInvoice->invoice_design_id; diff --git a/app/controllers/AccountController.php b/app/controllers/AccountController.php index 70e1cbb639d6..52caaae72076 100755 --- a/app/controllers/AccountController.php +++ b/app/controllers/AccountController.php @@ -597,6 +597,7 @@ class AccountController extends \BaseController { $account = Auth::user()->account; $account->invoice_terms = Input::get('invoice_terms'); + $account->invoice_footer = Input::get('invoice_footer'); $account->email_footer = Input::get('email_footer'); $account->save(); diff --git a/app/controllers/InvoiceApiController.php b/app/controllers/InvoiceApiController.php index 6e8696bfe87d..40c63ea30d9c 100644 --- a/app/controllers/InvoiceApiController.php +++ b/app/controllers/InvoiceApiController.php @@ -87,7 +87,8 @@ class InvoiceApiController extends Controller $fields = [ 'discount' => 0, 'is_amount_discount' => false, - 'terms' => $account->invoice_terms, + 'terms' => '', + 'invoice_footer' => '', 'public_notes' => '', 'po_number' => '', 'invoice_design_id' => $account->invoice_design_id, diff --git a/app/lang/da/texts.php b/app/lang/da/texts.php index 71870293bce2..74ba37fec136 100644 --- a/app/lang/da/texts.php +++ b/app/lang/da/texts.php @@ -535,5 +535,8 @@ return array( 'match_address' => '*Address must match address accociated with credit card.', 'click_once' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.', + 'default_invoice_footer' => 'Set default invoice footer', + 'invoice_footer' => 'Invoice footer', + 'save_as_default_footer' => 'Save as default footer', ); diff --git a/app/lang/de/texts.php b/app/lang/de/texts.php index 54351d10c4e0..4d72f3ad1eed 100644 --- a/app/lang/de/texts.php +++ b/app/lang/de/texts.php @@ -525,5 +525,8 @@ return array( 'match_address' => '*Address must match address accociated with credit card.', 'click_once' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.', + 'default_invoice_footer' => 'Set default invoice footer', + 'invoice_footer' => 'Invoice footer', + 'save_as_default_footer' => 'Save as default footer', ); diff --git a/app/lang/en/texts.php b/app/lang/en/texts.php index 99d84e7d387b..bd1b30a554e5 100644 --- a/app/lang/en/texts.php +++ b/app/lang/en/texts.php @@ -194,8 +194,8 @@ return array( 'email_paid' => 'Email me when an invoice is paid', 'site_updates' => 'Site Updates', 'custom_messages' => 'Custom Messages', - 'default_invoice_terms' => 'Set default invoice terms', - 'default_email_footer' => 'Set default email signature', + 'default_invoice_terms' => 'Set default invoice terms', + 'default_email_footer' => 'Set default email signature', 'import_clients' => 'Import Client Data', 'csv_file' => 'Select CSV file', 'export_clients' => 'Export Client Data', @@ -533,5 +533,8 @@ return array( 'match_address' => '*Address must match address accociated with credit card.', 'click_once' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.', + 'default_invoice_footer' => 'Set default invoice footer', + 'invoice_footer' => 'Invoice footer', + 'save_as_default_footer' => 'Save as default footer', ); diff --git a/app/lang/es/texts.php b/app/lang/es/texts.php index b1d5e79f70ae..752581c83783 100644 --- a/app/lang/es/texts.php +++ b/app/lang/es/texts.php @@ -505,5 +505,8 @@ return array( 'match_address' => '*Address must match address accociated with credit card.', 'click_once' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.', + 'default_invoice_footer' => 'Set default invoice footer', + 'invoice_footer' => 'Invoice footer', + 'save_as_default_footer' => 'Save as default footer', ); \ No newline at end of file diff --git a/app/lang/fr/texts.php b/app/lang/fr/texts.php index ff2cf1b9920d..676fa142100b 100644 --- a/app/lang/fr/texts.php +++ b/app/lang/fr/texts.php @@ -525,6 +525,9 @@ return array( 'order_overview' => 'Order overview', 'match_address' => '*Address must match address accociated with credit card.', 'click_once' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.', - + + 'default_invoice_footer' => 'Set default invoice footer', + 'invoice_footer' => 'Invoice footer', + 'save_as_default_footer' => 'Save as default footer', ); \ No newline at end of file diff --git a/app/lang/it/texts.php b/app/lang/it/texts.php index 264dd9c2e02f..68e9b52800fc 100644 --- a/app/lang/it/texts.php +++ b/app/lang/it/texts.php @@ -528,5 +528,8 @@ return array( 'match_address' => '*Address must match address accociated with credit card.', 'click_once' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.', + 'default_invoice_footer' => 'Set default invoice footer', + 'invoice_footer' => 'Invoice footer', + 'save_as_default_footer' => 'Save as default footer', ); diff --git a/app/lang/lt/texts.php b/app/lang/lt/texts.php index 77eb85a0ec5f..43b28f4b9260 100644 --- a/app/lang/lt/texts.php +++ b/app/lang/lt/texts.php @@ -536,6 +536,9 @@ return array( 'match_address' => '*Address must match address accociated with credit card.', 'click_once' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.', + 'default_invoice_footer' => 'Set default invoice footer', + 'invoice_footer' => 'Invoice footer', + 'save_as_default_footer' => 'Save as default footer', ); diff --git a/app/lang/nb_NO/texts.php b/app/lang/nb_NO/texts.php index 20a594bf2c4e..68fdefc62d14 100644 --- a/app/lang/nb_NO/texts.php +++ b/app/lang/nb_NO/texts.php @@ -533,7 +533,10 @@ return array( 'order_overview' => 'Order overview', 'match_address' => '*Address must match address accociated with credit card.', 'click_once' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.', - + + 'default_invoice_footer' => 'Set default invoice footer', + 'invoice_footer' => 'Invoice footer', + 'save_as_default_footer' => 'Save as default footer', ); \ No newline at end of file diff --git a/app/lang/nl/texts.php b/app/lang/nl/texts.php index 60b8a25203cf..950e77bc9b89 100644 --- a/app/lang/nl/texts.php +++ b/app/lang/nl/texts.php @@ -529,6 +529,9 @@ return array( 'match_address' => '*Address must match address accociated with credit card.', 'click_once' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.', + 'default_invoice_footer' => 'Set default invoice footer', + 'invoice_footer' => 'Invoice footer', + 'save_as_default_footer' => 'Save as default footer', ); \ No newline at end of file diff --git a/app/lang/pt_BR/texts.php b/app/lang/pt_BR/texts.php index 4e02fde455ee..7a12139699e2 100644 --- a/app/lang/pt_BR/texts.php +++ b/app/lang/pt_BR/texts.php @@ -516,5 +516,8 @@ return array( 'match_address' => '*Address must match address accociated with credit card.', 'click_once' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.', + 'default_invoice_footer' => 'Set default invoice footer', + 'invoice_footer' => 'Invoice footer', + 'save_as_default_footer' => 'Save as default footer', ); diff --git a/app/models/Activity.php b/app/models/Activity.php index f15506d435cd..c900ee1db4bd 100755 --- a/app/models/Activity.php +++ b/app/models/Activity.php @@ -177,26 +177,32 @@ class Activity extends Eloquent } else { $diff = floatval($invoice->amount) - floatval($invoice->getOriginal('amount')); - if ($diff == 0) { - return; + $fieldChanged = false; + foreach (['invoice_number', 'po_number', 'invoice_date', 'due_date', 'terms', 'public_notes', 'invoice_footer'] as $field) { + if ($invoice->$field != $invoice->getOriginal($field)) { + $fieldChanged = true; + break; + } } - $backupInvoice = Invoice::with('invoice_items', 'client.account', 'client.contacts')->find($invoice->id); + if ($diff > 0 || $fieldChanged) { + $backupInvoice = Invoice::with('invoice_items', 'client.account', 'client.contacts')->find($invoice->id); - if (!$invoice->is_quote && !$invoice->is_recurring) { - $client->balance = $client->balance + $diff; - $client->save(); + if ($diff > 0 && !$invoice->is_quote && !$invoice->is_recurring) { + $client->balance = $client->balance + $diff; + $client->save(); + } + + $activity = Activity::getBlank($invoice); + $activity->client_id = $invoice->client_id; + $activity->invoice_id = $invoice->id; + $activity->activity_type_id = $invoice->is_quote ? ACTIVITY_TYPE_UPDATE_QUOTE : ACTIVITY_TYPE_UPDATE_INVOICE; + $activity->message = Utils::encodeActivity(Auth::user(), 'updated', $invoice); + $activity->balance = $client->balance; + $activity->adjustment = $invoice->is_quote || $invoice->is_recurring ? 0 : $diff; + $activity->json_backup = $backupInvoice->hidePrivateFields()->toJSON(); + $activity->save(); } - - $activity = Activity::getBlank($invoice); - $activity->client_id = $invoice->client_id; - $activity->invoice_id = $invoice->id; - $activity->activity_type_id = $invoice->is_quote ? ACTIVITY_TYPE_UPDATE_QUOTE : ACTIVITY_TYPE_UPDATE_INVOICE; - $activity->message = Utils::encodeActivity(Auth::user(), 'updated', $invoice); - $activity->balance = $client->balance; - $activity->adjustment = $invoice->is_quote || $invoice->is_recurring ? 0 : $diff; - $activity->json_backup = $backupInvoice->hidePrivateFields()->toJSON(); - $activity->save(); } } diff --git a/app/models/Invoice.php b/app/models/Invoice.php index b5f7cad5bbc6..0d7687d4a8fe 100755 --- a/app/models/Invoice.php +++ b/app/models/Invoice.php @@ -77,6 +77,7 @@ class Invoice extends EntityModel 'invoice_date', 'due_date', 'terms', + 'invoice_footer', 'public_notes', 'amount', 'balance', diff --git a/app/ninja/repositories/InvoiceRepository.php b/app/ninja/repositories/InvoiceRepository.php index cef04eb2dbeb..8624c3d9e91d 100755 --- a/app/ninja/repositories/InvoiceRepository.php +++ b/app/ninja/repositories/InvoiceRepository.php @@ -221,6 +221,8 @@ class InvoiceRepository } } + $account = \Auth::user()->account; + $invoice->client_id = $data['client_id']; $invoice->discount = round(Utils::parseFloat($data['discount']), 2); $invoice->is_amount_discount = $data['is_amount_discount'] ? true : false; @@ -240,7 +242,8 @@ class InvoiceRepository $invoice->end_date = null; } - $invoice->terms = trim($data['terms']); + $invoice->terms = trim($data['terms']) ? trim($data['terms']) : $account->invoice_terms; + $invoice->invoice_footer = trim($data['invoice_footer']) ? trim($data['invoice_footer']) : $account->invoice_footer; $invoice->public_notes = trim($data['public_notes']); $invoice->po_number = trim($data['po_number']); $invoice->invoice_design_id = $data['invoice_design_id']; @@ -357,9 +360,14 @@ class InvoiceRepository $invoice->invoice_items()->save($invoiceItem); } - if (isset($data['set_default_terms']) && $data['set_default_terms']) { - $account = \Auth::user()->account; - $account->invoice_terms = $invoice->terms; + if ((isset($data['set_default_terms']) && $data['set_default_terms']) + || (isset($data['set_default_footer']) && $data['set_default_footer'])) { + if (isset($data['set_default_terms']) && $data['set_default_terms']) { + $account->invoice_terms = trim($data['terms']); + } + if (isset($data['set_default_footer']) && $data['set_default_footer']) { + $account->invoice_footer = trim($data['invoice_footer']); + } $account->save(); } @@ -400,6 +408,7 @@ class InvoiceRepository 'start_date', 'end_date', 'terms', + 'invoice_footer', 'public_notes', 'invoice_design_id', 'tax_name', diff --git a/app/views/accounts/notifications.blade.php b/app/views/accounts/notifications.blade.php index 7cebf0efbd39..08e0c97b4d82 100755 --- a/app/views/accounts/notifications.blade.php +++ b/app/views/accounts/notifications.blade.php @@ -37,7 +37,8 @@
    {{ Former::legend('custom_messages') }} - {{ Former::textarea('invoice_terms')->label(trans('texts.default_invoice_terms')) }} + {{ Former::textarea('invoice_terms')->label(trans('texts.default_invoice_terms')) }} + {{ Former::textarea('invoice_footer')->label(trans('texts.default_invoice_footer')) }} {{ Former::textarea('email_footer')->label(trans('texts.default_email_footer')) }} {{ Former::actions( Button::lg_success_submit(trans('texts.save'))->append_with_icon('floppy-disk') ) }} diff --git a/app/views/invoices/edit.blade.php b/app/views/invoices/edit.blade.php index 47aaefb211b9..1c5a0fc36a7d 100755 --- a/app/views/invoices/edit.blade.php +++ b/app/views/invoices/edit.blade.php @@ -165,16 +165,36 @@
    - {{ Former::textarea('public_notes')->data_bind("value: wrapped_notes, valueUpdate: 'afterkeydown'") - ->label(false)->placeholder(trans('texts.note_to_client'))->style('resize: none') }} - {{ Former::textarea('terms')->data_bind("value: wrapped_terms, valueUpdate: 'afterkeydown'") - ->label(false)->placeholder(trans('texts.invoice_terms'))->style('resize: none') - ->addGroupClass('less-space-bottom') }} - +
    + + + +
    +
    + {{ Former::textarea('public_notes')->data_bind("value: wrapped_notes, valueUpdate: 'afterkeydown'") + ->label(null)->style('resize: none; min-width: 460px;')->rows(3) }} +
    +
    + {{ Former::textarea('terms')->data_bind("value:wrapped_terms, placeholder: default_terms, valueUpdate: 'afterkeydown'") + ->label(false)->style('resize: none; min-width: 460px')->rows(3) + ->help('') }} +
    + +
    +
    + - + {{ trans('texts.subtotal') }} @@ -243,7 +263,7 @@ - + {{ trans($entityType == ENTITY_INVOICE ? 'texts.balance_due' : 'texts.total') }} @@ -568,7 +588,7 @@ }); } - $('#terms, #public_notes, #invoice_number, #invoice_date, #due_date, #po_number, #discount, #currency_id, #invoice_design_id, #recurring, #is_amount_discount').change(function() { + $('#invoice_footer, #terms, #public_notes, #invoice_number, #invoice_date, #due_date, #po_number, #discount, #currency_id, #invoice_design_id, #recurring, #is_amount_discount').change(function() { setTimeout(function() { refreshPDF(); }, 1); @@ -618,8 +638,7 @@ var client = model.invoice().client(); setComboboxValue($('.client_select'), client.public_id(), - client.name.display()); - + client.name.display()); }); function applyComboboxListeners() { @@ -653,6 +672,13 @@ invoice.is_quote = {{ $entityType == ENTITY_QUOTE ? 'true' : 'false' }}; invoice.contact = _.findWhere(invoice.client.contacts, {send_invoice: true}); + if (!invoice.terms) { + invoice.terms = "{{ $account->invoice_terms }}"; + } + if (!invoice.invoice_footer) { + invoice.invoice_footer = "{{ $account->invoice_footer }}"; + } + @if (file_exists($account->getLogoPath())) invoice.image = "{{ HTML::image_data($account->getLogoPath()) }}"; invoice.imageWidth = {{ $account->getLogoWidth() }}; @@ -1025,8 +1051,12 @@ self.is_amount_discount = ko.observable(0); self.frequency_id = ko.observable(''); //self.currency_id = ko.observable({{ $client && $client->currency_id ? $client->currency_id : Session::get(SESSION_CURRENCY) }}); - self.terms = ko.observable(wordWrapText('{{ str_replace(["\r\n","\r","\n"], '\n', addslashes($account->invoice_terms)) }}', 300)); - self.set_default_terms = ko.observable(false); + self.terms = ko.observable(''); + self.default_terms = ko.observable({{ $account->invoice_terms ? 'true' : 'false' }} ? wordWrapText('{{ str_replace(["\r\n","\r","\n"], '\n', addslashes($account->invoice_terms)) }}', 300) : "{{ trans('texts.invoice_terms') }}"); + self.set_default_terms = ko.observable(false); + self.invoice_footer = ko.observable(''); + self.default_footer = ko.observable({{ $account->invoice_footer ? 'true' : 'false' }} ? wordWrapText('{{ str_replace(["\r\n","\r","\n"], '\n', addslashes($account->invoice_footer)) }}', 600) : "{{ trans('texts.invoice_footer') }}"); + self.set_default_footer = ko.observable(false); self.public_notes = ko.observable(''); self.po_number = ko.observable(''); self.invoice_date = ko.observable('{{ Utils::today() }}'); @@ -1102,31 +1132,37 @@ self.wrapped_terms = ko.computed({ read: function() { - $('#terms').height(this.terms().split('\n').length * 36); return this.terms(); }, write: function(value) { value = wordWrapText(value, 300); self.terms(value); - $('#terms').height(value.split('\n').length * 36); }, owner: this }); - self.wrapped_notes = ko.computed({ - read: function() { - $('#public_notes').height(this.public_notes().split('\n').length * 36); - return this.public_notes(); - }, - write: function(value) { - value = wordWrapText(value, 300); - self.public_notes(value); - $('#public_notes').height(value.split('\n').length * 36); - }, - owner: this - }); + self.wrapped_notes = ko.computed({ + read: function() { + return this.public_notes(); + }, + write: function(value) { + value = wordWrapText(value, 300); + self.public_notes(value); + }, + owner: this + }); + self.wrapped_footer = ko.computed({ + read: function() { + return this.invoice_footer(); + }, + write: function(value) { + value = wordWrapText(value, 600); + self.invoice_footer(value); + }, + owner: this + }); self.removeItem = function(item) { self.invoice_items.remove(item); diff --git a/app/views/invoices/pdf.blade.php b/app/views/invoices/pdf.blade.php index 2c8c01671ddb..feb2e8234b93 100644 --- a/app/views/invoices/pdf.blade.php +++ b/app/views/invoices/pdf.blade.php @@ -69,7 +69,7 @@ } else { window.accountLogo = "{{ HTML::image_data($account->getLogoPath()) }}"; } - @endif + @endif var NINJA = NINJA || {}; NINJA.primaryColor = "{{ $account->primary_color }}"; diff --git a/public/built.js b/public/built.js index 2ab5710bea95..9fce8d058aec 100644 --- a/public/built.js +++ b/public/built.js @@ -31603,6 +31603,16 @@ function GetPdf(invoice, javascript){ eval(javascript); + // add footer + if (invoice.invoice_footer) { + doc.setFontType('normal'); + doc.setFontSize('8'); + SetPdfColor('Black',doc); + var top = doc.internal.pageSize.height - layout.marginLeft; + var numLines = invoice.invoice_footer.split("\n").length - 1; + doc.text(layout.marginLeft, top - (numLines * 8), invoice.invoice_footer); + } + return doc; } @@ -31991,6 +32001,13 @@ if (window.ko) { if (value) $(element).datepicker('update', value); } }; + + ko.bindingHandlers.placeholder = { + init: function (element, valueAccessor, allBindingsAccessor) { + var underlyingObservable = valueAccessor(); + ko.applyBindingsToNode(element, { attr: { placeholder: underlyingObservable } } ); + } + }; } function wordWrapText(value, width) diff --git a/public/js/script.js b/public/js/script.js index 6b6ff47f4978..ad7d7bc367a7 100644 --- a/public/js/script.js +++ b/public/js/script.js @@ -80,6 +80,16 @@ function GetPdf(invoice, javascript){ eval(javascript); + // add footer + if (invoice.invoice_footer) { + doc.setFontType('normal'); + doc.setFontSize('8'); + SetPdfColor('Black',doc); + var top = doc.internal.pageSize.height - layout.marginLeft; + var numLines = invoice.invoice_footer.split("\n").length - 1; + doc.text(layout.marginLeft, top - (numLines * 8), invoice.invoice_footer); + } + return doc; } @@ -468,6 +478,13 @@ if (window.ko) { if (value) $(element).datepicker('update', value); } }; + + ko.bindingHandlers.placeholder = { + init: function (element, valueAccessor, allBindingsAccessor) { + var underlyingObservable = valueAccessor(); + ko.applyBindingsToNode(element, { attr: { placeholder: underlyingObservable } } ); + } + }; } function wordWrapText(value, width) From 1453ad4a37d787aacf5a4ad95a3e09df3545d100 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Sun, 1 Mar 2015 20:15:22 +0200 Subject: [PATCH 27/32] Swapped white label and invoice design prices --- app/lang/da/texts.php | 4 ++-- app/lang/de/texts.php | 4 ++-- app/lang/en/texts.php | 4 ++-- app/lang/es/texts.php | 4 ++-- app/lang/fr/texts.php | 4 ++-- app/lang/it/texts.php | 4 ++-- app/lang/lt/texts.php | 4 ++-- app/lang/nb_NO/texts.php | 2 +- app/lang/nl/texts.php | 4 ++-- app/lang/pt_BR/texts.php | 4 ++-- app/routes.php | 5 ++++- 11 files changed, 23 insertions(+), 20 deletions(-) diff --git a/app/lang/da/texts.php b/app/lang/da/texts.php index 74ba37fec136..9996f0cb96cc 100644 --- a/app/lang/da/texts.php +++ b/app/lang/da/texts.php @@ -456,7 +456,7 @@ return array( 'more_designs_title' => 'Additional Invoice Designs', 'more_designs_cloud_header' => 'Go Pro for more invoice designs', 'more_designs_cloud_text' => '', - 'more_designs_self_host_header' => 'Get 6 more invoice designs for just $20', + 'more_designs_self_host_header' => 'Get 6 more invoice designs for just $'.INVOICE_DESIGNS_PRICE, 'more_designs_self_host_text' => '', 'buy' => 'Buy', 'bought_designs' => 'Successfully added additional invoice designs', @@ -471,7 +471,7 @@ return array( 'id_number' => 'ID Number', 'white_label_link' => 'White label', - 'white_label_text' => 'Purchase a white label license for $10.00 to remove the Invoice Ninja branding from the top of the client pages.', + 'white_label_text' => 'Purchase a white label license for $'.WHITE_LABEL_PRICE.' to remove the Invoice Ninja branding from the top of the client pages.', 'white_label_header' => 'White Label', 'bought_white_label' => 'Successfully enabled white label license', 'white_labeled' => 'White labeled', diff --git a/app/lang/de/texts.php b/app/lang/de/texts.php index 4d72f3ad1eed..ffbbf1ec2b5d 100644 --- a/app/lang/de/texts.php +++ b/app/lang/de/texts.php @@ -445,7 +445,7 @@ return array( 'more_designs_title' => 'Additional Invoice Designs', 'more_designs_cloud_header' => 'Go Pro for more invoice designs', 'more_designs_cloud_text' => '', - 'more_designs_self_host_header' => 'Get 6 more invoice designs for just $20', + 'more_designs_self_host_header' => 'Get 6 more invoice designs for just $'.INVOICE_DESIGNS_PRICE, 'more_designs_self_host_text' => '', 'buy' => 'Buy', 'bought_designs' => 'Successfully added additional invoice designs', @@ -461,7 +461,7 @@ return array( 'id_number' => 'ID-Nummer', 'white_label_link' => 'Branding entfernen', - 'white_label_text' => 'Um das Invoice Ninja Logo auf der Kundenseite zu entfernen, kaufe bitte eine Lizenz für $10.00.', + 'white_label_text' => 'Um das Invoice Ninja Logo auf der Kundenseite zu entfernen, kaufe bitte eine Lizenz für $'.WHITE_LABEL_PRICE, 'white_label_header' => 'Branding entfernen', 'bought_white_label' => 'Branding-freie Lizenz erfolgreich aktiviert', 'white_labeled' => 'Branding entfernt', diff --git a/app/lang/en/texts.php b/app/lang/en/texts.php index bd1b30a554e5..70d709660584 100644 --- a/app/lang/en/texts.php +++ b/app/lang/en/texts.php @@ -453,7 +453,7 @@ return array( 'more_designs_title' => 'Additional Invoice Designs', 'more_designs_cloud_header' => 'Go Pro for more invoice designs', 'more_designs_cloud_text' => '', - 'more_designs_self_host_header' => 'Get 6 more invoice designs for just $20', + 'more_designs_self_host_header' => 'Get 6 more invoice designs for just $'.INVOICE_DESIGNS_PRICE, 'more_designs_self_host_text' => '', 'buy' => 'Buy', 'bought_designs' => 'Successfully added additional invoice designs', @@ -469,7 +469,7 @@ return array( 'id_number' => 'ID Number', 'white_label_link' => 'White label', - 'white_label_text' => 'Purchase a white label license for $10.00 to remove the Invoice Ninja branding from the top of the client pages.', + 'white_label_text' => 'Purchase a white label license for $'.WHITE_LABEL_PRICE.' to remove the Invoice Ninja branding from the top of the client pages.', 'white_label_header' => 'White Label', 'bought_white_label' => 'Successfully enabled white label license', 'white_labeled' => 'White labeled', diff --git a/app/lang/es/texts.php b/app/lang/es/texts.php index 752581c83783..e264b2888767 100644 --- a/app/lang/es/texts.php +++ b/app/lang/es/texts.php @@ -425,7 +425,7 @@ return array( 'more_designs_title' => 'Additional Invoice Designs', 'more_designs_cloud_header' => 'Go Pro for more invoice designs', 'more_designs_cloud_text' => '', - 'more_designs_self_host_header' => 'Get 6 more invoice designs for just $20', + 'more_designs_self_host_header' => 'Get 6 more invoice designs for just $'.INVOICE_DESIGNS_PRICE, 'more_designs_self_host_text' => '', 'buy' => 'Buy', 'bought_designs' => 'Successfully added additional invoice designs', @@ -441,7 +441,7 @@ return array( 'id_number' => 'ID Number', 'white_label_link' => 'White label', - 'white_label_text' => 'Purchase a white label license for $10.00 to remove the Invoice Ninja branding from the top of the client pages.', + 'white_label_text' => 'Purchase a white label license for $'.WHITE_LABEL_PRICE.' to remove the Invoice Ninja branding from the top of the client pages.', 'white_label_header' => 'White Label', 'bought_white_label' => 'Successfully enabled white label license', 'white_labeled' => 'White labeled', diff --git a/app/lang/fr/texts.php b/app/lang/fr/texts.php index 676fa142100b..eda3e7de46d6 100644 --- a/app/lang/fr/texts.php +++ b/app/lang/fr/texts.php @@ -446,7 +446,7 @@ return array( 'more_designs_title' => 'Modèles de factures additionnels', 'more_designs_cloud_header' => 'Passez au Plan Pro pour plus de modèles', 'more_designs_cloud_text' => '', - 'more_designs_self_host_header' => 'Obtenez 6 modèles de factures additionnels pour seulement 20$', + 'more_designs_self_host_header' => 'Obtenez 6 modèles de factures additionnels pour seulement '.INVOICE_DESIGNS_PRICE.'$', 'more_designs_self_host_text' => '', 'buy' => 'Acheter', 'bought_designs' => 'Les nouveaux modèles ont été ajoutés avec succès', @@ -462,7 +462,7 @@ return array( 'id_number' => 'Numéro ID', 'white_label_link' => 'Marque blanche', - 'white_label_text' => 'Pour retirer la marque Invoice Ninja en haut de la page client, achetez un licence en marque blanche de 10,00$.', + 'white_label_text' => 'Pour retirer la marque Invoice Ninja en haut de la page client, achetez un licence en marque blanche de '.WHITE_LABEL_PRICE.'$.', 'white_label_header' => 'White Label', 'bought_white_label' => 'Successfully enabled white label license', 'white_labeled' => 'White labeled', diff --git a/app/lang/it/texts.php b/app/lang/it/texts.php index 68e9b52800fc..359bbfd5a189 100644 --- a/app/lang/it/texts.php +++ b/app/lang/it/texts.php @@ -446,7 +446,7 @@ return array( 'more_designs_title' => 'Additional Invoice Designs', 'more_designs_cloud_header' => 'Go Pro for more invoice designs', 'more_designs_cloud_text' => '', - 'more_designs_self_host_header' => 'Get 6 more invoice designs for just $20', + 'more_designs_self_host_header' => 'Get 6 more invoice designs for just $'.INVOICE_DESIGNS_PRICE, 'more_designs_self_host_text' => '', 'buy' => 'Buy', 'bought_designs' => 'Successfully added additional invoice designs', @@ -463,7 +463,7 @@ return array( 'id_number' => 'ID Number', 'white_label_link' => 'White label', - 'white_label_text' => 'Purchase a white label license for $10.00 to remove the Invoice Ninja branding from the top of the client pages.', + 'white_label_text' => 'Purchase a white label license for $'.WHITE_LABEL_PRICE.' to remove the Invoice Ninja branding from the top of the client pages.', 'white_label_header' => 'White Label', 'bought_white_label' => 'Successfully enabled white label license', 'white_labeled' => 'White labeled', diff --git a/app/lang/lt/texts.php b/app/lang/lt/texts.php index 43b28f4b9260..914c185b2202 100644 --- a/app/lang/lt/texts.php +++ b/app/lang/lt/texts.php @@ -454,7 +454,7 @@ return array( 'more_designs_title' => 'Additional Invoice Designs', 'more_designs_cloud_header' => 'Go Pro for more invoice designs', 'more_designs_cloud_text' => '', - 'more_designs_self_host_header' => 'Get 6 more invoice designs for just $20', + 'more_designs_self_host_header' => 'Get 6 more invoice designs for just $'.INVOICE_DESIGNS_PRICE, 'more_designs_self_host_text' => '', 'buy' => 'Buy', 'bought_designs' => 'Successfully added additional invoice designs', @@ -472,7 +472,7 @@ return array( 'id_number' => 'ID Number', 'white_label_link' => 'White label', - 'white_label_text' => 'Purchase a white label license for $10.00 to remove the Invoice Ninja branding from the top of the client pages.', + 'white_label_text' => 'Purchase a white label license for $'.WHITE_LABEL_PRICE.' to remove the Invoice Ninja branding from the top of the client pages.', 'white_label_header' => 'White Label', 'bought_white_label' => 'Successfully enabled white label license', 'white_labeled' => 'White labeled', diff --git a/app/lang/nb_NO/texts.php b/app/lang/nb_NO/texts.php index 68fdefc62d14..6f66e10b6d0d 100644 --- a/app/lang/nb_NO/texts.php +++ b/app/lang/nb_NO/texts.php @@ -470,7 +470,7 @@ return array( 'id_number' => 'ID Number', 'white_label_link' => 'White label', - 'white_label_text' => 'Purchase a white label license for $10.00 to remove the Invoice Ninja branding from the top of the client pages.', + 'white_label_text' => 'Purchase a white label license for $'.WHITE_LABEL_PRICE.' to remove the Invoice Ninja branding from the top of the client pages.', 'white_label_header' => 'White Label', 'bought_white_label' => 'Successfully enabled white label license', 'white_labeled' => 'White labeled', diff --git a/app/lang/nl/texts.php b/app/lang/nl/texts.php index 950e77bc9b89..c92925e84717 100644 --- a/app/lang/nl/texts.php +++ b/app/lang/nl/texts.php @@ -447,7 +447,7 @@ return array( 'more_designs_title' => 'Additional Invoice Designs', 'more_designs_cloud_header' => 'Go Pro for more invoice designs', 'more_designs_cloud_text' => '', - 'more_designs_self_host_header' => 'Get 6 more invoice designs for just $20', + 'more_designs_self_host_header' => 'Get 6 more invoice designs for just $'.INVOICE_DESIGNS_PRICE, 'more_designs_self_host_text' => '', 'buy' => 'Buy', 'bought_designs' => 'Successfully added additional invoice designs', @@ -464,7 +464,7 @@ return array( 'id_number' => 'ID Number', 'white_label_link' => 'White label', - 'white_label_text' => 'Purchase a white label license for $10.00 to remove the Invoice Ninja branding from the top of the client pages.', + 'white_label_text' => 'Purchase a white label license for $'.WHITE_LABEL_PRICE.' to remove the Invoice Ninja branding from the top of the client pages.', 'white_label_header' => 'White Label', 'bought_white_label' => 'Successfully enabled white label license', 'white_labeled' => 'White labeled', diff --git a/app/lang/pt_BR/texts.php b/app/lang/pt_BR/texts.php index 7a12139699e2..ae4c7d976f8b 100644 --- a/app/lang/pt_BR/texts.php +++ b/app/lang/pt_BR/texts.php @@ -434,7 +434,7 @@ return array( 'more_designs_title' => 'Additional Invoice Designs', 'more_designs_cloud_header' => 'Go Pro for more invoice designs', 'more_designs_cloud_text' => '', - 'more_designs_self_host_header' => 'Get 6 more invoice designs for just $20', + 'more_designs_self_host_header' => 'Get 6 more invoice designs for just $'.INVOICE_DESIGNS_PRICE, 'more_designs_self_host_text' => '', 'buy' => 'Buy', 'bought_designs' => 'Successfully added additional invoice designs', @@ -452,7 +452,7 @@ return array( 'id_number' => 'ID Number', 'white_label_link' => 'White label', - 'white_label_text' => 'Purchase a white label license for $10.00 to remove the Invoice Ninja branding from the top of the client pages.', + 'white_label_text' => 'Purchase a white label license for $'.WHITE_LABEL_PRICE.' to remove the Invoice Ninja branding from the top of the client pages.', 'white_label_header' => 'White Label', 'bought_white_label' => 'Successfully enabled white label license', 'white_labeled' => 'White labeled', diff --git a/app/routes.php b/app/routes.php index d142ba616b39..c039dfda9bb7 100755 --- a/app/routes.php +++ b/app/routes.php @@ -296,7 +296,6 @@ define('NINJA_FROM_EMAIL', 'maildelivery@invoiceninja.com'); define('RELEASES_URL', 'https://github.com/hillelcoren/invoice-ninja/releases/'); define('COUNT_FREE_DESIGNS', 4); -define('PRO_PLAN_PRICE', 50); define('PRODUCT_ONE_CLICK_INSTALL', 1); define('PRODUCT_INVOICE_DESIGNS', 2); define('PRODUCT_WHITE_LABEL', 3); @@ -305,6 +304,10 @@ define('WHITE_LABEL_AFFILIATE_KEY', '92D2J5'); define('INVOICE_DESIGNS_AFFILIATE_KEY', 'T3RS74'); define('SELF_HOST_AFFILIATE_KEY', '8S69AD'); +define('PRO_PLAN_PRICE', 50); +define('WHITE_LABEL_PRICE', 20); +define('INVOICE_DESIGNS_PRICE', 10); + define('USER_TYPE_SELF_HOST', 'SELF_HOST'); define('USER_TYPE_CLOUD_HOST', 'CLOUD_HOST'); define('NEW_VERSION_AVAILABLE', 'NEW_VERSION_AVAILABLE'); From d605c26bd4f86d70144ed2a11b4385314977e19d Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Sun, 1 Mar 2015 20:21:44 +0200 Subject: [PATCH 28/32] Bug fix if terms is null --- app/ninja/repositories/InvoiceRepository.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/ninja/repositories/InvoiceRepository.php b/app/ninja/repositories/InvoiceRepository.php index 8624c3d9e91d..8b78fabc8057 100755 --- a/app/ninja/repositories/InvoiceRepository.php +++ b/app/ninja/repositories/InvoiceRepository.php @@ -242,7 +242,7 @@ class InvoiceRepository $invoice->end_date = null; } - $invoice->terms = trim($data['terms']) ? trim($data['terms']) : $account->invoice_terms; + $invoice->terms = trim($data['terms']) ? trim($data['terms']) : ($account->invoice_terms ? $account->invoice_terms : ''); $invoice->invoice_footer = trim($data['invoice_footer']) ? trim($data['invoice_footer']) : $account->invoice_footer; $invoice->public_notes = trim($data['public_notes']); $invoice->po_number = trim($data['po_number']); From 6e03bc75106944e50438dc7bb865d9ca71950893 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Mon, 2 Mar 2015 16:17:33 +0200 Subject: [PATCH 29/32] Bug fixes --- app/models/Account.php | 10 +++++----- app/models/Activity.php | 5 +++++ app/views/accounts/email_templates.blade.php | 2 +- app/views/invoices/edit.blade.php | 17 +++++++++++++---- app/views/payments/payment.blade.php | 4 ++-- 5 files changed, 26 insertions(+), 12 deletions(-) diff --git a/app/models/Account.php b/app/models/Account.php index 267cb76b9f99..caaa03c12689 100755 --- a/app/models/Account.php +++ b/app/models/Account.php @@ -312,18 +312,18 @@ class Account extends Eloquent return $template; } - $template = "

    \$client,

    \r\n" . - "

    " . trans("texts.{$entityType}_message", ['amount' => '$amount']) . "

    \r\n"; + $template = "\$client,

    \r\n\r\n" . + trans("texts.{$entityType}_message", ['amount' => '$amount']) . "

    \r\n\r\n"; if ($entityType != ENTITY_PAYMENT) { - $template .= "

    \$link

    \r\n"; + $template .= "\$link

    \r\n\r\n"; } if ($message) { - $template .= "

    $message

    \r\n"; + $template .= "$message

    \r\n\r\n"; } - return $template . "

    \$footer

    "; + return $template . "\$footer"; } public function getEmailFooter() diff --git a/app/models/Activity.php b/app/models/Activity.php index c900ee1db4bd..9e9cb167101f 100755 --- a/app/models/Activity.php +++ b/app/models/Activity.php @@ -202,6 +202,11 @@ class Activity extends Eloquent $activity->adjustment = $invoice->is_quote || $invoice->is_recurring ? 0 : $diff; $activity->json_backup = $backupInvoice->hidePrivateFields()->toJSON(); $activity->save(); + + if ($invoice->isPaid() && $invoice->balance > 0) { + $invoice->invoice_status_id = INVOICE_STATUS_PARTIAL; + $invoice->save(); + } } } } diff --git a/app/views/accounts/email_templates.blade.php b/app/views/accounts/email_templates.blade.php index f50265e32573..f22abef5039e 100644 --- a/app/views/accounts/email_templates.blade.php +++ b/app/views/accounts/email_templates.blade.php @@ -5,7 +5,7 @@ diff --git a/app/views/invoices/edit.blade.php b/app/views/invoices/edit.blade.php index 1c5a0fc36a7d..1847b394ded6 100755 --- a/app/views/invoices/edit.blade.php +++ b/app/views/invoices/edit.blade.php @@ -83,7 +83,7 @@
    @else
    - {{ Former::checkbox('recurring')->text(trans('texts.enable').'    '.trans('texts.learn_more').'')->data_bind("checked: is_recurring") + {{ Former::checkbox('recurring')->onclick('setEmailEnabled()')->text(trans('texts.enable').'    '.trans('texts.learn_more').'')->data_bind("checked: is_recurring") ->inlineHelp($invoice && $invoice->last_sent_date ? 'Last invoice sent ' . Utils::dateToString($invoice->last_sent_date) : '') }}
    @endif @@ -1052,10 +1052,10 @@ self.frequency_id = ko.observable(''); //self.currency_id = ko.observable({{ $client && $client->currency_id ? $client->currency_id : Session::get(SESSION_CURRENCY) }}); self.terms = ko.observable(''); - self.default_terms = ko.observable({{ $account->invoice_terms ? 'true' : 'false' }} ? wordWrapText('{{ str_replace(["\r\n","\r","\n"], '\n', addslashes($account->invoice_terms)) }}', 300) : "{{ trans('texts.invoice_terms') }}"); + self.default_terms = ko.observable({{ $account->invoice_terms ? 'true' : 'false' }} ? wordWrapText('{{ str_replace(["\r\n","\r","\n"], '\n', addslashes($account->invoice_terms)) }}', 300) : ''); self.set_default_terms = ko.observable(false); self.invoice_footer = ko.observable(''); - self.default_footer = ko.observable({{ $account->invoice_footer ? 'true' : 'false' }} ? wordWrapText('{{ str_replace(["\r\n","\r","\n"], '\n', addslashes($account->invoice_footer)) }}', 600) : "{{ trans('texts.invoice_footer') }}"); + self.default_footer = ko.observable({{ $account->invoice_footer ? 'true' : 'false' }} ? wordWrapText('{{ str_replace(["\r\n","\r","\n"], '\n', addslashes($account->invoice_footer)) }}', 600) : ''); self.set_default_footer = ko.observable(false); self.public_notes = ko.observable(''); self.po_number = ko.observable(''); @@ -1413,7 +1413,7 @@ this.prettyRate = ko.computed({ read: function () { - return this.rate() ? parseFloat(this.rate()) : ''; + return this.rate() ? this.rate() : ''; }, write: function (value) { this.rate(value); @@ -1587,6 +1587,15 @@ } } + function setEmailEnabled() + { + if ($('#recurring').prop('checked')) { + $('#email_button').attr('disabled', true); + } else { + $('#email_button').removeAttr('disabled'); + } + } + var products = {{ $products }}; var clients = {{ $clients }}; diff --git a/app/views/payments/payment.blade.php b/app/views/payments/payment.blade.php index 845399c73e5d..e1019c19d358 100755 --- a/app/views/payments/payment.blade.php +++ b/app/views/payments/payment.blade.php @@ -149,8 +149,8 @@ header h3 em {
    @if ($client) -

    {{ $client->getDisplayName() }}

    -

    {{ trans('texts.invoice') . ' ' . $invoiceNumber }}|  {{ trans('texts.amount_due') }}: {{ Utils::formatMoney($amount, $currencyId) }}

    +

    {{{ $client->getDisplayName() }}}

    +

    {{{ trans('texts.invoice') . ' ' . $invoiceNumber }}}|  {{ trans('texts.amount_due') }}: {{ Utils::formatMoney($amount, $currencyId) }}

    @elseif ($paymentTitle)

    {{ $paymentTitle }}
    {{ $paymentSubtitle }}

    @endif From 29833e6d83f34f22c6237adcf024d5f0c278e9dc Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Tue, 3 Mar 2015 14:59:52 +0200 Subject: [PATCH 30/32] Corrected invoice items spacing on second page of PDF --- app/controllers/ClientApiController.php | 2 ++ public/built.js | 5 ++++- public/js/script.js | 3 ++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/controllers/ClientApiController.php b/app/controllers/ClientApiController.php index 1ce750931252..138a92aabcdb 100644 --- a/app/controllers/ClientApiController.php +++ b/app/controllers/ClientApiController.php @@ -40,6 +40,8 @@ class ClientApiController extends Controller return Response::make($error, 500, $headers); } else { $client = $this->clientRepo->save(false, $data, false); + $client->load('contacts'); + $client = Utils::remapPublicIds($client->toArray()); $response = json_encode($client, JSON_PRETTY_PRINT); $headers = Utils::getApiHeaders(); diff --git a/public/built.js b/public/built.js index 9fce8d058aec..f671719efb2e 100644 --- a/public/built.js +++ b/public/built.js @@ -32578,11 +32578,13 @@ function displayInvoiceItems(doc, invoice, layout) { if (newTop > 770) { line = 0; tableTop = layout.accountTop + layout.tablePadding; - y = tableTop; + y = tableTop + (2 * layout.tablePadding); top = y - layout.tablePadding; newTop = top + (numLines * layout.tableRowHeight); doc.addPage(); + console.log('== ADD PAGE =='); } + console.log('Y: %s', y); var left = layout.marginLeft - layout.tablePadding; var width = layout.marginRight + layout.tablePadding; @@ -32748,6 +32750,7 @@ function displayInvoiceItems(doc, invoice, layout) { } */ + SetPdfColor('Black', doc); doc.setFontType('normal'); diff --git a/public/js/script.js b/public/js/script.js index ad7d7bc367a7..a6d9bf6df0d4 100644 --- a/public/js/script.js +++ b/public/js/script.js @@ -1055,7 +1055,7 @@ function displayInvoiceItems(doc, invoice, layout) { if (newTop > 770) { line = 0; tableTop = layout.accountTop + layout.tablePadding; - y = tableTop; + y = tableTop + (2 * layout.tablePadding); top = y - layout.tablePadding; newTop = top + (numLines * layout.tableRowHeight); doc.addPage(); @@ -1225,6 +1225,7 @@ function displayInvoiceItems(doc, invoice, layout) { } */ + SetPdfColor('Black', doc); doc.setFontType('normal'); From 9210e3d578aeebda0fb29db3d4e95089dae494c3 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Tue, 3 Mar 2015 17:32:50 +0200 Subject: [PATCH 31/32] Added support for API tokens --- app/controllers/AccountController.php | 2 + app/controllers/TokenController.php | 159 ++++++++++++++++++ .../2015_03_03_140259_add_tokens.php | 54 ++++++ app/filters.php | 10 ++ app/lang/da/texts.php | 11 ++ app/lang/de/texts.php | 11 ++ app/lang/en/texts.php | 11 ++ app/lang/es/texts.php | 11 ++ app/lang/fr/texts.php | 10 ++ app/lang/it/texts.php | 10 ++ app/lang/lt/texts.php | 10 ++ app/lang/nb_NO/texts.php | 10 ++ app/lang/nl/texts.php | 10 ++ app/lang/pt_BR/texts.php | 11 ++ app/libraries/Utils.php | 3 +- app/models/AccountToken.php | 9 + app/models/Activity.php | 2 + app/routes.php | 7 +- app/views/accounts/nav_advanced.blade.php | 3 +- app/views/accounts/token.blade.php | 29 ++++ app/views/accounts/token_management.blade.php | 67 ++++++++ app/views/accounts/user_management.blade.php | 2 - 22 files changed, 447 insertions(+), 5 deletions(-) create mode 100755 app/controllers/TokenController.php create mode 100644 app/database/migrations/2015_03_03_140259_add_tokens.php create mode 100755 app/models/AccountToken.php create mode 100644 app/views/accounts/token.blade.php create mode 100644 app/views/accounts/token_management.blade.php diff --git a/app/controllers/AccountController.php b/app/controllers/AccountController.php index 52caaae72076..2fb4e0e39dc7 100755 --- a/app/controllers/AccountController.php +++ b/app/controllers/AccountController.php @@ -87,6 +87,8 @@ class AccountController extends \BaseController if ($entityType == 'user') { return Redirect::to('company/'.ACCOUNT_ADVANCED_SETTINGS.'/'.ACCOUNT_USER_MANAGEMENT); + } elseif ($entityType == 'token') { + return Redirect::to('company/'.ACCOUNT_ADVANCED_SETTINGS.'/'.ACCOUNT_TOKEN_MANAGEMENT); } else { return Redirect::to("{$entityType}s"); } diff --git a/app/controllers/TokenController.php b/app/controllers/TokenController.php new file mode 100755 index 000000000000..c472cc6d2b83 --- /dev/null +++ b/app/controllers/TokenController.php @@ -0,0 +1,159 @@ +where('account_tokens.account_id', '=', Auth::user()->account_id); + + if (!Session::get('show_trash:token')) { + $query->where('account_tokens.deleted_at', '=', null); + } + + $query->select('account_tokens.public_id', 'account_tokens.name', 'account_tokens.token', 'account_tokens.public_id', 'account_tokens.deleted_at'); + + return Datatable::query($query) + ->addColumn('name', function ($model) { return link_to('tokens/'.$model->public_id.'/edit', $model->name); }) + ->addColumn('token', function ($model) { return $model->token; }) + ->addColumn('dropdown', function ($model) { + $actions = ''; + + return $actions; + }) + ->orderColumns(['name', 'token']) + ->make(); + } + + public function edit($publicId) + { + $token = AccountToken::where('account_id', '=', Auth::user()->account_id) + ->where('public_id', '=', $publicId)->firstOrFail(); + + $data = [ + 'showBreadcrumbs' => false, + 'token' => $token, + 'method' => 'PUT', + 'url' => 'tokens/'.$publicId, + 'title' => trans('texts.edit_token'), + ]; + + return View::make('accounts.token', $data); + } + + public function update($publicId) + { + return $this->save($publicId); + } + + public function store() + { + return $this->save(); + } + + /** + * Displays the form for account creation + * + */ + public function create() + { + if (!Auth::user()->confirmed) { + Session::flash('error', trans('texts.register_to_add_user')); + return Redirect::to('company/advanced_settings/user_management'); + } + + $data = [ + 'showBreadcrumbs' => false, + 'token' => null, + 'method' => 'POST', + 'url' => 'tokens', + 'title' => trans('texts.add_token'), + ]; + + return View::make('accounts.token', $data); + } + + public function delete() + { + $tokenPublicId = Input::get('tokenPublicId'); + $token = AccountToken::where('account_id', '=', Auth::user()->account_id) + ->where('public_id', '=', $tokenPublicId)->firstOrFail(); + + $token->delete(); + + Session::flash('message', trans('texts.deleted_token')); + + return Redirect::to('company/advanced_settings/token_management'); + } + + /** + * Stores new account + * + */ + public function save($tokenPublicId = false) + { + $rules = [ + 'name' => 'required', + ]; + + if ($tokenPublicId) { + $token = AccountToken::where('account_id', '=', Auth::user()->account_id) + ->where('public_id', '=', $tokenPublicId)->firstOrFail(); + } + + $validator = Validator::make(Input::all(), $rules); + + if ($validator->fails()) { + return Redirect::to($tokenPublicId ? 'tokens/edit' : 'tokens/create')->withInput()->withErrors($validator); + } + + if ($tokenPublicId) { + $token->name = trim(Input::get('name')); + } else { + $lastToken = AccountToken::withTrashed()->where('account_id', '=', Auth::user()->account_id) + ->orderBy('public_id', 'DESC')->first(); + + $token = AccountToken::createNew(); + $token->name = trim(Input::get('name')); + $token->token = str_random(RANDOM_KEY_LENGTH); + $token->public_id = $lastToken ? $lastToken->public_id + 1 : 1; + } + + $token->save(); + + if ($tokenPublicId) { + $message = trans('texts.updated_token'); + } else { + $message = trans('texts.created_token'); + } + + Session::flash('message', $message); + + return Redirect::to('company/advanced_settings/token_management'); + } + +} diff --git a/app/database/migrations/2015_03_03_140259_add_tokens.php b/app/database/migrations/2015_03_03_140259_add_tokens.php new file mode 100644 index 000000000000..45b54e3ca4f8 --- /dev/null +++ b/app/database/migrations/2015_03_03_140259_add_tokens.php @@ -0,0 +1,54 @@ +increments('id'); + $table->unsignedInteger('account_id')->index(); + $table->unsignedInteger('user_id'); + $table->timestamps(); + $table->softDeletes(); + + $table->string('name')->nullable(); + $table->string('token')->unique(); + + $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + + $table->unsignedInteger('public_id')->nullable(); + $table->unique(['account_id', 'public_id']); + }); + + Schema::table('activities', function($table) + { + $table->unsignedInteger('token_id')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('account_tokens'); + + Schema::table('activities', function($table) + { + $table->dropColumn('token_id'); + }); + } + +} diff --git a/app/filters.php b/app/filters.php index 3792f38a9d11..db20fa951eb8 100755 --- a/app/filters.php +++ b/app/filters.php @@ -176,6 +176,16 @@ Route::filter('auth.basic', function() Route::filter('api.access', function() { $headers = Utils::getApiHeaders(); + + // check for a valid token + $token = AccountToken::where('token', '=', Request::header('X-Ninja-Token'))->first(['id', 'user_id']); + + if ($token) { + Auth::loginUsingId($token->user_id); + Session::set('token_id', $token->id); + } else { + return Response::make('Invalid token', 403, $headers); + } if (!Utils::isPro()) { return Response::make('API requires pro plan', 403, $headers); diff --git a/app/lang/da/texts.php b/app/lang/da/texts.php index 9996f0cb96cc..b9fe647bc5fd 100644 --- a/app/lang/da/texts.php +++ b/app/lang/da/texts.php @@ -539,4 +539,15 @@ return array( 'invoice_footer' => 'Invoice footer', 'save_as_default_footer' => 'Save as default footer', + 'token_management' => 'Token Management', + 'tokens' => 'Tokens', + 'add_token' => 'Add Token', + 'show_deleted_tokens' => 'Show deleted tokens', + 'deleted_token' => 'Successfully deleted token', + 'created_token' => 'Successfully created token', + 'edit_token' => 'Edit Token', + 'delete_token' => 'Delete Token', + 'token' => 'Token', + + ); diff --git a/app/lang/de/texts.php b/app/lang/de/texts.php index ffbbf1ec2b5d..baae707b2683 100644 --- a/app/lang/de/texts.php +++ b/app/lang/de/texts.php @@ -529,4 +529,15 @@ return array( 'invoice_footer' => 'Invoice footer', 'save_as_default_footer' => 'Save as default footer', + 'token_management' => 'Token Management', + 'tokens' => 'Tokens', + 'add_token' => 'Add Token', + 'show_deleted_tokens' => 'Show deleted tokens', + 'deleted_token' => 'Successfully deleted token', + 'created_token' => 'Successfully created token', + 'edit_token' => 'Edit Token', + 'delete_token' => 'Delete Token', + 'token' => 'Token', + + ); diff --git a/app/lang/en/texts.php b/app/lang/en/texts.php index 70d709660584..78077cb34e31 100644 --- a/app/lang/en/texts.php +++ b/app/lang/en/texts.php @@ -537,4 +537,15 @@ return array( 'invoice_footer' => 'Invoice footer', 'save_as_default_footer' => 'Save as default footer', + 'token_management' => 'Token Management', + 'tokens' => 'Tokens', + 'add_token' => 'Add Token', + 'show_deleted_tokens' => 'Show deleted tokens', + 'deleted_token' => 'Successfully deleted token', + 'created_token' => 'Successfully created token', + 'edit_token' => 'Edit Token', + 'delete_token' => 'Delete Token', + 'token' => 'Token', + + ); diff --git a/app/lang/es/texts.php b/app/lang/es/texts.php index e264b2888767..c1656cdd6207 100644 --- a/app/lang/es/texts.php +++ b/app/lang/es/texts.php @@ -509,4 +509,15 @@ return array( 'invoice_footer' => 'Invoice footer', 'save_as_default_footer' => 'Save as default footer', + 'token_management' => 'Token Management', + 'tokens' => 'Tokens', + 'add_token' => 'Add Token', + 'show_deleted_tokens' => 'Show deleted tokens', + 'deleted_token' => 'Successfully deleted token', + 'created_token' => 'Successfully created token', + 'edit_token' => 'Edit Token', + 'delete_token' => 'Delete Token', + 'token' => 'Token', + + ); \ No newline at end of file diff --git a/app/lang/fr/texts.php b/app/lang/fr/texts.php index eda3e7de46d6..feb611dffa1a 100644 --- a/app/lang/fr/texts.php +++ b/app/lang/fr/texts.php @@ -530,4 +530,14 @@ return array( 'invoice_footer' => 'Invoice footer', 'save_as_default_footer' => 'Save as default footer', + 'token_management' => 'Token Management', + 'tokens' => 'Tokens', + 'add_token' => 'Add Token', + 'show_deleted_tokens' => 'Show deleted tokens', + 'deleted_token' => 'Successfully deleted token', + 'created_token' => 'Successfully created token', + 'edit_token' => 'Edit Token', + 'delete_token' => 'Delete Token', + 'token' => 'Token', + ); \ No newline at end of file diff --git a/app/lang/it/texts.php b/app/lang/it/texts.php index 359bbfd5a189..418acd0aed32 100644 --- a/app/lang/it/texts.php +++ b/app/lang/it/texts.php @@ -531,5 +531,15 @@ return array( 'default_invoice_footer' => 'Set default invoice footer', 'invoice_footer' => 'Invoice footer', 'save_as_default_footer' => 'Save as default footer', + + 'token_management' => 'Token Management', + 'tokens' => 'Tokens', + 'add_token' => 'Add Token', + 'show_deleted_tokens' => 'Show deleted tokens', + 'deleted_token' => 'Successfully deleted token', + 'created_token' => 'Successfully created token', + 'edit_token' => 'Edit Token', + 'delete_token' => 'Delete Token', + 'token' => 'Token', ); diff --git a/app/lang/lt/texts.php b/app/lang/lt/texts.php index 914c185b2202..194a88af5868 100644 --- a/app/lang/lt/texts.php +++ b/app/lang/lt/texts.php @@ -539,6 +539,16 @@ return array( 'default_invoice_footer' => 'Set default invoice footer', 'invoice_footer' => 'Invoice footer', 'save_as_default_footer' => 'Save as default footer', + + 'token_management' => 'Token Management', + 'tokens' => 'Tokens', + 'add_token' => 'Add Token', + 'show_deleted_tokens' => 'Show deleted tokens', + 'deleted_token' => 'Successfully deleted token', + 'created_token' => 'Successfully created token', + 'edit_token' => 'Edit Token', + 'delete_token' => 'Delete Token', + 'token' => 'Token', ); diff --git a/app/lang/nb_NO/texts.php b/app/lang/nb_NO/texts.php index 6f66e10b6d0d..c90260274b40 100644 --- a/app/lang/nb_NO/texts.php +++ b/app/lang/nb_NO/texts.php @@ -538,5 +538,15 @@ return array( 'invoice_footer' => 'Invoice footer', 'save_as_default_footer' => 'Save as default footer', + 'token_management' => 'Token Management', + 'tokens' => 'Tokens', + 'add_token' => 'Add Token', + 'show_deleted_tokens' => 'Show deleted tokens', + 'deleted_token' => 'Successfully deleted token', + 'created_token' => 'Successfully created token', + 'edit_token' => 'Edit Token', + 'delete_token' => 'Delete Token', + 'token' => 'Token', + ); \ No newline at end of file diff --git a/app/lang/nl/texts.php b/app/lang/nl/texts.php index c92925e84717..961228fbe10c 100644 --- a/app/lang/nl/texts.php +++ b/app/lang/nl/texts.php @@ -532,6 +532,16 @@ return array( 'default_invoice_footer' => 'Set default invoice footer', 'invoice_footer' => 'Invoice footer', 'save_as_default_footer' => 'Save as default footer', + + 'token_management' => 'Token Management', + 'tokens' => 'Tokens', + 'add_token' => 'Add Token', + 'show_deleted_tokens' => 'Show deleted tokens', + 'deleted_token' => 'Successfully deleted token', + 'created_token' => 'Successfully created token', + 'edit_token' => 'Edit Token', + 'delete_token' => 'Delete Token', + 'token' => 'Token', ); \ No newline at end of file diff --git a/app/lang/pt_BR/texts.php b/app/lang/pt_BR/texts.php index ae4c7d976f8b..b194ed7538ea 100644 --- a/app/lang/pt_BR/texts.php +++ b/app/lang/pt_BR/texts.php @@ -519,5 +519,16 @@ return array( 'default_invoice_footer' => 'Set default invoice footer', 'invoice_footer' => 'Invoice footer', 'save_as_default_footer' => 'Save as default footer', + + 'token_management' => 'Token Management', + 'tokens' => 'Tokens', + 'add_token' => 'Add Token', + 'show_deleted_tokens' => 'Show deleted tokens', + 'deleted_token' => 'Successfully deleted token', + 'created_token' => 'Successfully created token', + 'edit_token' => 'Edit Token', + 'delete_token' => 'Delete Token', + 'token' => 'Token', + ); diff --git a/app/libraries/Utils.php b/app/libraries/Utils.php index 98c209ac63f1..99d5a7052e7c 100755 --- a/app/libraries/Utils.php +++ b/app/libraries/Utils.php @@ -466,8 +466,9 @@ class Utils $person = $person ? $person->getDisplayName() : 'System'; $entity = $entity ? '['.$entity->getActivityKey().']' : ''; $otherPerson = $otherPerson ? 'to '.$otherPerson->getDisplayName() : ''; + $token = Session::get('token_id') ? ' ('.trans('texts.token').')' : ''; - return trim("$person $action $entity $otherPerson"); + return trim("$person $token $action $entity $otherPerson"); } public static function decodeActivity($message) diff --git a/app/models/AccountToken.php b/app/models/AccountToken.php new file mode 100755 index 000000000000..dea1f1d19a77 --- /dev/null +++ b/app/models/AccountToken.php @@ -0,0 +1,9 @@ +belongsTo('Account'); + } +} diff --git a/app/models/Activity.php b/app/models/Activity.php index 9e9cb167101f..912aa554be7f 100755 --- a/app/models/Activity.php +++ b/app/models/Activity.php @@ -34,6 +34,8 @@ class Activity extends Eloquent Utils::fatalError(); } + $activity->token_id = Session::get('token_id', null); + return $activity; } diff --git a/app/routes.php b/app/routes.php index c039dfda9bb7..377407cc6ec0 100755 --- a/app/routes.php +++ b/app/routes.php @@ -82,6 +82,10 @@ Route::group(array('before' => 'auth'), function() { Route::get('send_confirmation/{user_id}', 'UserController@sendConfirmation'); Route::get('restore_user/{user_id}', 'UserController@restoreUser'); + Route::get('api/tokens', array('as'=>'api.tokens', 'uses'=>'TokenController@getDatatable')); + Route::resource('tokens', 'TokenController'); + Route::post('tokens/delete', 'TokenController@delete'); + Route::get('api/products', array('as'=>'api.products', 'uses'=>'ProductController@getDatatable')); Route::resource('products', 'ProductController'); Route::get('products/{product_id}/archive', 'ProductController@archive'); @@ -142,7 +146,7 @@ Route::group(array('before' => 'auth'), function() { }); // Route group for API -Route::group(array('prefix' => 'api/v1', 'before' => ['auth.basic', 'api.access']), function() +Route::group(array('prefix' => 'api/v1', 'before' => ['api.access']), function() { Route::resource('ping', 'ClientApiController@ping'); Route::resource('clients', 'ClientApiController'); @@ -186,6 +190,7 @@ define('ACCOUNT_CHART_BUILDER', 'chart_builder'); define('ACCOUNT_USER_MANAGEMENT', 'user_management'); define('ACCOUNT_DATA_VISUALIZATIONS', 'data_visualizations'); define('ACCOUNT_EMAIL_TEMPLATES', 'email_templates'); +define('ACCOUNT_TOKEN_MANAGEMENT', 'token_management'); define('ACTIVITY_TYPE_CREATE_CLIENT', 1); define('ACTIVITY_TYPE_ARCHIVE_CLIENT', 2); diff --git a/app/views/accounts/nav_advanced.blade.php b/app/views/accounts/nav_advanced.blade.php index 513c05dffdd2..99ea2abf8eb6 100644 --- a/app/views/accounts/nav_advanced.blade.php +++ b/app/views/accounts/nav_advanced.blade.php @@ -4,7 +4,8 @@ {{ HTML::nav_link('company/advanced_settings/email_templates', 'email_templates') }} {{ HTML::nav_link('company/advanced_settings/data_visualizations', 'data_visualizations') }} {{ HTML::nav_link('company/advanced_settings/chart_builder', 'chart_builder') }} - {{ HTML::nav_link('company/advanced_settings/user_management', 'user_management') }} + {{ HTML::nav_link('company/advanced_settings/user_management', 'users') }} + {{ HTML::nav_link('company/advanced_settings/token_management', 'tokens') }}

     

    diff --git a/app/views/accounts/token.blade.php b/app/views/accounts/token.blade.php new file mode 100644 index 000000000000..ac8649079f92 --- /dev/null +++ b/app/views/accounts/token.blade.php @@ -0,0 +1,29 @@ +@extends('accounts.nav') + +@section('content') + @parent + + {{ Former::open($url)->method($method)->addClass('col-md-8 col-md-offset-2 warn-on-exit')->rules(array( + 'name' => 'required', + )); }} + + {{ Former::legend($title) }} + +

     

    + + @if ($token) + {{ Former::populate($token) }} + @endif + + {{ Former::text('name') }} + +

     

    + + {{ Former::actions( + Button::lg_success_submit(trans('texts.save'))->append_with_icon('floppy-disk'), + Button::lg_default_link('company/advanced_settings/token_management', 'Cancel')->append_with_icon('remove-circle') + ) }} + + {{ Former::close() }} + +@stop \ No newline at end of file diff --git a/app/views/accounts/token_management.blade.php b/app/views/accounts/token_management.blade.php new file mode 100644 index 000000000000..9f1c0ed1c729 --- /dev/null +++ b/app/views/accounts/token_management.blade.php @@ -0,0 +1,67 @@ +@extends('accounts.nav') + +@section('content') + @parent + @include('accounts.nav_advanced') + + {{ Former::open('tokens/delete')->addClass('user-form') }} + {{ Former::legend('token_management') }} + +
    + {{ Former::text('tokenPublicId') }} +
    + {{ Former::close() }} + + + @if (Utils::isPro()) + {{ Button::success_link(URL::to('tokens/create'), trans("texts.add_token"), array('class' => 'pull-right'))->append_with_icon('plus-sign') }} + @endif + + + + {{ Datatable::table() + ->addColumn( + trans('texts.name'), + trans('texts.token'), + trans('texts.action')) + ->setUrl(url('api/tokens/')) + ->setOptions('sPaginationType', 'bootstrap') + ->setOptions('bFilter', false) + ->setOptions('bAutoWidth', false) + ->setOptions('aoColumns', [[ "sWidth"=> "40%" ], [ "sWidth"=> "40%" ], ["sWidth"=> "20%"]]) + ->setOptions('aoColumnDefs', [['bSortable'=>false, 'aTargets'=>[2]]]) + ->render('datatable') }} + + + +@stop diff --git a/app/views/accounts/user_management.blade.php b/app/views/accounts/user_management.blade.php index 6d46a19bf097..8a1a66df9b46 100644 --- a/app/views/accounts/user_management.blade.php +++ b/app/views/accounts/user_management.blade.php @@ -7,8 +7,6 @@ {{ Former::open('users/delete')->addClass('user-form') }} {{ Former::legend('user_management') }} - -
    {{ Former::text('userPublicId') }}
    From c71dcee2ea7e4eea9043d963382b1b605c5d0c71 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Tue, 3 Mar 2015 17:41:36 +0200 Subject: [PATCH 32/32] Added support for API tokens --- app/controllers/TokenController.php | 70 +++++++++---------- app/controllers/UserController.php | 100 ++++++++++++++-------------- app/lang/da/texts.php | 1 + app/lang/de/texts.php | 1 + app/lang/en/texts.php | 2 +- app/lang/es/texts.php | 2 +- app/lang/fr/texts.php | 1 + app/lang/it/texts.php | 1 + app/lang/lt/texts.php | 1 + app/lang/nb_NO/texts.php | 1 + app/lang/nl/texts.php | 1 + app/lang/pt_BR/texts.php | 1 + 12 files changed, 97 insertions(+), 85 deletions(-) diff --git a/app/controllers/TokenController.php b/app/controllers/TokenController.php index c472cc6d2b83..ba7924d49479 100755 --- a/app/controllers/TokenController.php +++ b/app/controllers/TokenController.php @@ -116,43 +116,45 @@ class TokenController extends BaseController */ public function save($tokenPublicId = false) { - $rules = [ - 'name' => 'required', - ]; + if (Auth::user()->account->isPro()) { + $rules = [ + 'name' => 'required', + ]; - if ($tokenPublicId) { - $token = AccountToken::where('account_id', '=', Auth::user()->account_id) - ->where('public_id', '=', $tokenPublicId)->firstOrFail(); + if ($tokenPublicId) { + $token = AccountToken::where('account_id', '=', Auth::user()->account_id) + ->where('public_id', '=', $tokenPublicId)->firstOrFail(); + } + + $validator = Validator::make(Input::all(), $rules); + + if ($validator->fails()) { + return Redirect::to($tokenPublicId ? 'tokens/edit' : 'tokens/create')->withInput()->withErrors($validator); + } + + if ($tokenPublicId) { + $token->name = trim(Input::get('name')); + } else { + $lastToken = AccountToken::withTrashed()->where('account_id', '=', Auth::user()->account_id) + ->orderBy('public_id', 'DESC')->first(); + + $token = AccountToken::createNew(); + $token->name = trim(Input::get('name')); + $token->token = str_random(RANDOM_KEY_LENGTH); + $token->public_id = $lastToken ? $lastToken->public_id + 1 : 1; + } + + $token->save(); + + if ($tokenPublicId) { + $message = trans('texts.updated_token'); + } else { + $message = trans('texts.created_token'); + } + + Session::flash('message', $message); } - $validator = Validator::make(Input::all(), $rules); - - if ($validator->fails()) { - return Redirect::to($tokenPublicId ? 'tokens/edit' : 'tokens/create')->withInput()->withErrors($validator); - } - - if ($tokenPublicId) { - $token->name = trim(Input::get('name')); - } else { - $lastToken = AccountToken::withTrashed()->where('account_id', '=', Auth::user()->account_id) - ->orderBy('public_id', 'DESC')->first(); - - $token = AccountToken::createNew(); - $token->name = trim(Input::get('name')); - $token->token = str_random(RANDOM_KEY_LENGTH); - $token->public_id = $lastToken ? $lastToken->public_id + 1 : 1; - } - - $token->save(); - - if ($tokenPublicId) { - $message = trans('texts.updated_token'); - } else { - $message = trans('texts.created_token'); - } - - Session::flash('message', $message); - return Redirect::to('company/advanced_settings/token_management'); } diff --git a/app/controllers/UserController.php b/app/controllers/UserController.php index ec6b701c29e3..931eae529052 100755 --- a/app/controllers/UserController.php +++ b/app/controllers/UserController.php @@ -183,58 +183,60 @@ class UserController extends BaseController */ public function save($userPublicId = false) { - $rules = [ - 'first_name' => 'required', - 'last_name' => 'required', - ]; + if (Auth::user()->account->isPro()) { + $rules = [ + 'first_name' => 'required', + 'last_name' => 'required', + ]; - if ($userPublicId) { - $user = User::where('account_id', '=', Auth::user()->account_id) - ->where('public_id', '=', $userPublicId)->firstOrFail(); + if ($userPublicId) { + $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 { - $rules['email'] = 'required|email|unique:users'; + $rules['email'] = 'required|email|unique:users,email,'.$user->id.',id'; + } else { + $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); } - - $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'); } diff --git a/app/lang/da/texts.php b/app/lang/da/texts.php index b9fe647bc5fd..c9bb24e2dbf7 100644 --- a/app/lang/da/texts.php +++ b/app/lang/da/texts.php @@ -545,6 +545,7 @@ return array( 'show_deleted_tokens' => 'Show deleted tokens', 'deleted_token' => 'Successfully deleted token', 'created_token' => 'Successfully created token', + 'updated_token' => 'Successfully updated token', 'edit_token' => 'Edit Token', 'delete_token' => 'Delete Token', 'token' => 'Token', diff --git a/app/lang/de/texts.php b/app/lang/de/texts.php index baae707b2683..9b625600c51f 100644 --- a/app/lang/de/texts.php +++ b/app/lang/de/texts.php @@ -535,6 +535,7 @@ return array( 'show_deleted_tokens' => 'Show deleted tokens', 'deleted_token' => 'Successfully deleted token', 'created_token' => 'Successfully created token', + 'updated_token' => 'Successfully updated token', 'edit_token' => 'Edit Token', 'delete_token' => 'Delete Token', 'token' => 'Token', diff --git a/app/lang/en/texts.php b/app/lang/en/texts.php index 78077cb34e31..f15f14e5e85c 100644 --- a/app/lang/en/texts.php +++ b/app/lang/en/texts.php @@ -543,9 +543,9 @@ return array( 'show_deleted_tokens' => 'Show deleted tokens', 'deleted_token' => 'Successfully deleted token', 'created_token' => 'Successfully created token', + 'updated_token' => 'Successfully updated token', 'edit_token' => 'Edit Token', 'delete_token' => 'Delete Token', 'token' => 'Token', - ); diff --git a/app/lang/es/texts.php b/app/lang/es/texts.php index c1656cdd6207..76aac6f70da1 100644 --- a/app/lang/es/texts.php +++ b/app/lang/es/texts.php @@ -515,9 +515,9 @@ return array( 'show_deleted_tokens' => 'Show deleted tokens', 'deleted_token' => 'Successfully deleted token', 'created_token' => 'Successfully created token', + 'updated_token' => 'Successfully updated token', 'edit_token' => 'Edit Token', 'delete_token' => 'Delete Token', 'token' => 'Token', - ); \ No newline at end of file diff --git a/app/lang/fr/texts.php b/app/lang/fr/texts.php index feb611dffa1a..3ca233cf043c 100644 --- a/app/lang/fr/texts.php +++ b/app/lang/fr/texts.php @@ -536,6 +536,7 @@ return array( 'show_deleted_tokens' => 'Show deleted tokens', 'deleted_token' => 'Successfully deleted token', 'created_token' => 'Successfully created token', + 'updated_token' => 'Successfully updated token', 'edit_token' => 'Edit Token', 'delete_token' => 'Delete Token', 'token' => 'Token', diff --git a/app/lang/it/texts.php b/app/lang/it/texts.php index 418acd0aed32..7fa241629f23 100644 --- a/app/lang/it/texts.php +++ b/app/lang/it/texts.php @@ -538,6 +538,7 @@ return array( 'show_deleted_tokens' => 'Show deleted tokens', 'deleted_token' => 'Successfully deleted token', 'created_token' => 'Successfully created token', + 'updated_token' => 'Successfully updated token', 'edit_token' => 'Edit Token', 'delete_token' => 'Delete Token', 'token' => 'Token', diff --git a/app/lang/lt/texts.php b/app/lang/lt/texts.php index 194a88af5868..d0985358a938 100644 --- a/app/lang/lt/texts.php +++ b/app/lang/lt/texts.php @@ -546,6 +546,7 @@ return array( 'show_deleted_tokens' => 'Show deleted tokens', 'deleted_token' => 'Successfully deleted token', 'created_token' => 'Successfully created token', + 'updated_token' => 'Successfully updated token', 'edit_token' => 'Edit Token', 'delete_token' => 'Delete Token', 'token' => 'Token', diff --git a/app/lang/nb_NO/texts.php b/app/lang/nb_NO/texts.php index c90260274b40..25a3109460db 100644 --- a/app/lang/nb_NO/texts.php +++ b/app/lang/nb_NO/texts.php @@ -544,6 +544,7 @@ return array( 'show_deleted_tokens' => 'Show deleted tokens', 'deleted_token' => 'Successfully deleted token', 'created_token' => 'Successfully created token', + 'updated_token' => 'Successfully updated token', 'edit_token' => 'Edit Token', 'delete_token' => 'Delete Token', 'token' => 'Token', diff --git a/app/lang/nl/texts.php b/app/lang/nl/texts.php index 961228fbe10c..e9f4e7d5abc8 100644 --- a/app/lang/nl/texts.php +++ b/app/lang/nl/texts.php @@ -539,6 +539,7 @@ return array( 'show_deleted_tokens' => 'Show deleted tokens', 'deleted_token' => 'Successfully deleted token', 'created_token' => 'Successfully created token', + 'updated_token' => 'Successfully updated token', 'edit_token' => 'Edit Token', 'delete_token' => 'Delete Token', 'token' => 'Token', diff --git a/app/lang/pt_BR/texts.php b/app/lang/pt_BR/texts.php index b194ed7538ea..079721e4d925 100644 --- a/app/lang/pt_BR/texts.php +++ b/app/lang/pt_BR/texts.php @@ -526,6 +526,7 @@ return array( 'show_deleted_tokens' => 'Show deleted tokens', 'deleted_token' => 'Successfully deleted token', 'created_token' => 'Successfully created token', + 'updated_token' => 'Successfully updated token', 'edit_token' => 'Edit Token', 'delete_token' => 'Delete Token', 'token' => 'Token',