mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-10 05:02:36 +01:00
Working on CSV import
This commit is contained in:
parent
a324434375
commit
1a37a197a5
@ -22,6 +22,7 @@ class ImportController extends BaseController
|
||||
{
|
||||
$source = Input::get('source');
|
||||
$files = [];
|
||||
$skipped = [];
|
||||
|
||||
foreach (ImportService::$entityTypes as $entityType) {
|
||||
if (Input::file("{$entityType}_file")) {
|
||||
@ -34,8 +35,16 @@ class ImportController extends BaseController
|
||||
$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);
|
||||
$skipped = $this->importService->import($source, $files);
|
||||
if (count($skipped)) {
|
||||
$message = trans('texts.failed_to_import');
|
||||
foreach ($skipped as $skip) {
|
||||
$message .= '<br/>' . json_encode($skip);
|
||||
}
|
||||
Session::flash('warning', $message);
|
||||
} else {
|
||||
Session::flash('message', trans('texts.imported_file'));
|
||||
}
|
||||
}
|
||||
} catch (Exception $exception) {
|
||||
Session::flash('error', $exception->getMessage());
|
||||
@ -48,15 +57,23 @@ class ImportController extends BaseController
|
||||
{
|
||||
$map = Input::get('map');
|
||||
$headers = Input::get('headers');
|
||||
$skipped = [];
|
||||
|
||||
//try {
|
||||
$count = $this->importService->importCSV($map, $headers);
|
||||
$message = Utils::pluralize('created_client', $count);
|
||||
try {
|
||||
$skipped = $this->importService->importCSV($map, $headers);
|
||||
|
||||
Session::flash('message', $message);
|
||||
//} catch (Exception $exception) {
|
||||
// Session::flash('error', $exception->getMessage());
|
||||
//}
|
||||
if (count($skipped)) {
|
||||
$message = trans('texts.failed_to_import');
|
||||
foreach ($skipped as $skip) {
|
||||
$message .= '<br/>' . json_encode($skip);
|
||||
}
|
||||
Session::flash('warning', $message);
|
||||
} else {
|
||||
Session::flash('message', trans('texts.imported_file'));
|
||||
}
|
||||
} catch (Exception $exception) {
|
||||
Session::flash('error', $exception->getMessage());
|
||||
}
|
||||
|
||||
return Redirect::to('/settings/' . ACCOUNT_IMPORT_EXPORT);
|
||||
}
|
||||
|
@ -71,19 +71,18 @@ class Client extends EntityModel
|
||||
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,
|
||||
'first' => 'first_name',
|
||||
'last' => 'last_name',
|
||||
'email' => 'email',
|
||||
'mobile|phone' => 'phone',
|
||||
'name|organization' => 'name',
|
||||
'street2|address2' => 'address2',
|
||||
'street|address|address1' => 'address1',
|
||||
'city' => 'city',
|
||||
'state|province' => 'state',
|
||||
'zip|postal|code' => 'postal_code',
|
||||
'country' => 'country',
|
||||
'note' => 'notes',
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -65,11 +65,11 @@ class Invoice extends EntityModel implements BalanceAffecting
|
||||
public static function getImportMap()
|
||||
{
|
||||
return [
|
||||
'number' => Invoice::$fieldInvoiceNumber,
|
||||
'amount' => Invoice::$fieldAmount,
|
||||
'number^po' => 'invoice_number',
|
||||
'amount' => 'amount',
|
||||
'organization' => 'name',
|
||||
'paid' => 'paid',
|
||||
'invoice_date' => Invoice::$fieldInvoiceDate,
|
||||
'paid^date' => 'paid',
|
||||
'invoice_date|create_date' => 'invoice_date',
|
||||
'terms' => 'terms',
|
||||
'notes' => 'notes',
|
||||
];
|
||||
|
@ -59,46 +59,24 @@ class ImportService
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
Excel::load($file, function ($reader) use ($source, $entityType) {
|
||||
$skipped = [];
|
||||
|
||||
Excel::load($file, function ($reader) use ($source, $entityType, $skipped) {
|
||||
$this->checkData($entityType, count($reader->all()));
|
||||
$maps = $this->createMaps();
|
||||
|
||||
$reader->each(function ($row) use ($source, $entityType, $maps) {
|
||||
$this->saveData($source, $entityType, $row, $maps);
|
||||
$result = $this->saveData($source, $entityType, $row, $maps);
|
||||
|
||||
if ( ! $result) {
|
||||
$skipped[] = $row;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
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");
|
||||
return $skipped;
|
||||
}
|
||||
|
||||
private function saveData($source, $entityType, $row, $maps)
|
||||
@ -112,6 +90,7 @@ class ImportService
|
||||
|
||||
$data = $this->fractal->createData($resource)->toArray();
|
||||
|
||||
// if the invoice number is blank we'll assign it
|
||||
if ($entityType == ENTITY_INVOICE && !$data['invoice_number']) {
|
||||
$account = Auth::user()->account;
|
||||
$invoice = Invoice::createNew();
|
||||
@ -137,6 +116,14 @@ class ImportService
|
||||
}
|
||||
}
|
||||
|
||||
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()]));
|
||||
}
|
||||
}
|
||||
|
||||
public static function getTransformerClassName($source, $entityType)
|
||||
{
|
||||
return 'App\\Ninja\\Import\\'.$source.'\\'.ucwords($entityType).'Transformer';
|
||||
@ -162,15 +149,14 @@ class ImportService
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
if ($entityType === ENTITY_CLIENT) {
|
||||
$rules = [
|
||||
'contacts' => 'valid_contacts',
|
||||
];
|
||||
} if ($entityType === ENTITY_INVOICE) {
|
||||
}
|
||||
if ($entityType === ENTITY_INVOICE) {
|
||||
$rules = [
|
||||
'client.contacts' => 'valid_contacts',
|
||||
'invoice_items' => 'valid_invoice_items',
|
||||
@ -279,13 +265,9 @@ class ImportService
|
||||
|
||||
if ($hasHeaders) {
|
||||
foreach ($map as $search => $column) {
|
||||
foreach (explode("|", $search) as $string) {
|
||||
if (strpos($title, 'sec') === 0) {
|
||||
continue;
|
||||
} elseif (strpos($title, $string) !== false) {
|
||||
if ($this->checkForMatch($title, $search)) {
|
||||
$mapped[$i] = $column;
|
||||
break(2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -304,11 +286,77 @@ class ImportService
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function checkForMatch($column, $pattern)
|
||||
{
|
||||
if (strpos($column, 'sec') === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strpos($pattern, '^')) {
|
||||
list($include, $exclude) = explode('^', $pattern);
|
||||
$includes = explode('|', $include);
|
||||
$excludes = explode('|', $exclude);
|
||||
} else {
|
||||
$includes = explode('|', $pattern);
|
||||
$excludes = [];
|
||||
}
|
||||
|
||||
foreach ($includes as $string) {
|
||||
if (strpos($column, $string) !== false) {
|
||||
$excluded = false;
|
||||
foreach ($excludes as $exclude) {
|
||||
if (strpos($column, $exclude) !== false) {
|
||||
$excluded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$excluded) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function importCSV($maps, $headers)
|
||||
{
|
||||
$skipped = [];
|
||||
|
||||
foreach ($maps as $entityType => $map) {
|
||||
$this->executeCSV($entityType, $map, $headers[$entityType]);
|
||||
$result = $this->executeCSV($entityType, $map, $headers[$entityType]);
|
||||
$skipped = array_merge($skipped, $result);
|
||||
}
|
||||
|
||||
return $skipped;
|
||||
}
|
||||
|
||||
private function executeCSV($entityType, $map, $hasHeaders)
|
||||
{
|
||||
$skipped = [];
|
||||
$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);
|
||||
$result = $this->saveData($source, $entityType, $row, $maps);
|
||||
|
||||
if ( ! $result) {
|
||||
$skipped[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
Session::forget("{$entityType}-data");
|
||||
|
||||
return $skipped;
|
||||
}
|
||||
|
||||
private function convertToObject($entityType, $data, $map)
|
||||
@ -330,6 +378,10 @@ class ImportService
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($obj->$field) && $obj->$field) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$obj->$field = $data[$index];
|
||||
}
|
||||
|
||||
|
@ -948,5 +948,6 @@ return array(
|
||||
'notes' => 'Notes',
|
||||
'invoice_will_create' => 'client will be created',
|
||||
'invoices_will_create' => 'invoices will be created',
|
||||
'failed_to_import' => 'The following records failed to import',
|
||||
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user