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