diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 804cc6dfe3bd..d743637eaec7 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php-versions: ['7.3', '7.4', '8.0'] + php-versions: ['7.3', '7.4'] env: DB_DATABASE1: ninja DB_USERNAME1: root diff --git a/app/Http/Controllers/ImportController.php b/app/Http/Controllers/ImportController.php index 8d65b0e33d13..899b4060d105 100644 --- a/app/Http/Controllers/ImportController.php +++ b/app/Http/Controllers/ImportController.php @@ -79,14 +79,16 @@ class ImportController extends Controller $hash = Str::random(32); //store the csv in cache with an expiry of 10 minutes - Cache::put($hash, base64_encode(file_get_contents($request->file('file')->getPathname())), 60); + Cache::put($hash, base64_encode(file_get_contents($request->file('file')->getPathname())), 3600); //parse CSV $csv_array = $this->getCsvData(file_get_contents($request->file('file')->getPathname())); + $class_map = $this->getEntityMap($request->input('entity_type')); + $data = [ 'hash' => $hash, - 'available' => InvoiceMap::importable(), + 'available' => $class_map::importable(), 'headers' => array_slice($csv_array, 0, 2) ]; @@ -95,11 +97,17 @@ class ImportController extends Controller public function import(ImportRequest $request) { - CSVImport::dispatch($request, auth()->user()->company()); + + CSVImport::dispatch($request->all(), auth()->user()->company()); return response()->json(['message' => 'Importing data, email will be sent on completion'], 200); } + private function getEntityMap($entity_type) + { + return sprintf('App\\Import\\Definitions\%sMap', ucfirst($entity_type)); + } + private function getCsvData($csvfile) { diff --git a/app/Http/Requests/Import/ImportRequest.php b/app/Http/Requests/Import/ImportRequest.php index a1f92a0dc465..a09837c92d20 100644 --- a/app/Http/Requests/Import/ImportRequest.php +++ b/app/Http/Requests/Import/ImportRequest.php @@ -29,8 +29,10 @@ class ImportRequest extends Request { return [ - 'hash' => 'required', - 'entity_type' => 'required', + 'hash' => 'required|string', + 'entity_type' => 'required|string', + 'column_map' => 'required|array', + 'skip_header' => 'required|boolean' ]; } diff --git a/app/Import/Definitions/ClientMap.php b/app/Import/Definitions/ClientMap.php new file mode 100644 index 000000000000..c8edf27e75fc --- /dev/null +++ b/app/Import/Definitions/ClientMap.php @@ -0,0 +1,101 @@ + 'client.name', + 1 => 'client.user_id', + 2 => 'client.balance', + 3 => 'client.paid_to_date', + 4 => 'client.currency_id', + 5 => 'client.website', + 6 => 'client.private_notes', + 7 => 'client.industry_id', + 8 => 'client.size_id', + 9 => 'client.address1', + 10 => 'client.address2', + 11 => 'client.city', + 12 => 'client.state', + 13 => 'client.postal_code', + 14 => 'client.country_id', + 15 => 'client.custom_value1', + 16 => 'client.custom_value2', + 17 => 'client.custom_value3', + 18 => 'client.custom_value4', + 19 => 'client.shipping_address1', + 20 => 'client.shipping_address2', + 21 => 'client.shipping_city', + 22 => 'client.shipping_state', + 23 => 'client.shipping_postal_code', + 24 => 'client.shipping_country_id', + 25 => 'client.payment_terms', + 26 => 'client.vat_number', + 27 => 'client.id_number', + 28 => 'client.public_notes', + 29 => 'contact.first_name', + 30 => 'contact.last_name', + 31 => 'contact.email', + 32 => 'contact.phone', + 33 => 'contact.custom_value1', + 34 => 'contact.custom_value2', + 35 => 'contact.custom_value3', + 36 => 'contact.custom_value4', + ]; + } + + public static function import_keys() + { + return [ + 0 => 'texts.client_name', + 1 => 'texts.user', + 2 => 'texts.balance', + 3 => 'texts.paid_to_date', + 4 => 'texts.currency', + 5 => 'texts.website', + 6 => 'texts.private_notes', + 7 => 'texts.industry', + 8 => 'texts.size', + 9 => 'texts.address1', + 10 => 'texts.address2', + 11 => 'texts.city', + 12 => 'texts.state', + 13 => 'texts.postal_code', + 14 => 'texts.country', + 15 => 'texts.custom_value', + 16 => 'texts.custom_value', + 17 => 'texts.custom_value', + 18 => 'texts.custom_value', + 19 => 'texts.address1', + 20 => 'texts.address2', + 21 => 'texts.shipping_city', + 22 => 'texts.shipping_state', + 23 => 'texts.shipping_postal_code', + 24 => 'texts.shipping_country', + 25 => 'texts.payment_terms', + 26 => 'texts.vat_number', + 27 => 'texts.id_number', + 28 => 'texts.public_notes', + 29 => 'texts.first_name', + 30 => 'texts.last_name', + 31 => 'texts.email', + 32 => 'texts.phone', + 33 => 'texts.custom_value', + 34 => 'texts.custom_value', + 35 => 'texts.custom_value', + 36 => 'texts.custom_value', + ]; + } +} diff --git a/app/Import/Transformers/BaseTransformer.php b/app/Import/Transformers/BaseTransformer.php new file mode 100644 index 000000000000..f0153be91513 --- /dev/null +++ b/app/Import/Transformers/BaseTransformer.php @@ -0,0 +1,350 @@ +maps = $maps; + } + + + /** + * @param $data + * @param $field + * + * @return string + */ + public function getString($data, $field) + { + return (isset($data[$field]) && $data[$field]) ? $data[$field] : ''; + } + + public function getCurrencyByCode($data) + { + $code = array_key_exists('client.currency_id', $data) ? $data['client.currency_id'] : false; + + if($code) + return $this->maps['currencies']->where('code', $code)->first()->id; + + return $this->maps['company']->settings->currency_id; + } + + /** + * @param $name + * + * @return bool + */ + public function hasClient($name) + { + $name = trim(strtolower($name)); + + return isset($this->maps[ENTITY_CLIENT][$name]); + } + + /** + * @param $name + * + * @return bool + */ + public function hasVendor($name) + { + $name = trim(strtolower($name)); + + return isset($this->maps[ENTITY_VENDOR][$name]); + } + + + /** + * @param $key + * + * @return bool + */ + public function hasProduct($key) + { + $key = trim(strtolower($key)); + + return isset($this->maps[ENTITY_PRODUCT][$key]); + } + + + /** + * @param $data + * @param $field + * + * @return int + */ + public function getNumber($data, $field) + { + return (isset($data->$field) && $data->$field) ? $data->$field : 0; + } + + /** + * @param $data + * @param $field + * + * @return float + */ + public function getFloat($data, $field) + { + return (isset($data->$field) && $data->$field) ? Utils::parseFloat($data->$field) : 0; + } + + /** + * @param $name + * + * @return null + */ + public function getClientId($name) + { + $name = strtolower(trim($name)); + + return isset($this->maps[ENTITY_CLIENT][$name]) ? $this->maps[ENTITY_CLIENT][$name] : null; + } + + /** + * @param $name + * + * @return null + */ + public function getProduct($data, $key, $field, $default = false) + { + $productKey = trim(strtolower($data->$key)); + + if (! isset($this->maps['product'][$productKey])) { + return $default; + } + + $product = $this->maps['product'][$productKey]; + + return $product->$field ?: $default; + } + + /** + * @param $name + * + * @return null + */ + public function getContact($email) + { + $email = trim(strtolower($email)); + + if (! isset($this->maps['contact'][$email])) { + return false; + } + + return $this->maps['contact'][$email]; + } + + + /** + * @param $name + * + * @return null + */ + public function getCustomer($key) + { + $key = trim($key); + + if (! isset($this->maps['customer'][$key])) { + return false; + } + + return $this->maps['customer'][$key]; + } + + /** + * @param $name + * + * @return null + */ + public function getCountryId($name) + { + $name = strtolower(trim($name)); + + return isset($this->maps['countries'][$name]) ? $this->maps['countries'][$name] : null; + } + + /** + * @param $name + * + * @return null + */ + public function getCountryIdBy2($name) + { + $name = strtolower(trim($name)); + + return isset($this->maps['countries2'][$name]) ? $this->maps['countries2'][$name] : null; + } + + /** + * @param $name + * + * @return null + */ + public function getTaxRate($name) + { + $name = strtolower(trim($name)); + + return isset($this->maps['tax_rates'][$name]) ? $this->maps['tax_rates'][$name] : 0; + } + + /** + * @param $name + * + * @return null + */ + public function getTaxName($name) + { + $name = strtolower(trim($name)); + + return isset($this->maps['tax_names'][$name]) ? $this->maps['tax_names'][$name] : ''; + } + + /** + * @param $name + * + * @return mixed + */ + public function getFirstName($name) + { + $name = Utils::splitName($name); + + return $name[0]; + } + + /** + * @param $date + * @param string $format + * @param mixed $data + * @param mixed $field + * + * @return null + */ + public function getDate($data, $field) + { + if ($date = data_get($data, $field)) { + try { + $date = new Carbon($date); + } catch (Exception $e) { + // if we fail to parse return blank + $date = false; + } + } + + return $date ? $date->format('Y-m-d') : null; + } + + /** + * @param $name + * + * @return mixed + */ + public function getLastName($name) + { + $name = Utils::splitName($name); + + return $name[1]; + } + + /** + * @param $number + * + * @return string + */ + public function getInvoiceNumber($number) + { + return $number ? str_pad(trim($number), 4, '0', STR_PAD_LEFT) : null; + } + + /** + * @param $invoiceNumber + * + * @return null + */ + public function getInvoiceId($invoiceNumber) + { + $invoiceNumber = $this->getInvoiceNumber($invoiceNumber); + $invoiceNumber = strtolower($invoiceNumber); + return isset($this->maps[ENTITY_INVOICE][$invoiceNumber]) ? $this->maps[ENTITY_INVOICE][$invoiceNumber] : null; + } + + /** + * @param $invoiceNumber + * + * @return null + */ + public function getInvoicePublicId($invoiceNumber) + { + $invoiceNumber = $this->getInvoiceNumber($invoiceNumber); + $invoiceNumber = strtolower($invoiceNumber); + return isset($this->maps['invoices'][$invoiceNumber]) ? $this->maps['invoices'][$invoiceNumber]->public_id : null; + } + + /** + * @param $invoiceNumber + * + * @return bool + */ + public function hasInvoice($invoiceNumber) + { + $invoiceNumber = $this->getInvoiceNumber($invoiceNumber); + $invoiceNumber = strtolower($invoiceNumber); + + return isset($this->maps[ENTITY_INVOICE][$invoiceNumber]); + } + + /** + * @param $invoiceNumber + * + * @return null + */ + public function getInvoiceClientId($invoiceNumber) + { + $invoiceNumber = $this->getInvoiceNumber($invoiceNumber); + $invoiceNumber = strtolower($invoiceNumber); + + return isset($this->maps[ENTITY_INVOICE.'_'.ENTITY_CLIENT][$invoiceNumber]) ? $this->maps[ENTITY_INVOICE.'_'.ENTITY_CLIENT][$invoiceNumber] : null; + } + + /** + * @param $name + * + * @return null + */ + public function getVendorId($name) + { + $name = strtolower(trim($name)); + + return isset($this->maps[ENTITY_VENDOR][$name]) ? $this->maps[ENTITY_VENDOR][$name] : null; + } + + /** + * @param $name + * + * @return null + */ + public function getExpenseCategoryId($name) + { + $name = strtolower(trim($name)); + + return isset($this->maps[ENTITY_EXPENSE_CATEGORY][$name]) ? $this->maps[ENTITY_EXPENSE_CATEGORY][$name] : null; + } +} diff --git a/app/Import/Transformers/ClientTransformer.php b/app/Import/Transformers/ClientTransformer.php new file mode 100644 index 000000000000..f0a8c17adee2 --- /dev/null +++ b/app/Import/Transformers/ClientTransformer.php @@ -0,0 +1,70 @@ +name) && $this->hasClient($data->name)) { + return false; + } + + $settings = new \stdClass; + $settings->currency_id = (string)$this->getCurrencyByCode($data); + + return [ + 'company_id' => $this->maps['company']->id, + 'name' => $this->getString($data, 'client.name'), + 'work_phone' => $this->getString($data, 'client.phone'), + 'address1' => $this->getString($data, 'client.address1'), + 'address2' => $this->getString($data, 'client.address2'), + 'city' => $this->getString($data, 'client.city'), + 'state' => $this->getString($data, 'client.state'), + 'shipping_address1' => $this->getString($data, 'client.shipping_address1'), + 'shipping_address2' => $this->getString($data, 'client.shipping_address2'), + 'shipping_city' => $this->getString($data, 'client.shipping_city'), + 'shipping_state' => $this->getString($data, 'client.shipping_state'), + 'shipping_postal_code' => $this->getString($data, 'client.shipping_postal_code'), + 'public_notes' => $this->getString($data, 'client.public_notes'), + 'private_notes' => $this->getString($data, 'client.private_notes'), + 'website' => $this->getString($data, 'client.website'), + 'vat_number' => $this->getString($data, 'client.vat_number'), + 'id_number' => $this->getString($data, 'client.id_number'), + 'custom_value1' => $this->getString($data, 'client.custom1'), + 'custom_value2' => $this->getString($data, 'client.custom2'), + 'custom_value3' => $this->getString($data, 'client.custom3'), + 'custom_value4' => $this->getString($data, 'client.custom4'), + 'balance' => $this->getString($data, 'client.balance'), + 'paid_to_date' => $this->getString($data, 'client.paid_to_date'), + 'credit_balance' => 0, + 'settings' => $settings, + 'client_hash' => Str::random(40), + 'contacts' => [ + [ + 'first_name' => $this->getString($data, 'contact.first_name'), + 'last_name' => $this->getString($data, 'contact.last_name'), + 'email' => $this->getString($data, 'contact.email'), + 'phone' => $this->getString($data, 'contact.phone'), + 'custom_value1' => $this->getString($data, 'contact.custom1'), + 'custom_value2' => $this->getString($data, 'contact.custom2'), + 'custom_value3' => $this->getString($data, 'contact.custom3'), + 'custom_value4' => $this->getString($data, 'contact.custom4'), + ], + ], + 'country_id' => isset($data->country_id) ? $this->getCountryId($data->country_id) : null, + 'shipping_country_id' => isset($data->shipping_country_id) ? $this->getCountryId($data->shipping_country_id) : null, + ]; + + } +} diff --git a/app/Jobs/Import/CSVImport.php b/app/Jobs/Import/CSVImport.php index 49657ce0d065..c899cea98a1d 100644 --- a/app/Jobs/Import/CSVImport.php +++ b/app/Jobs/Import/CSVImport.php @@ -11,7 +11,16 @@ namespace App\Jobs\Import; +use App\Factory\ClientFactory; +use App\Http\Requests\Client\StoreClientRequest; +use App\Import\Transformers\ClientTransformer; use App\Libraries\MultiDB; +use App\Models\Client; +use App\Models\Company; +use App\Models\Currency; +use App\Models\User; +use App\Repositories\ClientContactRepository; +use App\Repositories\ClientRepository; use Exception; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; @@ -20,6 +29,11 @@ use Illuminate\Http\Request; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; use Illuminate\Support\Facades\Cache; +use Illuminate\Support\Str; +use League\Csv\Reader; +use League\Csv\Statement; +use Illuminate\Support\Facades\Validator; +use Illuminate\Support\Facades\Auth; class CSVImport implements ShouldQueue { @@ -33,19 +47,48 @@ class CSVImport implements ShouldQueue public $entity_type; - public $skip_headers; + public $skip_header; - public function __construct(Request $request, Company $company) + public $column_map; + + public $import_array; + + public $error_array; + + public $maps; + + /* + [hash] => 2lTm7HVR3i9Zv3y86eQYZIO16yVJ7J6l + [entity_type] => client + [skip_header] => 1 + [column_map] => Array + ( + [0] => client.name + [1] => client.user_id + [2] => client.balance + [3] => client.paid_to_date + [4] => client.address1 + [5] => client.address2 + [6] => client.city + [7] => client.state + [8] => client.postal_code + [9] => client.country_id + [20] => client.currency_id + [21] => client.public_notes + [22] => client.private_notes + ) + */ + public function __construct(array $request, Company $company) { - $this->request = $request; - $this->company = $company; - $this->hash = $request->input('hash'); + $this->hash = $request['hash']; - $this->entity_type = $request->input('entity_type'); + $this->entity_type = $request['entity_type']; - $this->skip_headers = $request->input('skip_headers'); + $this->skip_header = $request['skip_header']; + + $this->column_map = $request['column_map']; } /** @@ -58,6 +101,54 @@ class CSVImport implements ShouldQueue { MultiDB::setDb($this->company->db); + $this->company->owner()->setCompany($this->company); + Auth::login($this->company->owner(), true); + + $this->buildMaps(); + + //sort the array by key + ksort($this->column_map); + + //clients + $records = $this->getCsvData(); + + $contact_repository = new ClientContactRepository(); + $client_repository = new ClientRepository($contact_repository); + $client_transformer = new ClientTransformer($this->maps); + + if($this->skip_header) + array_shift($records); + + foreach($records as $record) { + + $keys = $this->column_map; + $values = array_intersect_key($record, $this->column_map); + + $client_data = array_combine($keys, $values); + + $client = $client_transformer->transform($client_data); + + $validator = Validator::make($client, (new StoreClientRequest())->rules()); + + if ($validator->fails()) { + $this->error_array[] = ['client' => $client, 'error' => json_encode($validator->errors())]; + } + else{ + $client = $client_repository->save($client, ClientFactory::create($this->company->id, $this->setUser($record))); + + if(array_key_exists('client.balance', $client_data)) + $client->balance = preg_replace('/[^0-9,.]+/', '', $client_data['client.balance']); + + if(array_key_exists('client.paid_to_date', $client_data)) + $client->paid_to_date = preg_replace('/[^0-9,.]+/', '', $client_data['client.paid_to_date']); + + $client->save(); + + $this->import_array['clients'][] = $client->id; + } + + } + } public function failed($exception) @@ -65,10 +156,67 @@ class CSVImport implements ShouldQueue } - private function getCsv() +////////////////////////////////////////////////////////////////////////////////////////////////////////////// + private function buildMaps() + { + $this->maps['currencies'] = Currency::all(); + $this->maps['users'] = $this->company->users; + $this->maps['company'] = $this->company; + + return $this; + } + + + private function setUser($record) + { + $user_key_exists = array_search('client.user_id', $this->column_map); + + if($user_key_exists) + return $this->findUser($record[$user_key_exists]); + else + return $this->company->owner()->id; + + } + + private function findUser($user_hash) + { + $user = User::where('company_id', $this->company->id) + ->where(\DB::raw('CONCAT_WS(" ", first_name, last_name)'), 'like', '%' . $user_hash . '%') + ->first(); + + if($user) + return $user->id; + else + return $this->company->owner()->id; + + } + + private function getCsvData() { $base64_encoded_csv = Cache::get($this->hash); + $csv = base64_decode($base64_encoded_csv); + $csv = Reader::createFromString($csv); + + $stmt = new Statement(); + $data = iterator_to_array($stmt->process($csv)); + + if (count($data) > 0) { + $headers = $data[0]; + + // Remove Invoice Ninja headers + if (count($headers) && count($data) > 4) { + $firstCell = $headers[0]; + if (strstr($firstCell, config('ninja.app_name'))) { + array_shift($data); // Invoice Ninja... + array_shift($data); // + array_shift($data); // Enitty Type Header + } + } + } + + return $data; + + - return base64_decode($base64_encoded_csv); } } diff --git a/composer.json b/composer.json index fdcd1945ef31..603c68b22b5e 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,8 @@ "CRM", "Credit card billing", "projects", - "tasks" + "tasks", + "freelancer" ], "license": "Attribution Assurance License", "authors": [ @@ -52,7 +53,7 @@ "league/flysystem-aws-s3-v3": "~1.0", "league/flysystem-cached-adapter": "^1.1", "league/fractal": "^0.17.0", - "league/omnipay": "^3.0", + "league/omnipay": "^3", "livewire/livewire": "^2.0", "maennchen/zipstream-php": "^1.2", "nwidart/laravel-modules": "^8.0", diff --git a/composer.lock b/composer.lock index a3e25bf94666..ad280ddbd6d4 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "75cb7287f45830678381d8e27486cf4a", + "content-hash": "aeacc9e2738ddc41353c497c14feadb0", "packages": [ { "name": "asgrim/ofxparser", @@ -116,16 +116,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.169.0", + "version": "3.170.0", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "d15a231355e4435fc33bab83df075ec31edd0a9b" + "reference": "7f457a08219173eba4b856cb7aef3a903cd790cc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/d15a231355e4435fc33bab83df075ec31edd0a9b", - "reference": "d15a231355e4435fc33bab83df075ec31edd0a9b", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/7f457a08219173eba4b856cb7aef3a903cd790cc", + "reference": "7f457a08219173eba4b856cb7aef3a903cd790cc", "shasum": "" }, "require": { @@ -200,9 +200,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.169.0" + "source": "https://github.com/aws/aws-sdk-php/tree/3.170.0" }, - "time": "2020-12-14T19:12:33+00:00" + "time": "2020-12-15T19:13:22+00:00" }, { "name": "beganovich/chromium-pdf", @@ -2715,16 +2715,16 @@ }, { "name": "laravel/framework", - "version": "v8.18.1", + "version": "v8.19.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "31747193c26ba0a9cb7929a912895d3cdefd10cf" + "reference": "f5f331cee60f1bbe672503b7eb9ba5b22b2ceacb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/31747193c26ba0a9cb7929a912895d3cdefd10cf", - "reference": "31747193c26ba0a9cb7929a912895d3cdefd10cf", + "url": "https://api.github.com/repos/laravel/framework/zipball/f5f331cee60f1bbe672503b7eb9ba5b22b2ceacb", + "reference": "f5f331cee60f1bbe672503b7eb9ba5b22b2ceacb", "shasum": "" }, "require": { @@ -2878,7 +2878,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2020-12-08T22:05:12+00:00" + "time": "2020-12-15T16:16:31+00:00" }, { "name": "laravel/slack-notification-channel", @@ -9558,22 +9558,22 @@ }, { "name": "turbo124/beacon", - "version": "1.0.3", + "version": "1.0.4", "source": { "type": "git", "url": "https://github.com/turbo124/beacon.git", - "reference": "687484955bdc8bfca957ccd060e6c1fa41ada056" + "reference": "ae328ad12364186dd07d893d35f6991880b97f18" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/turbo124/beacon/zipball/687484955bdc8bfca957ccd060e6c1fa41ada056", - "reference": "687484955bdc8bfca957ccd060e6c1fa41ada056", + "url": "https://api.github.com/repos/turbo124/beacon/zipball/ae328ad12364186dd07d893d35f6991880b97f18", + "reference": "ae328ad12364186dd07d893d35f6991880b97f18", "shasum": "" }, "require": { "guzzlehttp/guzzle": "^7", "illuminate/support": "^6.0|^7.0|^8.0", - "php": "^7.3" + "php": "^7.3|^7.4|^8" }, "require-dev": { "orchestra/testbench": "^4.0", @@ -9615,9 +9615,9 @@ "turbo124" ], "support": { - "source": "https://github.com/turbo124/beacon/tree/1.0.3" + "source": "https://github.com/turbo124/beacon/tree/1.0.4" }, - "time": "2020-10-01T05:21:36+00:00" + "time": "2020-12-15T20:56:25+00:00" }, { "name": "turbo124/laravel-gmail", diff --git a/public/.htaccess b/public/.htaccess old mode 100644 new mode 100755 diff --git a/public/assets/AssetManifest.json b/public/assets/AssetManifest.json old mode 100644 new mode 100755 diff --git a/public/assets/FontManifest.json b/public/assets/FontManifest.json old mode 100644 new mode 100755 diff --git a/public/assets/LICENSE b/public/assets/LICENSE old mode 100644 new mode 100755 diff --git a/public/assets/NOTICES b/public/assets/NOTICES old mode 100644 new mode 100755 diff --git a/public/assets/assets/images/google-icon.png b/public/assets/assets/images/google-icon.png old mode 100644 new mode 100755 diff --git a/public/assets/assets/images/logo.png b/public/assets/assets/images/logo.png old mode 100644 new mode 100755 diff --git a/public/assets/assets/images/payment_types/ach.png b/public/assets/assets/images/payment_types/ach.png old mode 100644 new mode 100755 diff --git a/public/assets/assets/images/payment_types/amex.png b/public/assets/assets/images/payment_types/amex.png old mode 100644 new mode 100755 diff --git a/public/assets/assets/images/payment_types/carteblanche.png b/public/assets/assets/images/payment_types/carteblanche.png old mode 100644 new mode 100755 diff --git a/public/assets/assets/images/payment_types/dinerscard.png b/public/assets/assets/images/payment_types/dinerscard.png old mode 100644 new mode 100755 diff --git a/public/assets/assets/images/payment_types/discover.png b/public/assets/assets/images/payment_types/discover.png old mode 100644 new mode 100755 diff --git a/public/assets/assets/images/payment_types/jcb.png b/public/assets/assets/images/payment_types/jcb.png old mode 100644 new mode 100755 diff --git a/public/assets/assets/images/payment_types/laser.png b/public/assets/assets/images/payment_types/laser.png old mode 100644 new mode 100755 diff --git a/public/assets/assets/images/payment_types/maestro.png b/public/assets/assets/images/payment_types/maestro.png old mode 100644 new mode 100755 diff --git a/public/assets/assets/images/payment_types/mastercard.png b/public/assets/assets/images/payment_types/mastercard.png old mode 100644 new mode 100755 diff --git a/public/assets/assets/images/payment_types/other.png b/public/assets/assets/images/payment_types/other.png old mode 100644 new mode 100755 diff --git a/public/assets/assets/images/payment_types/paypal.png b/public/assets/assets/images/payment_types/paypal.png old mode 100644 new mode 100755 diff --git a/public/assets/assets/images/payment_types/solo.png b/public/assets/assets/images/payment_types/solo.png old mode 100644 new mode 100755 diff --git a/public/assets/assets/images/payment_types/switch.png b/public/assets/assets/images/payment_types/switch.png old mode 100644 new mode 100755 diff --git a/public/assets/assets/images/payment_types/unionpay.png b/public/assets/assets/images/payment_types/unionpay.png old mode 100644 new mode 100755 diff --git a/public/assets/assets/images/payment_types/visa.png b/public/assets/assets/images/payment_types/visa.png old mode 100644 new mode 100755 diff --git a/public/assets/fonts/MaterialIcons-Regular.otf b/public/assets/fonts/MaterialIcons-Regular.otf old mode 100644 new mode 100755 diff --git a/public/assets/fonts/MaterialIcons-Regular.ttf b/public/assets/fonts/MaterialIcons-Regular.ttf old mode 100644 new mode 100755 diff --git a/public/assets/fonts/Roboto-Regular.ttf b/public/assets/fonts/Roboto-Regular.ttf old mode 100644 new mode 100755 diff --git a/public/assets/packages/flutter_auth_buttons/fonts/SF-Pro-Medium.ttf b/public/assets/packages/flutter_auth_buttons/fonts/SF-Pro-Medium.ttf old mode 100644 new mode 100755 diff --git a/public/assets/packages/flutter_auth_buttons/graphics/apple_logo_black.png b/public/assets/packages/flutter_auth_buttons/graphics/apple_logo_black.png old mode 100644 new mode 100755 diff --git a/public/assets/packages/flutter_auth_buttons/graphics/apple_logo_white.png b/public/assets/packages/flutter_auth_buttons/graphics/apple_logo_white.png old mode 100644 new mode 100755 diff --git a/public/assets/packages/flutter_auth_buttons/graphics/flogo-HexRBG-Wht-100.png b/public/assets/packages/flutter_auth_buttons/graphics/flogo-HexRBG-Wht-100.png old mode 100644 new mode 100755 diff --git a/public/assets/packages/flutter_auth_buttons/graphics/google-logo.png b/public/assets/packages/flutter_auth_buttons/graphics/google-logo.png old mode 100644 new mode 100755 diff --git a/public/assets/packages/flutter_auth_buttons/graphics/ms-symbollockup_mssymbol_19.png b/public/assets/packages/flutter_auth_buttons/graphics/ms-symbollockup_mssymbol_19.png old mode 100644 new mode 100755 diff --git a/public/assets/packages/font_awesome_flutter/lib/fonts/fa-brands-400.ttf b/public/assets/packages/font_awesome_flutter/lib/fonts/fa-brands-400.ttf old mode 100644 new mode 100755 diff --git a/public/assets/packages/font_awesome_flutter/lib/fonts/fa-regular-400.ttf b/public/assets/packages/font_awesome_flutter/lib/fonts/fa-regular-400.ttf old mode 100644 new mode 100755 diff --git a/public/assets/packages/font_awesome_flutter/lib/fonts/fa-solid-900.ttf b/public/assets/packages/font_awesome_flutter/lib/fonts/fa-solid-900.ttf old mode 100644 new mode 100755 diff --git a/public/assets/web/assets/fonts/Roboto-Regular.ttf b/public/assets/web/assets/fonts/Roboto-Regular.ttf old mode 100644 new mode 100755 diff --git a/public/css/app.css b/public/css/app.css old mode 100644 new mode 100755 diff --git a/public/css/card-js.min.css b/public/css/card-js.min.css old mode 100644 new mode 100755 diff --git a/public/css/ninja.css b/public/css/ninja.css old mode 100644 new mode 100755 diff --git a/public/css/ninja.min.css b/public/css/ninja.min.css old mode 100644 new mode 100755 diff --git a/public/css/tailwind-1.2.0.css b/public/css/tailwind-1.2.0.css old mode 100644 new mode 100755 diff --git a/public/css/tailwindcss@1.4.6.css b/public/css/tailwindcss@1.4.6.css old mode 100644 new mode 100755 diff --git a/public/favicon.ico b/public/favicon.ico old mode 100644 new mode 100755 diff --git a/public/favicon.png b/public/favicon.png old mode 100644 new mode 100755 diff --git a/public/flutter_service_worker.js b/public/flutter_service_worker.js old mode 100644 new mode 100755 diff --git a/public/icons/Icon-192.png b/public/icons/Icon-192.png old mode 100644 new mode 100755 diff --git a/public/icons/Icon-512.png b/public/icons/Icon-512.png old mode 100644 new mode 100755 diff --git a/public/images/american-express.png b/public/images/american-express.png old mode 100644 new mode 100755 diff --git a/public/images/created-by-invoiceninja-new.png b/public/images/created-by-invoiceninja-new.png old mode 100644 new mode 100755 diff --git a/public/images/created-by-invoiceninja.jpg b/public/images/created-by-invoiceninja.jpg old mode 100644 new mode 100755 diff --git a/public/images/diners-club.png b/public/images/diners-club.png old mode 100644 new mode 100755 diff --git a/public/images/discover.png b/public/images/discover.png old mode 100644 new mode 100755 diff --git a/public/images/invoiceninja-black-logo-2.png b/public/images/invoiceninja-black-logo-2.png old mode 100644 new mode 100755 diff --git a/public/images/invoiceninja-white-logo.png b/public/images/invoiceninja-white-logo.png old mode 100644 new mode 100755 diff --git a/public/images/logo.png b/public/images/logo.png old mode 100644 new mode 100755 diff --git a/public/images/mastercard.png b/public/images/mastercard.png old mode 100644 new mode 100755 diff --git a/public/images/paypal.png b/public/images/paypal.png old mode 100644 new mode 100755 diff --git a/public/images/svg/activity.svg b/public/images/svg/activity.svg old mode 100644 new mode 100755 diff --git a/public/images/svg/align-left.svg b/public/images/svg/align-left.svg old mode 100644 new mode 100755 diff --git a/public/images/svg/clock.svg b/public/images/svg/clock.svg old mode 100644 new mode 100755 diff --git a/public/images/svg/credit-card.svg b/public/images/svg/credit-card.svg old mode 100644 new mode 100755 diff --git a/public/images/svg/download.svg b/public/images/svg/download.svg old mode 100644 new mode 100755 diff --git a/public/images/svg/file-text.svg b/public/images/svg/file-text.svg old mode 100644 new mode 100755 diff --git a/public/images/svg/file.svg b/public/images/svg/file.svg old mode 100644 new mode 100755 diff --git a/public/images/svg/shield.svg b/public/images/svg/shield.svg old mode 100644 new mode 100755 diff --git a/public/images/svg/user.svg b/public/images/svg/user.svg old mode 100644 new mode 100755 diff --git a/public/images/visa.png b/public/images/visa.png old mode 100644 new mode 100755 diff --git a/public/index.php b/public/index.php old mode 100644 new mode 100755 diff --git a/public/js/app.js b/public/js/app.js old mode 100644 new mode 100755 diff --git a/public/js/client_create.js b/public/js/client_create.js old mode 100644 new mode 100755 diff --git a/public/js/client_create.min.js b/public/js/client_create.min.js old mode 100644 new mode 100755 diff --git a/public/js/client_edit.js b/public/js/client_edit.js old mode 100644 new mode 100755 diff --git a/public/js/client_edit.min.js b/public/js/client_edit.min.js old mode 100644 new mode 100755 diff --git a/public/js/client_list.js b/public/js/client_list.js old mode 100644 new mode 100755 diff --git a/public/js/client_list.min.js b/public/js/client_list.min.js old mode 100644 new mode 100755 diff --git a/public/js/client_settings.js b/public/js/client_settings.js old mode 100644 new mode 100755 diff --git a/public/js/client_settings.min.js b/public/js/client_settings.min.js old mode 100644 new mode 100755 diff --git a/public/js/client_show.js b/public/js/client_show.js old mode 100644 new mode 100755 diff --git a/public/js/client_show.min.js b/public/js/client_show.min.js old mode 100644 new mode 100755 diff --git a/public/js/clients/invoices/action-selectors.js b/public/js/clients/invoices/action-selectors.js old mode 100644 new mode 100755 diff --git a/public/js/clients/invoices/action-selectors.js.LICENSE.txt b/public/js/clients/invoices/action-selectors.js.LICENSE.txt old mode 100644 new mode 100755 diff --git a/public/js/clients/invoices/payment.js b/public/js/clients/invoices/payment.js old mode 100644 new mode 100755 diff --git a/public/js/clients/invoices/payment.js.LICENSE.txt b/public/js/clients/invoices/payment.js.LICENSE.txt old mode 100644 new mode 100755 diff --git a/public/js/clients/payment_methods/authorize-ach.js b/public/js/clients/payment_methods/authorize-ach.js old mode 100644 new mode 100755 diff --git a/public/js/clients/payment_methods/authorize-ach.js.LICENSE.txt b/public/js/clients/payment_methods/authorize-ach.js.LICENSE.txt old mode 100644 new mode 100755 diff --git a/public/js/clients/payment_methods/authorize-authorize-card.js b/public/js/clients/payment_methods/authorize-authorize-card.js old mode 100644 new mode 100755 diff --git a/public/js/clients/payment_methods/authorize-authorize-card.js.LICENSE.txt b/public/js/clients/payment_methods/authorize-authorize-card.js.LICENSE.txt old mode 100644 new mode 100755 diff --git a/public/js/clients/payment_methods/authorize-stripe-card.js b/public/js/clients/payment_methods/authorize-stripe-card.js old mode 100644 new mode 100755 diff --git a/public/js/clients/payment_methods/authorize-stripe-card.js.LICENSE.txt b/public/js/clients/payment_methods/authorize-stripe-card.js.LICENSE.txt old mode 100644 new mode 100755 diff --git a/public/js/clients/payment_methods/stripe-ach.js b/public/js/clients/payment_methods/stripe-ach.js old mode 100644 new mode 100755 diff --git a/public/js/clients/payments/alipay.js b/public/js/clients/payments/alipay.js old mode 100644 new mode 100755 diff --git a/public/js/clients/payments/alipay.js.LICENSE.txt b/public/js/clients/payments/alipay.js.LICENSE.txt old mode 100644 new mode 100755 diff --git a/public/js/clients/payments/authorize-credit-card-payment.js b/public/js/clients/payments/authorize-credit-card-payment.js old mode 100644 new mode 100755 diff --git a/public/js/clients/payments/authorize-credit-card-payment.js.LICENSE.txt b/public/js/clients/payments/authorize-credit-card-payment.js.LICENSE.txt old mode 100644 new mode 100755 diff --git a/public/js/clients/payments/card-js.min.js b/public/js/clients/payments/card-js.min.js old mode 100644 new mode 100755 diff --git a/public/js/clients/payments/checkout.com.js b/public/js/clients/payments/checkout.com.js old mode 100644 new mode 100755 diff --git a/public/js/clients/payments/checkout.com.js.LICENSE.txt b/public/js/clients/payments/checkout.com.js.LICENSE.txt old mode 100644 new mode 100755 diff --git a/public/js/clients/payments/process.js b/public/js/clients/payments/process.js old mode 100644 new mode 100755 diff --git a/public/js/clients/payments/process.js.LICENSE.txt b/public/js/clients/payments/process.js.LICENSE.txt old mode 100644 new mode 100755 diff --git a/public/js/clients/payments/sofort.js b/public/js/clients/payments/sofort.js old mode 100644 new mode 100755 diff --git a/public/js/clients/payments/sofort.js.LICENSE.txt b/public/js/clients/payments/sofort.js.LICENSE.txt old mode 100644 new mode 100755 diff --git a/public/js/clients/payments/stripe-ach.js b/public/js/clients/payments/stripe-ach.js old mode 100644 new mode 100755 diff --git a/public/js/clients/payments/stripe-ach.js.LICENSE.txt b/public/js/clients/payments/stripe-ach.js.LICENSE.txt old mode 100644 new mode 100755 diff --git a/public/js/clients/payments/stripe-alipay.js b/public/js/clients/payments/stripe-alipay.js old mode 100644 new mode 100755 diff --git a/public/js/clients/payments/stripe-alipay.js.LICENSE.txt b/public/js/clients/payments/stripe-alipay.js.LICENSE.txt old mode 100644 new mode 100755 diff --git a/public/js/clients/payments/stripe-credit-card.js b/public/js/clients/payments/stripe-credit-card.js old mode 100644 new mode 100755 diff --git a/public/js/clients/payments/stripe-credit-card.js.LICENSE.txt b/public/js/clients/payments/stripe-credit-card.js.LICENSE.txt old mode 100644 new mode 100755 diff --git a/public/js/clients/payments/stripe-sofort.js b/public/js/clients/payments/stripe-sofort.js old mode 100644 new mode 100755 diff --git a/public/js/clients/payments/stripe-sofort.js.LICENSE.txt b/public/js/clients/payments/stripe-sofort.js.LICENSE.txt old mode 100644 new mode 100755 diff --git a/public/js/clients/quotes/action-selectors.js b/public/js/clients/quotes/action-selectors.js old mode 100644 new mode 100755 diff --git a/public/js/clients/quotes/action-selectors.js.LICENSE.txt b/public/js/clients/quotes/action-selectors.js.LICENSE.txt old mode 100644 new mode 100755 diff --git a/public/js/clients/quotes/approve.js b/public/js/clients/quotes/approve.js old mode 100644 new mode 100755 diff --git a/public/js/clients/quotes/approve.js.LICENSE.txt b/public/js/clients/quotes/approve.js.LICENSE.txt old mode 100644 new mode 100755 diff --git a/public/js/clients/shared/multiple-downloads.js b/public/js/clients/shared/multiple-downloads.js old mode 100644 new mode 100755 diff --git a/public/js/clients/shared/pdf.js b/public/js/clients/shared/pdf.js old mode 100644 new mode 100755 diff --git a/public/js/clients/shared/pdf.js.LICENSE.txt b/public/js/clients/shared/pdf.js.LICENSE.txt old mode 100644 new mode 100755 diff --git a/public/js/coreui.js b/public/js/coreui.js old mode 100644 new mode 100755 diff --git a/public/js/coreui.min.js b/public/js/coreui.min.js old mode 100644 new mode 100755 diff --git a/public/js/localization.js b/public/js/localization.js old mode 100644 new mode 100755 diff --git a/public/js/localization.min.js b/public/js/localization.min.js old mode 100644 new mode 100755 diff --git a/public/js/ninja.js b/public/js/ninja.js old mode 100644 new mode 100755 diff --git a/public/js/ninja.min.js b/public/js/ninja.min.js old mode 100644 new mode 100755 diff --git a/public/js/setup/setup.js b/public/js/setup/setup.js old mode 100644 new mode 100755 diff --git a/public/js/setup/setup.js.LICENSE.txt b/public/js/setup/setup.js.LICENSE.txt old mode 100644 new mode 100755 diff --git a/public/js/vendor/app.js b/public/js/vendor/app.js old mode 100644 new mode 100755 diff --git a/public/js/vendor/datatables/datatables.min.css b/public/js/vendor/datatables/datatables.min.css old mode 100644 new mode 100755 diff --git a/public/js/vendor/datatables/datatables.min.js b/public/js/vendor/datatables/datatables.min.js old mode 100644 new mode 100755 diff --git a/public/js/vendor/jquery-3.3.1/jquery-3.3.1.js b/public/js/vendor/jquery-3.3.1/jquery-3.3.1.js old mode 100644 new mode 100755 diff --git a/public/js/vendor/jquery-3.3.1/jquery-3.3.1.min.js b/public/js/vendor/jquery-3.3.1/jquery-3.3.1.min.js old mode 100644 new mode 100755 diff --git a/public/js/vendor/pdf.js/pdf.min.js b/public/js/vendor/pdf.js/pdf.min.js old mode 100644 new mode 100755 diff --git a/public/js/vendor/pdf.js/pdf.worker.min.js b/public/js/vendor/pdf.js/pdf.worker.min.js old mode 100644 new mode 100755 diff --git a/public/main.dart.js b/public/main.dart.js old mode 100644 new mode 100755 diff --git a/public/main.dart.js.map b/public/main.dart.js.map old mode 100644 new mode 100755 diff --git a/public/manifest.json b/public/manifest.json old mode 100644 new mode 100755 diff --git a/public/mix-manifest.json b/public/mix-manifest.json old mode 100644 new mode 100755 diff --git a/public/robots.txt b/public/robots.txt old mode 100644 new mode 100755 diff --git a/public/svg/403.svg b/public/svg/403.svg old mode 100644 new mode 100755 diff --git a/public/svg/404.svg b/public/svg/404.svg old mode 100644 new mode 100755 diff --git a/public/svg/500.svg b/public/svg/500.svg old mode 100644 new mode 100755 diff --git a/public/svg/503.svg b/public/svg/503.svg old mode 100644 new mode 100755 diff --git a/public/vendor/dropzone-5.7.0/.gitignore b/public/vendor/dropzone-5.7.0/.gitignore old mode 100644 new mode 100755 diff --git a/public/vendor/dropzone-5.7.0/CONTRIBUTING.md b/public/vendor/dropzone-5.7.0/CONTRIBUTING.md old mode 100644 new mode 100755 diff --git a/public/vendor/dropzone-5.7.0/LICENSE b/public/vendor/dropzone-5.7.0/LICENSE old mode 100644 new mode 100755 diff --git a/public/vendor/dropzone-5.7.0/README.md b/public/vendor/dropzone-5.7.0/README.md old mode 100644 new mode 100755 diff --git a/public/vendor/dropzone-5.7.0/component.json b/public/vendor/dropzone-5.7.0/component.json old mode 100644 new mode 100755 diff --git a/public/vendor/dropzone-5.7.0/composer.json b/public/vendor/dropzone-5.7.0/composer.json old mode 100644 new mode 100755 diff --git a/public/vendor/dropzone-5.7.0/dist/basic.css b/public/vendor/dropzone-5.7.0/dist/basic.css old mode 100644 new mode 100755 diff --git a/public/vendor/dropzone-5.7.0/dist/dropzone-amd-module.js b/public/vendor/dropzone-5.7.0/dist/dropzone-amd-module.js old mode 100644 new mode 100755 diff --git a/public/vendor/dropzone-5.7.0/dist/dropzone.css b/public/vendor/dropzone-5.7.0/dist/dropzone.css old mode 100644 new mode 100755 diff --git a/public/vendor/dropzone-5.7.0/dist/dropzone.js b/public/vendor/dropzone-5.7.0/dist/dropzone.js old mode 100644 new mode 100755 diff --git a/public/vendor/dropzone-5.7.0/dist/dropzone.js.map b/public/vendor/dropzone-5.7.0/dist/dropzone.js.map old mode 100644 new mode 100755 diff --git a/public/vendor/dropzone-5.7.0/dist/min/basic.min.css b/public/vendor/dropzone-5.7.0/dist/min/basic.min.css old mode 100644 new mode 100755 diff --git a/public/vendor/dropzone-5.7.0/dist/min/dropzone-amd-module.min.js b/public/vendor/dropzone-5.7.0/dist/min/dropzone-amd-module.min.js old mode 100644 new mode 100755 diff --git a/public/vendor/dropzone-5.7.0/dist/min/dropzone.min.css b/public/vendor/dropzone-5.7.0/dist/min/dropzone.min.css old mode 100644 new mode 100755 diff --git a/public/vendor/dropzone-5.7.0/dist/min/dropzone.min.js b/public/vendor/dropzone-5.7.0/dist/min/dropzone.min.js old mode 100644 new mode 100755 diff --git a/public/vendor/dropzone-5.7.0/index.js b/public/vendor/dropzone-5.7.0/index.js old mode 100644 new mode 100755 diff --git a/public/vendor/dropzone-5.7.0/package.json b/public/vendor/dropzone-5.7.0/package.json old mode 100644 new mode 100755 diff --git a/public/vendor/livewire/livewire.js b/public/vendor/livewire/livewire.js old mode 100644 new mode 100755 diff --git a/public/vendor/livewire/livewire.js.map b/public/vendor/livewire/livewire.js.map old mode 100644 new mode 100755 diff --git a/public/vendor/livewire/manifest.json b/public/vendor/livewire/manifest.json old mode 100644 new mode 100755 diff --git a/public/version.json b/public/version.json old mode 100644 new mode 100755 diff --git a/routes/api.php b/routes/api.php index 85376b4e6e29..609f364eab58 100644 --- a/routes/api.php +++ b/routes/api.php @@ -169,6 +169,7 @@ Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'a Route::get('company_ledger', 'CompanyLedgerController@index')->name('company_ledger.index'); Route::post('preimport', 'ImportController@preimport')->name('import.preimport'); + Route::post('import', 'ImportController@import')->name('import.import'); /* Route::resource('tasks', 'TaskController'); // name = (tasks. index / create / show / update / destroy / edit diff --git a/tests/Feature/Import/ImportCsvTest.php b/tests/Feature/Import/ImportCsvTest.php index 8d7fb687c662..807ecf7b921c 100644 --- a/tests/Feature/Import/ImportCsvTest.php +++ b/tests/Feature/Import/ImportCsvTest.php @@ -10,8 +10,11 @@ */ namespace Tests\Feature\Import; +use App\Jobs\Import\CSVImport; use App\Utils\Traits\MakesHash; use Illuminate\Routing\Middleware\ThrottleRequests; +use Illuminate\Support\Facades\Cache; +use Illuminate\Support\Str; use League\Csv\Reader; use League\Csv\Statement; use Tests\MockAccountData; @@ -36,7 +39,7 @@ class ImportCsvTest extends TestCase // $this->faker = \Faker\Factory::create(); - // $this->makeTestData(); + $this->makeTestData(); $this->withoutExceptionHandling(); } @@ -49,6 +52,34 @@ class ImportCsvTest extends TestCase } + public function testClientCsvImport() + { + $csv = file_get_contents(base_path().'/tests/Feature/Import/clients.csv'); + $hash = Str::random(32); + $column_map = [ + 1 => 'client.balance', + 2 => 'client.paid_to_date', + 0 => 'client.name', + 19 => 'client.currency_id', + 20 => 'client.public_notes', + 21 => 'client.private_notes', + 22 => 'contact.first_name', + 23 => 'contact.last_name', + ]; + + $data = [ + 'hash' => $hash, + 'column_map' => $column_map, + 'skip_header' => true, + 'entity_type'=> 'client', + ]; + + Cache::put($hash, base64_encode($csv), 360); + + CSVImport::dispatchNow($data, $this->company); + + } + private function getCsvData($csvfile) { if (! ini_get('auto_detect_line_endings')) { diff --git a/tests/Feature/Import/clients.csv b/tests/Feature/Import/clients.csv new file mode 100644 index 000000000000..772d58a3d196 --- /dev/null +++ b/tests/Feature/Import/clients.csv @@ -0,0 +1,24 @@ +"Invoice Ninja v4.5.17 - December 15, 2020 10:58 pm","","","","","","","","","","","","","","","","","","","","","","","","","" +"","","","","","","","","","","","","","","","","","","","","","","","","","" +"CLIENTS","","","","","","","","","","","","","","","","","","","","","","","","","" +"Name","Balance","Paid to Date","Billing Street","Billing Apt/Suite","Billing City","Billing State/Province","Billing Postal Code","Billing Country","Shipping Street","Shipping Apt/Suite","Shipping City","Shipping State/Province","Shipping Postal Code","Shipping Country","ID Number","VAT Number","Website","Phone","Currency","Public Notes","Private Notes","First Name","Last Name","Email","Phone" +"Ludwig Krajcik DVM","$-142.85","$205.15","371 O'Connell Summit","Suite 612","Lornamouth","New York","83425-0771","","","","","","","","","","","","","","","Terrill","Ondricka","brook59@example.org","1-537-759-0369" +"Bradly Jaskolski Sr.","$310.81","$313.71","21854 Prosacco Isle","Suite 619","Vicentastad","Colorado","05144","","","","","","","","","","","","","","","Pink","Balistreri","gheidenreich@example.org","1-995-790-2394 x58884" +"Mr. Dustin Stehr I","$285.70","$250.97","2941 Terence Station","Apt. 761","Bernierbury","Massachusetts","47675","","","","","","","","","","","","","","","Shemar","Stehr","labadie.dominique@example.com","624-610-5940" +"Dr. Baron Armstrong Sr.","$241.53","$280.42","9469 Ofelia Gateway","Suite 748","Evelynside","New Hampshire","66872","","","","","","","","","","","","","","","Fabiola","Mitchell","nico78@example.net","1-986-772-8058 x00345" +"Dr. Clemens Douglas MD","$317.94","$342.92","2919 Thompson Common Suite 410","Suite 381","Port Margie","Nevada","49890","","","","","","","","","","","","","","","Lolita","Tremblay","daphney.marquardt@example.com","1-461-699-9192 x9875" +"Dr. Claire Huel Sr.","$333.45","$359.51","363 Arlene Causeway Suite 763","Suite 409","Millerstad","Florida","25750","","","","","","","","","","","","","","","Brown","Lakin","vbeer@example.net","(776) 821-0650 x839" +"Francisca Padberg","$366.58","$203.16","5558 Ratke Flats","Suite 511","Krystelport","Alabama","15359-3783","","","","","","","","","","","","","","","Hallie","Dooley","kgottlieb@example.net","1-573-770-4753 x72129" +"Dr. Roy Kihn","$272.12","$251.41","20236 O'Hara Shores","Suite 368","Aliciaport","North Carolina","35415","","","","","","","","","","","","","","","Elwyn","Daugherty","wunsch.rozella@example.org","(745) 859-5855 x04216" +"Nasir Vandervort","$401.23","$173.17","24599 Hills Centers Suite 467","Apt. 038","North German","Ohio","85363-4720","","","","","","","","","","","","","","","Tre","Moore","wilfrid.kuhic@example.com","1-519-675-7395" +"Garry Rosenbaum","$271.82","$306.63","7127 Heidenreich Union Apt. 168","Suite 441","North Murray","North Carolina","29242","","","","","","","","","","","","","","","Ricardo","Johnston","ddubuque@example.com","(682) 216-1962" +"Hildegard Crona PhD","$398.96","$162.49","60142 Janice Islands","Apt. 627","South Stantown","Colorado","10298-5737","","","","","","","","","","","","","","","Miles","Tremblay","sabrina86@example.org","775-210-8656 x93138" +"Kristopher White I","$318.14","$423.20","7498 Brook Crest Apt. 175","Suite 682","Marianoland","Connecticut","86235-9979","","","","","","","","","","","","","","","Mateo","Welch","jedidiah64@example.com","847.353.7644" +"Ethan Grant","$380.71","$367.38","26755 June Extension Suite 589","Suite 706","North Krystelmouth","Delaware","12414","","","","","","","","","","","","","","","Colton","Muller","dorian.mayert@example.net","(267) 647-0537" +"Terry Shields","$230.25","$290.83","60946 Kayden Camp Apt. 046","Apt. 178","Douglashaven","Wyoming","68992","","","","","","","","","","","","","","","Dashawn","Homenick","hills.gina@example.net","(478) 814-9961" +"Agustina Lockman","$351.60","$264.81","152 Pattie Coves","Suite 971","North Mohamed","Hawaii","52966","","","","","","","","","","","","","","","Bert","Fritsch","greilly@example.org","15342929833" +"Alfonso Schimmel","$343.71","$200.99","358 Hills Coves","Apt. 032","Lake Aisha","District of Columbia","68945-0439","","","","","","","","","","","","","","","Antonio","Hayes","dkshlerin@example.com","1-350-691-4459 x775" +"Vergie Monahan","$210.27","$201.10","64004 Anderson Mall Suite 207","Suite 469","Oleshire","California","78369","","","","","","","","","","","","","","","Hilario","Morissette","zjacobs@example.net","552.914.6800 x81120" +"Carol Cremin","$301.53","$473.39","68731 Bartoletti Crescent","Suite 855","Aaronland","Wyoming","07924","","","","","","","","","","","","","","","Nathen","Wehner","jacobi.rosendo@example.com","1-223-910-2060 x09970" +"Randal Bosco MD","$318.71","$226.47","51884 Peter Falls","Suite 314","Angelicaville","Nebraska","78016-3254","","","","","","","","","","","","","","","Angelo","Ward","kozey.aurelio@example.org","1-329-488-8800" +"Ms. Alena Cassin","$262.45","$388.50","706 Delfina Burgs","Apt. 996","Bertaton","Ohio","22957","","","","","","","","","","","","","","","Eusebio","Reinger","golden.green@example.org","429-551-1362"