diff --git a/app/Http/Controllers/ImportController.php b/app/Http/Controllers/ImportController.php index 8d65b0e33d13..e98adb53a90e 100644 --- a/app/Http/Controllers/ImportController.php +++ b/app/Http/Controllers/ImportController.php @@ -84,9 +84,11 @@ class ImportController extends Controller //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 index adb135b867b0..c8edf27e75fc 100644 --- a/app/Import/Definitions/ClientMap.php +++ b/app/Import/Definitions/ClientMap.php @@ -44,7 +44,15 @@ class ClientMap 25 => 'client.payment_terms', 26 => 'client.vat_number', 27 => 'client.id_number', - 28 => 'client.public_notes' + 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', ]; } @@ -53,57 +61,41 @@ class ClientMap return [ 0 => 'texts.client_name', 1 => 'texts.user', - 2 => 'texts.amount', - 3 => 'texts.balance', - 4 => 'texts.client', - 5 => 'texts.discount', - 6 => 'texts.po_number', - 7 => 'texts.date', - 8 => 'texts.due_date', - 9 => 'texts.terms', - 10 => 'texts.public_notes', - 11 => 'texts.sent', - 12 => 'texts.private_notes', - 13 => 'texts.uses_inclusive_taxes', - 14 => 'texts.tax_name', - 15 => 'texts.tax_rate', - 16 => 'texts.tax_name', - 17 => 'texts.tax_rate', - 18 => 'texts.tax_name', - 19 => 'texts.tax_rate', - 20 => 'texts.is_amount_discount', - 21 => 'texts.footer', - 22 => 'texts.partial', - 23 => 'texts.partial_due_date', - 24 => 'texts.custom_value1', - 25 => 'texts.custom_value2', - 26 => 'texts.custom_value3', - 27 => 'texts.custom_value4', - 28 => 'texts.surcharge', - 29 => 'texts.surcharge', - 30 => 'texts.surcharge', - 31 => 'texts.surcharge', - 32 => 'texts.exchange_rate', - 33 => 'texts.payment_date', - 34 => 'texts.payment_amount', - 35 => 'texts.transaction_reference', - 36 => 'texts.quantity', - 37 => 'texts.cost', - 38 => 'texts.product_key', - 39 => 'texts.notes', - 40 => 'texts.discount', - 41 => 'texts.is_amount_discount', - 42 => 'texts.tax_name', - 43 => 'texts.tax_rate', - 44 => 'texts.tax_name', - 45 => 'texts.tax_rate', - 46 => 'texts.tax_name', - 47 => 'texts.tax_rate', - 48 => 'texts.custom_value', - 49 => 'texts.custom_value', - 50 => 'texts.custom_value', - 51 => 'texts.custom_value', - 52 => 'texts.type', + 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/Jobs/Import/CSVImport.php b/app/Jobs/Import/CSVImport.php index 49657ce0d065..9b51b78409ca 100644 --- a/app/Jobs/Import/CSVImport.php +++ b/app/Jobs/Import/CSVImport.php @@ -12,6 +12,7 @@ namespace App\Jobs\Import; use App\Libraries\MultiDB; +use App\Models\Company; use Exception; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; @@ -20,6 +21,8 @@ use Illuminate\Http\Request; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; use Illuminate\Support\Facades\Cache; +use League\Csv\Reader; +use League\Csv\Statement; class CSVImport implements ShouldQueue { @@ -33,19 +36,42 @@ class CSVImport implements ShouldQueue public $entity_type; - public $skip_headers; + public $skip_header; - public function __construct(Request $request, Company $company) + public $column_map; + + /* + [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 +84,10 @@ class CSVImport implements ShouldQueue { MultiDB::setDb($this->company->db); + foreach($this->getCsv() as $record) { + + } + } public function failed($exception) @@ -65,10 +95,31 @@ class CSVImport implements ShouldQueue } - private function getCsv() + private function getCsvData() { $base64_encoded_csv = Cache::get($this->hash); + $csv = base64_decode($base64_encoded_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, 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/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