Working on CSV imports

This commit is contained in:
David Bomba 2020-12-16 11:01:15 +11:00
parent b087046489
commit 8df553c4cc
5 changed files with 119 additions and 65 deletions

View File

@ -84,9 +84,11 @@ class ImportController extends Controller
//parse CSV //parse CSV
$csv_array = $this->getCsvData(file_get_contents($request->file('file')->getPathname())); $csv_array = $this->getCsvData(file_get_contents($request->file('file')->getPathname()));
$class_map = $this->getEntityMap($request->input('entity_type'));
$data = [ $data = [
'hash' => $hash, 'hash' => $hash,
'available' => InvoiceMap::importable(), 'available' => $class_map::importable(),
'headers' => array_slice($csv_array, 0, 2) 'headers' => array_slice($csv_array, 0, 2)
]; ];
@ -95,11 +97,17 @@ class ImportController extends Controller
public function import(ImportRequest $request) 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); 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) private function getCsvData($csvfile)
{ {

View File

@ -29,8 +29,10 @@ class ImportRequest extends Request
{ {
return [ return [
'hash' => 'required', 'hash' => 'required|string',
'entity_type' => 'required', 'entity_type' => 'required|string',
'column_map' => 'required|array',
'skip_header' => 'required|boolean'
]; ];
} }

View File

@ -44,7 +44,15 @@ class ClientMap
25 => 'client.payment_terms', 25 => 'client.payment_terms',
26 => 'client.vat_number', 26 => 'client.vat_number',
27 => 'client.id_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 [ return [
0 => 'texts.client_name', 0 => 'texts.client_name',
1 => 'texts.user', 1 => 'texts.user',
2 => 'texts.amount', 2 => 'texts.balance',
3 => 'texts.balance', 3 => 'texts.paid_to_date',
4 => 'texts.client', 4 => 'texts.currency',
5 => 'texts.discount', 5 => 'texts.website',
6 => 'texts.po_number', 6 => 'texts.private_notes',
7 => 'texts.date', 7 => 'texts.industry',
8 => 'texts.due_date', 8 => 'texts.size',
9 => 'texts.terms', 9 => 'texts.address1',
10 => 'texts.public_notes', 10 => 'texts.address2',
11 => 'texts.sent', 11 => 'texts.city',
12 => 'texts.private_notes', 12 => 'texts.state',
13 => 'texts.uses_inclusive_taxes', 13 => 'texts.postal_code',
14 => 'texts.tax_name', 14 => 'texts.country',
15 => 'texts.tax_rate', 15 => 'texts.custom_value',
16 => 'texts.tax_name', 16 => 'texts.custom_value',
17 => 'texts.tax_rate', 17 => 'texts.custom_value',
18 => 'texts.tax_name', 18 => 'texts.custom_value',
19 => 'texts.tax_rate', 19 => 'texts.address1',
20 => 'texts.is_amount_discount', 20 => 'texts.address2',
21 => 'texts.footer', 21 => 'texts.shipping_city',
22 => 'texts.partial', 22 => 'texts.shipping_state',
23 => 'texts.partial_due_date', 23 => 'texts.shipping_postal_code',
24 => 'texts.custom_value1', 24 => 'texts.shipping_country',
25 => 'texts.custom_value2', 25 => 'texts.payment_terms',
26 => 'texts.custom_value3', 26 => 'texts.vat_number',
27 => 'texts.custom_value4', 27 => 'texts.id_number',
28 => 'texts.surcharge', 28 => 'texts.public_notes',
29 => 'texts.surcharge', 29 => 'texts.first_name',
30 => 'texts.surcharge', 30 => 'texts.last_name',
31 => 'texts.surcharge', 31 => 'texts.email',
32 => 'texts.exchange_rate', 32 => 'texts.phone',
33 => 'texts.payment_date', 33 => 'texts.custom_value',
34 => 'texts.payment_amount', 34 => 'texts.custom_value',
35 => 'texts.transaction_reference', 35 => 'texts.custom_value',
36 => 'texts.quantity', 36 => 'texts.custom_value',
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',
]; ];
} }
} }

View File

@ -12,6 +12,7 @@
namespace App\Jobs\Import; namespace App\Jobs\Import;
use App\Libraries\MultiDB; use App\Libraries\MultiDB;
use App\Models\Company;
use Exception; use Exception;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
@ -20,6 +21,8 @@ use Illuminate\Http\Request;
use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Cache;
use League\Csv\Reader;
use League\Csv\Statement;
class CSVImport implements ShouldQueue class CSVImport implements ShouldQueue
{ {
@ -33,19 +36,42 @@ class CSVImport implements ShouldQueue
public $entity_type; 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->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); MultiDB::setDb($this->company->db);
foreach($this->getCsv() as $record) {
}
} }
public function failed($exception) 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); $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); // <blank line>
array_shift($data); // Enitty Type Header
}
}
}
return $data;
return base64_decode($base64_encoded_csv);
} }
} }

View File

@ -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::get('company_ledger', 'CompanyLedgerController@index')->name('company_ledger.index');
Route::post('preimport', 'ImportController@preimport')->name('import.preimport'); 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 Route::resource('tasks', 'TaskController'); // name = (tasks. index / create / show / update / destroy / edit