From ae57fdf9a38229e3cd1ef51cade35f1ba6b663b7 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Tue, 24 Nov 2015 21:45:38 +0200 Subject: [PATCH] Updated readme --- .env.example | 1 + app/Http/Controllers/ImportController.php | 58 ++-- app/Http/Middleware/StartupCheck.php | 2 +- app/Libraries/Utils.php | 5 + app/Models/Client.php | 56 +++- app/Models/Contact.php | 8 +- app/Models/Invoice.php | 36 +++ app/Ninja/Import/CSV/ClientTransformer.php | 40 +++ app/Ninja/Import/CSV/InvoiceTransformer.php | 40 +++ app/Ninja/Import/CSV/PaymentTransformer.php | 19 ++ app/Services/ImportService.php | 305 +++++++++--------- readme.md | 2 - resources/lang/en/texts.php | 8 +- .../views/accounts/import_export.blade.php | 15 +- resources/views/accounts/import_map.blade.php | 87 +---- .../views/accounts/partials/map.blade.php | 66 ++++ 16 files changed, 464 insertions(+), 284 deletions(-) create mode 100644 app/Ninja/Import/CSV/ClientTransformer.php create mode 100644 app/Ninja/Import/CSV/InvoiceTransformer.php create mode 100644 app/Ninja/Import/CSV/PaymentTransformer.php create mode 100644 resources/views/accounts/partials/map.blade.php diff --git a/.env.example b/.env.example index c955b9de3a71..51f3c553acd5 100644 --- a/.env.example +++ b/.env.example @@ -22,6 +22,7 @@ MAIL_PASSWORD PHANTOMJS_CLOUD_KEY='a-demo-key-with-low-quota-per-ip-address' LOG=single +REQUIRE_HTTPS=false GOOGLE_CLIENT_ID GOOGLE_CLIENT_SECRET diff --git a/app/Http/Controllers/ImportController.php b/app/Http/Controllers/ImportController.php index 7573e72e7087..7da808209bec 100644 --- a/app/Http/Controllers/ImportController.php +++ b/app/Http/Controllers/ImportController.php @@ -21,45 +21,43 @@ class ImportController extends BaseController public function doImport() { $source = Input::get('source'); + $files = []; - if ($source === IMPORT_CSV) { - $filename = Input::file('client_file')->getRealPath(); - $data = $this->importService->mapFile($filename); - - return View::make('accounts.import_map', $data); - } else { - $files = []; - foreach (ImportService::$entityTypes as $entityType) { - if (Input::file("{$entityType}_file")) { - $files[$entityType] = Input::file("{$entityType}_file")->getRealPath(); - } + foreach (ImportService::$entityTypes as $entityType) { + if (Input::file("{$entityType}_file")) { + $files[$entityType] = Input::file("{$entityType}_file")->getRealPath(); } - - try { - $result = $this->importService->import($source, $files); - Session::flash('message', trans('texts.imported_file') . ' - ' . $result); - } catch (Exception $exception) { - Session::flash('error', $exception->getMessage()); - } - - return Redirect::to('/settings/' . ACCOUNT_IMPORT_EXPORT); } - } - - public function doImportCSV() - { - $map = Input::get('map'); - $hasHeaders = Input::get('header_checkbox'); try { - $count = $this->importService->importCSV($map, $hasHeaders); - $message = Utils::pluralize('created_client', $count); - - Session::flash('message', $message); + if ($source === IMPORT_CSV) { + $data = $this->importService->mapCSV($files); + return View::make('accounts.import_map', ['data' => $data]); + } else { + $result = $this->importService->import($source, $files); + Session::flash('message', trans('texts.imported_file') . ' - ' . $result); + } } catch (Exception $exception) { Session::flash('error', $exception->getMessage()); } return Redirect::to('/settings/' . ACCOUNT_IMPORT_EXPORT); } + + public function doImportCSV() + { + $map = Input::get('map'); + $headers = Input::get('headers'); + + //try { + $count = $this->importService->importCSV($map, $headers); + $message = Utils::pluralize('created_client', $count); + + Session::flash('message', $message); + //} catch (Exception $exception) { + // Session::flash('error', $exception->getMessage()); + //} + + return Redirect::to('/settings/' . ACCOUNT_IMPORT_EXPORT); + } } diff --git a/app/Http/Middleware/StartupCheck.php b/app/Http/Middleware/StartupCheck.php index 08b586b80fc1..5bc4d543204a 100644 --- a/app/Http/Middleware/StartupCheck.php +++ b/app/Http/Middleware/StartupCheck.php @@ -33,7 +33,7 @@ class StartupCheck } // Ensure all request are over HTTPS in production - if (Utils::isNinjaProd() && !Request::secure()) { + if (Utils::requireHTTPS() && !Request::secure()) { return Redirect::secure(Request::getRequestUri()); } diff --git a/app/Libraries/Utils.php b/app/Libraries/Utils.php index a8c74d2b64a5..8ce036dbdbfe 100644 --- a/app/Libraries/Utils.php +++ b/app/Libraries/Utils.php @@ -60,6 +60,11 @@ class Utils return isset($_ENV['NINJA_DEV']) && $_ENV['NINJA_DEV'] == 'true'; } + public static function requireHTTPS() + { + return Utils::isNinjaProd() || (isset($_ENV['REQUIRE_HTTPS']) && $_ENV['REQUIRE_HTTPS'] == 'true'); + } + public static function isOAuthEnabled() { $providers = [ diff --git a/app/Models/Client.php b/app/Models/Client.php index 389fad250557..ee0e80fc8948 100644 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -39,15 +39,53 @@ class Client extends EntityModel 'website', ]; - public static $fieldName = 'Client - Name'; - public static $fieldPhone = 'Client - Phone'; - public static $fieldAddress1 = 'Client - Street'; - public static $fieldAddress2 = 'Client - Apt/Floor'; - public static $fieldCity = 'Client - City'; - public static $fieldState = 'Client - State'; - public static $fieldPostalCode = 'Client - Postal Code'; - public static $fieldNotes = 'Client - Notes'; - public static $fieldCountry = 'Client - Country'; + public static $fieldName = 'name'; + public static $fieldPhone = 'work_phone'; + public static $fieldAddress1 = 'address1'; + public static $fieldAddress2 = 'address2'; + public static $fieldCity = 'city'; + public static $fieldState = 'state'; + public static $fieldPostalCode = 'postal_code'; + public static $fieldNotes = 'notes'; + public static $fieldCountry = 'country'; + + public static function getImportColumns() + { + return [ + Client::$fieldName, + Client::$fieldPhone, + Client::$fieldAddress1, + Client::$fieldAddress2, + Client::$fieldCity, + Client::$fieldState, + Client::$fieldPostalCode, + Client::$fieldCountry, + Client::$fieldNotes, + Contact::$fieldFirstName, + Contact::$fieldLastName, + Contact::$fieldPhone, + Contact::$fieldEmail, + ]; + } + + public static function getImportMap() + { + return [ + 'first' => Contact::$fieldFirstName, + 'last' => Contact::$fieldLastName, + 'email' => Contact::$fieldEmail, + 'mobile' => Contact::$fieldPhone, + 'phone' => Client::$fieldPhone, + 'name|organization' => Client::$fieldName, + 'street|address|address1' => Client::$fieldAddress1, + 'street2|address2' => Client::$fieldAddress2, + 'city' => Client::$fieldCity, + 'state|province' => Client::$fieldState, + 'zip|postal|code' => Client::$fieldPostalCode, + 'country' => Client::$fieldCountry, + 'note' => Client::$fieldNotes, + ]; + } public function account() { diff --git a/app/Models/Contact.php b/app/Models/Contact.php index 23faf964315e..a95f40bab059 100644 --- a/app/Models/Contact.php +++ b/app/Models/Contact.php @@ -17,10 +17,10 @@ class Contact extends EntityModel 'send_invoice', ]; - public static $fieldFirstName = 'Contact - First Name'; - public static $fieldLastName = 'Contact - Last Name'; - public static $fieldEmail = 'Contact - Email'; - public static $fieldPhone = 'Contact - Phone'; + public static $fieldFirstName = 'first_name'; + public static $fieldLastName = 'last_name'; + public static $fieldEmail = 'email'; + public static $fieldPhone = 'phone'; public function account() { diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index 97079eb42416..22f5b75b6704 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -5,6 +5,7 @@ use DateTime; use Illuminate\Database\Eloquent\SoftDeletes; use Laracasts\Presenter\PresentableTrait; use App\Models\BalanceAffecting; +use App\Models\Client; use App\Events\QuoteWasCreated; use App\Events\QuoteWasUpdated; use App\Events\InvoiceWasCreated; @@ -29,6 +30,7 @@ class Invoice extends EntityModel implements BalanceAffecting 'auto_bill' => 'boolean', ]; + // used for custom invoice numbers public static $patternFields = [ 'counter', 'custom1', @@ -38,6 +40,40 @@ class Invoice extends EntityModel implements BalanceAffecting 'date:', ]; + public static $fieldInvoiceNumber = 'invoice_number'; + public static $fieldInvoiceDate = 'invoice_date'; + public static $fieldDueDate = 'due_date'; + public static $fieldAmount = 'amount'; + public static $fieldPaid = 'paid'; + public static $fieldNotes = 'notes'; + public static $fieldTerms = 'terms'; + + public static function getImportColumns() + { + return [ + Client::$fieldName, + Invoice::$fieldInvoiceNumber, + Invoice::$fieldInvoiceDate, + Invoice::$fieldDueDate, + Invoice::$fieldAmount, + Invoice::$fieldPaid, + Invoice::$fieldNotes, + Invoice::$fieldTerms, + ]; + } + + public static function getImportMap() + { + return [ + 'number' => Invoice::$fieldInvoiceNumber, + 'amount' => Invoice::$fieldAmount, + 'organization' => 'name', + 'paid' => 'paid', + 'create_date' => Invoice::$fieldInvoiceDate, + 'terms' => 'terms', + 'notes' => 'notes', + ]; + } public function getRoute() { $entityType = $this->getEntityType(); diff --git a/app/Ninja/Import/CSV/ClientTransformer.php b/app/Ninja/Import/CSV/ClientTransformer.php new file mode 100644 index 000000000000..8a0d4ab0130b --- /dev/null +++ b/app/Ninja/Import/CSV/ClientTransformer.php @@ -0,0 +1,40 @@ +name])) { + return false; + } + + if (isset($maps['countries'][$data->country])) { + $data->country_id = $maps['countries'][$data->country]; + } + + return new Item($data, function ($data) use ($maps) { + return [ + 'name' => isset($data->name) ? $data->name : null, + 'work_phone' => isset($data->work_phone) ? $data->work_phone : null, + 'address1' => isset($data->address1) ? $data->address1 : null, + 'city' => isset($data->city) ? $data->city : null, + 'state' => isset($data->state) ? $data->state : null, + 'postal_code' => isset($data->postal_code) ? $data->postal_code : null, + 'private_notes' => isset($data->notes) ? $data->notes : null, + 'contacts' => [ + [ + 'first_name' => isset($data->first_name) ? $data->first_name : null, + 'last_name' => isset($data->last_name) ? $data->last_name : null, + 'email' => isset($data->email) ? $data->email : null, + 'phone' => isset($data->phone) ? $data->phone : null, + ], + ], + 'country_id' => isset($data->country_id) ? $data->country_id : null, + ]; + }); + } +} diff --git a/app/Ninja/Import/CSV/InvoiceTransformer.php b/app/Ninja/Import/CSV/InvoiceTransformer.php new file mode 100644 index 000000000000..17d802774e2f --- /dev/null +++ b/app/Ninja/Import/CSV/InvoiceTransformer.php @@ -0,0 +1,40 @@ +invoice_number])) { + return false; + } + + if (isset($maps[ENTITY_CLIENT][$data->name])) { + $data->client_id = $maps[ENTITY_CLIENT][$data->name]; + } else { + return false; + } + + return new Item($data, function ($data) use ($maps) { + return [ + 'invoice_number' => isset($data->invoice_number) ? $data->invoice_number : null, + 'paid' => isset($data->paid) ? (float) $data->paid : null, + 'client_id' => (int) $data->client_id, + 'po_number' => isset($data->po_number) ? $data->po_number : null, + 'terms' => isset($data->terms) ? $data->terms : null, + 'public_notes' => isset($data->notes) ? $data->notes : null, + 'invoice_date_sql' => isset($data->create_date) ? $data->create_date : null, + 'invoice_items' => [ + [ + 'notes' => isset($data->notes) ? $data->notes : null, + 'cost' => isset($data->amount) ? (float) $data->amount : null, + 'qty' => 1, + ] + ], + ]; + }); + } +} \ No newline at end of file diff --git a/app/Ninja/Import/CSV/PaymentTransformer.php b/app/Ninja/Import/CSV/PaymentTransformer.php new file mode 100644 index 000000000000..08feade8b1f7 --- /dev/null +++ b/app/Ninja/Import/CSV/PaymentTransformer.php @@ -0,0 +1,19 @@ + $data->paid, + 'payment_date_sql' => $data->create_date, + 'client_id' => $data->client_id, + 'invoice_id' => $data->invoice_id, + ]; + }); + } +} \ No newline at end of file diff --git a/app/Services/ImportService.php b/app/Services/ImportService.php index ebab4b8780b1..ab3d367474e8 100644 --- a/app/Services/ImportService.php +++ b/app/Services/ImportService.php @@ -1,10 +1,10 @@ - $file) { $this->execute($source, $entityType, $file); } } + private function checkClientCount($count) + { + $totalClients = $count + Client::scope()->withTrashed()->count(); + if ($totalClients > Auth::user()->getMaxNumClients()) { + throw new Exception(trans('texts.limit_clients', ['count' => Auth::user()->getMaxNumClients()])); + } + } + private function execute($source, $entityType, $file) { - $transformerClassName = $this->getTransformerClassName($source, $entityType); - $transformer = new $transformerClassName; - - Excel::load($file, function($reader) use ($source, $entityType, $transformer) { - - if ($entityType === ENTITY_CLIENT) { - $totalClients = count($reader->all()) + Client::scope()->withTrashed()->count(); - if ($totalClients > Auth::user()->getMaxNumClients()) { - throw new Exception(trans('texts.limit_clients', ['count' => Auth::user()->getMaxNumClients()])); - } - } + Excel::load($file, function ($reader) use ($source, $entityType, $transformer) { + $this->checkData($entityType, count($reader->all())); $maps = $this->createMaps(); - - $reader->each(function($row) use ($source, $entityType, $transformer, $maps) { - if ($resource = $transformer->transform($row, $maps)) { - $data = $this->fractal->createData($resource)->toArray(); - if ($this->validate($data, $entityType) !== true) { - return; - } - - $entity = $this->{"{$entityType}Repo"}->save($data); - - // if the invoice is paid we'll also create a payment record - if ($entityType === ENTITY_INVOICE && isset($data['paid']) && $data['paid']) { - $class = self::getTransformerClassName($source, ENTITY_PAYMENT); - $paymentTransformer = new $class; - $row->client_id = $data['client_id']; - $row->invoice_id = $entity->public_id; - if ($resource = $paymentTransformer->transform($row, $maps)) { - $data = $this->fractal->createData($resource)->toArray(); - $this->paymentRepo->save($data); - } - } - } + $reader->each(function ($row) use ($source, $entityType, $transformer, $maps) { + $this->saveData($source, $entityType, $row, $maps); }); }); } + private function executeCSV($entityType, $map, $hasHeaders) + { + $source = IMPORT_CSV; + + $data = Session::get("{$entityType}-data"); + $this->checkData($entityType, count($data)); + $maps = $this->createMaps(); + + foreach ($data as $row) { + if ($hasHeaders) { + $hasHeaders = false; + continue; + } + + $row = $this->convertToObject($entityType, $row, $map); + $this->saveData($source, $entityType, $row, $maps); + } + + Session::forget("{$entityType}-data"); + } + + private function saveData($source, $entityType, $row, $maps) + { + $transformer = $this->getTransformer($source, $entityType); + $resource = $transformer->transform($row, $maps); + + if (!$resource) { + return; + } + + $data = $this->fractal->createData($resource)->toArray(); + + if ($this->validate($data, $entityType) !== true) { + return; + } + + $entity = $this->{"{$entityType}Repo"}->save($data); + + // if the invoice is paid we'll also create a payment record + if ($entityType === ENTITY_INVOICE && isset($data['paid']) && $data['paid']) { + $this->createPayment($source, $row, $maps, $data['client_id'], $entity->public_id); + } + } + + private function checkData($entityType, $count) + { + if ($entityType === ENTITY_CLIENT) { + $this->checkClientCount($count); + } + } + + public static function getTransformerClassName($source, $entityType) + { + return 'App\\Ninja\\Import\\'.$source.'\\'.ucwords($entityType).'Transformer'; + } + + public static function getTransformer($source, $entityType) + { + $className = self::getTransformerClassName($source, $entityType); + + return new $className(); + } + + private function createPayment($source, $data, $maps, $clientId, $invoiceId) + { + $paymentTransformer = $this->getTransformer($source, ENTITY_PAYMENT); + + $row->client_id = $clientId; + $row->invoice_id = $invoiceId; + + if ($resource = $paymentTransformer->transform($data, $maps)) { + $data = $this->fractal->createData($resource)->toArray(); + $this->paymentRepo->save($data); + } + } + // looking for a better solution... // http://stackoverflow.com/questions/33781567/how-can-i-re-use-the-validation-code-in-my-laravel-formrequest-classes private function validate($data, $entityType) @@ -109,7 +164,8 @@ class ImportService $rules = [ 'contacts' => 'valid_contacts', ]; - } if ($entityType === ENTITY_INVOICE) { + } + if ($entityType === ENTITY_INVOICE) { $rules = [ 'client.contacts' => 'valid_contacts', 'invoice_items' => 'valid_invoice_items', @@ -122,6 +178,7 @@ class ImportService if ($validator->fails()) { $messages = $validator->messages(); + return $messages->first(); } else { return true; @@ -155,42 +212,50 @@ class ImportService ]; } - public static function getTransformerClassName($source, $entityType) + public function mapCSV($files) { - return 'App\\Ninja\\Import\\' . $source . '\\' . ucwords($entityType) . 'Transformer'; + $data = []; + + foreach ($files as $entityType => $filename) { + if ($entityType === ENTITY_CLIENT) { + $columns = Client::getImportColumns(); + $map = Client::getImportMap(); + } else { + $columns = Invoice::getImportColumns(); + $map = Invoice::getImportMap(); + } + + // Lookup field translations + foreach ($columns as $key => $value) { + unset($columns[$key]); + $columns[$value] = trans("texts.{$value}"); + } + array_unshift($columns, ' '); + + $data[$entityType] = $this->mapFile($entityType, $filename, $columns, $map); + + if ($entityType === ENTITY_CLIENT) { + if (count($data[$entityType]['data']) + Client::scope()->count() > Auth::user()->getMaxNumClients()) { + throw new Exception(trans('texts.limit_clients', ['count' => Auth::user()->getMaxNumClients()])); + } + } + } + + return $data; } - public function mapFile($filename) + public function mapFile($entityType, $filename, $columns, $map) { require_once app_path().'/Includes/parsecsv.lib.php'; $csv = new parseCSV(); $csv->heading = false; $csv->auto($filename); - if (count($csv->data) + Client::scope()->count() > Auth::user()->getMaxNumClients()) { - throw new Exception(trans('texts.limit_clients', ['count' => Auth::user()->getMaxNumClients()])); - } - - Session::put('data', $csv->data); + Session::put("{$entityType}-data", $csv->data); $headers = false; $hasHeaders = false; $mapped = array(); - $columns = array('', - Client::$fieldName, - Client::$fieldPhone, - Client::$fieldAddress1, - Client::$fieldAddress2, - Client::$fieldCity, - Client::$fieldState, - Client::$fieldPostalCode, - Client::$fieldCountry, - Client::$fieldNotes, - Contact::$fieldFirstName, - Contact::$fieldLastName, - Contact::$fieldPhone, - Contact::$fieldEmail, - ); if (count($csv->data) > 0) { $headers = $csv->data[0]; @@ -206,29 +271,11 @@ class ImportService $mapped[$i] = ''; if ($hasHeaders) { - $map = array( - 'first' => Contact::$fieldFirstName, - 'last' => Contact::$fieldLastName, - 'email' => Contact::$fieldEmail, - 'mobile' => Contact::$fieldPhone, - 'phone' => Client::$fieldPhone, - 'name|organization' => Client::$fieldName, - 'street|address|address1' => Client::$fieldAddress1, - 'street2|address2' => Client::$fieldAddress2, - 'city' => Client::$fieldCity, - 'state|province' => Client::$fieldState, - 'zip|postal|code' => Client::$fieldPostalCode, - 'country' => Client::$fieldCountry, - 'note' => Client::$fieldNotes, - ); - foreach ($map as $search => $column) { foreach (explode("|", $search) as $string) { if (strpos($title, 'sec') === 0) { continue; - } - - if (strpos($title, $string) !== false) { + } elseif (strpos($title, $string) !== false) { $mapped[$i] = $column; break(2); } @@ -239,6 +286,7 @@ class ImportService } $data = array( + 'entityType' => $entityType, 'data' => $csv->data, 'headers' => $headers, 'hasHeaders' => $hasHeaders, @@ -249,78 +297,35 @@ class ImportService return $data; } - public function importCSV($map, $hasHeaders) + public function importCSV($maps, $headers) { - $count = 0; - $data = Session::get('data'); - $countries = Cache::get('countries'); - $countryMap = []; - - foreach ($countries as $country) { - $countryMap[strtolower($country->name)] = $country->id; + foreach ($maps as $entityType => $map) { + $this->executeCSV($entityType, $map, $headers[$entityType]); } - - foreach ($data as $row) { - if ($hasHeaders) { - $hasHeaders = false; - continue; - } - - $data = [ - 'contacts' => [[]] - ]; - - foreach ($row as $index => $value) { - $field = $map[$index]; - if ( ! $value = trim($value)) { - continue; - } - - if ($field == Client::$fieldName) { - $data['name'] = $value; - } elseif ($field == Client::$fieldPhone) { - $data['work_phone'] = $value; - } elseif ($field == Client::$fieldAddress1) { - $data['address1'] = $value; - } elseif ($field == Client::$fieldAddress2) { - $data['address2'] = $value; - } elseif ($field == Client::$fieldCity) { - $data['city'] = $value; - } elseif ($field == Client::$fieldState) { - $data['state'] = $value; - } elseif ($field == Client::$fieldPostalCode) { - $data['postal_code'] = $value; - } elseif ($field == Client::$fieldCountry) { - $value = strtolower($value); - $data['country_id'] = isset($countryMap[$value]) ? $countryMap[$value] : null; - } elseif ($field == Client::$fieldNotes) { - $data['private_notes'] = $value; - } elseif ($field == Contact::$fieldFirstName) { - $data['contacts'][0]['first_name'] = $value; - } elseif ($field == Contact::$fieldLastName) { - $data['contacts'][0]['last_name'] = $value; - } elseif ($field == Contact::$fieldPhone) { - $data['contacts'][0]['phone'] = $value; - } elseif ($field == Contact::$fieldEmail) { - $data['contacts'][0]['email'] = strtolower($value); - } - } - - $rules = [ - 'contacts' => 'valid_contacts', - ]; - $validator = Validator::make($data, $rules); - if ($validator->fails()) { - continue; - } - - $this->clientRepo->save($data); - $count++; - } - - Session::forget('data'); - - return $count; } + private function convertToObject($entityType, $data, $map) + { + $obj = new stdClass(); + + if ($entityType === ENTITY_CLIENT) { + $columns = Client::getImportColumns(); + } else { + $columns = Invoice::getImportColumns(); + } + + foreach ($columns as $column) { + $obj->$column = false; + } + + foreach ($map as $index => $field) { + if (! $field) { + continue; + } + + $obj->$field = $data[$index]; + } + + return $obj; + } } diff --git a/readme.md b/readme.md index 6dad94e09e70..886299ab685b 100644 --- a/readme.md +++ b/readme.md @@ -12,8 +12,6 @@ We offer two options: * 10% of revenue * $1,000 for a site limited to 1,000 accounts -If you'd like to use our code to sell your own invoicing app email us for details about our affiliate program. - ### Installation Options * [Self-Host Zip](https://www.invoiceninja.com/knowledgebase/self-host/) - Free * [Docker File](https://github.com/invoiceninja/dockerfiles) - Free diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 82941ea6298a..a2f7c8ba77ce 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -87,7 +87,7 @@ return array( 'guest' => 'Guest', 'company_details' => 'Company Details', 'online_payments' => 'Online Payments', - 'notifications' => 'Notifications', + 'notifications' => 'Email Notifications', 'import_export' => 'Import/Export', 'done' => 'Done', 'save' => 'Save', @@ -334,7 +334,7 @@ return array( // product management 'product_library' => 'Product Library', 'product' => 'Product', - 'products' => 'Products', + 'products' => 'Product Library', 'fill_products' => 'Auto-fill products', 'fill_products_help' => 'Selecting a product will automatically fill in the description and cost', 'update_products' => 'Auto-update products', @@ -945,4 +945,8 @@ return array( 'admin' => 'Admin', 'disabled' => 'Disabled', 'show_archived_users' => 'Show archived users', + 'notes' => 'Notes', + 'invoice_will_create' => 'client will be created', + 'invoices_will_create' => 'invoices will be created', + ); diff --git a/resources/views/accounts/import_export.blade.php b/resources/views/accounts/import_export.blade.php index cab0b31b9d51..92f3c231508f 100644 --- a/resources/views/accounts/import_export.blade.php +++ b/resources/views/accounts/import_export.blade.php @@ -4,7 +4,6 @@ @parent