From 6e2eeba0f61cdeea5971a9a6768c875922e7bc50 Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 29 May 2025 14:47:54 +0100 Subject: [PATCH 1/9] Added supplier importer Signed-off-by: snipe --- app/Importer/ItemImporter.php | 2 +- app/Importer/SupplierImporter.php | 105 ++++++++++++++++++++++++++++++ app/Livewire/Importer.php | 30 +++++++-- 3 files changed, 129 insertions(+), 8 deletions(-) create mode 100644 app/Importer/SupplierImporter.php diff --git a/app/Importer/ItemImporter.php b/app/Importer/ItemImporter.php index dfcd644c9d..0f3461e19f 100644 --- a/app/Importer/ItemImporter.php +++ b/app/Importer/ItemImporter.php @@ -110,7 +110,7 @@ class ItemImporter extends Importer protected function determineCheckout($row) { // Locations don't get checked out to anyone/anything - if ((get_class($this) == LocationImporter::class) || (get_class($this) == AssetModelImporter::class)) { + if ((get_class($this) == LocationImporter::class) || (get_class($this) == AssetModelImporter::class) || (get_class($this) == SupplierImporter::class)) { return; } diff --git a/app/Importer/SupplierImporter.php b/app/Importer/SupplierImporter.php new file mode 100644 index 0000000000..7878aff835 --- /dev/null +++ b/app/Importer/SupplierImporter.php @@ -0,0 +1,105 @@ +createSupplierIfNotExists($row); + } + + /** + * Create a supplier if a duplicate does not exist. + * @todo Investigate how this should interact with Importer::createSupplierIfNotExists + * + * @author A. Gianotto + * @since 6.1.0 + * @param array $row + */ + public function createSupplierIfNotExists(array $row) + { + + $editingSupplier = false; + + $supplier = Supplier::where('name', '=', $this->findCsvMatch($row, 'name'))->first(); + + if ($this->findCsvMatch($row, 'id')!='') { + // Override supplier if an ID was given + \Log::debug('Finding supplier by ID: '.$this->findCsvMatch($row, 'id')); + $supplier = Supplier::find($this->findCsvMatch($row, 'id')); + } + + + if ($supplier) { + if (! $this->updating) { + $this->log('A matching Supplier '.$this->item['name'].' already exists'); + return; + } + + $this->log('Updating Supplier'); + $editingSupplier = true; + } else { + $this->log('No Matching Supplier, Create a new one'); + $supplier = new Supplier; + $supplier->created_by = auth()->id(); + } + + // Pull the records from the CSV to determine their values + $this->item['name'] = trim($this->findCsvMatch($row, 'name')); + $this->item['address'] = trim($this->findCsvMatch($row, 'address')); + $this->item['address2'] = trim($this->findCsvMatch($row, 'address2')); + $this->item['city'] = trim($this->findCsvMatch($row, 'city')); + $this->item['state'] = trim($this->findCsvMatch($row, 'state')); + $this->item['country'] = trim($this->findCsvMatch($row, 'country')); + $this->item['zip'] = trim($this->findCsvMatch($row, 'zip')); + $this->item['phone'] = trim($this->findCsvMatch($row, 'phone')); + $this->item['fax'] = trim($this->findCsvMatch($row, 'fax')); + $this->item['email'] = trim($this->findCsvMatch($row, 'email')); + $this->item['contact'] = trim($this->findCsvMatch($row, 'contact')); + $this->item['url'] = trim($this->findCsvMatch($row, 'url')); + $this->item['notes'] = trim($this->findCsvMatch($row, 'notes')); + + + Log::debug('Item array is: '); + Log::debug(print_r($this->item, true)); + + + if ($editingSupplier) { + Log::debug('Updating existing supplier'); + $supplier->update($this->sanitizeItemForUpdating($supplier)); + } else { + Log::debug('Creating supplier'); + $supplier->fill($this->sanitizeItemForStoring($supplier)); + } + + if ($supplier->save()) { + $this->log('Supplier '.$supplier->name.' created or updated from CSV import'); + return $supplier; + + } else { + Log::debug($supplier->getErrors()); + $this->logError($supplier, 'Supplier "'.$this->item['name'].'"'); + return $supplier->errors; + } + + + } +} \ No newline at end of file diff --git a/app/Livewire/Importer.php b/app/Livewire/Importer.php index 5f30dca7be..55752a5c2f 100644 --- a/app/Livewire/Importer.php +++ b/app/Livewire/Importer.php @@ -35,6 +35,8 @@ class Importer extends Component public $accessories_fields; public $assets_fields; public $users_fields; + public $assetmodels_fields; + public $suppliers_fields; public $licenses_fields; public $locations_fields; public $consumables_fields; @@ -85,9 +87,6 @@ class Importer extends Component case 'component': $results = $this->components_fields; break; - case 'consumable': - $results = $this->consumables_fields; - break; case 'license': $results = $this->licenses_fields; break; @@ -97,8 +96,8 @@ class Importer extends Component case 'location': $results = $this->locations_fields; break; - case 'user': - $results = $this->users_fields; + case 'supplier': + $results = $this->suppliers_fields; break; default: $results = []; @@ -128,7 +127,7 @@ class Importer extends Component //yes, this key *is* valid. Continue on to the next field. continue; } else { - //no, this key is *INVALID* for this import type. Better set it to null + //no, this key is *INVALID* for this import type. Better set it to null, // and we'll hope that the $aliases_fields or something else picks it up. $this->field_map[$i] = null; // fingers crossed! But it's not likely, tbh. } // TODO - strictly speaking, this isn't necessary here I don't think. @@ -149,7 +148,7 @@ class Importer extends Component // in "Accessories"!) if (array_key_exists($key, $this->columnOptions[$type])) { $this->field_map[$i] = $key; - continue 3; // bust out of both of these loops; as well as the surrounding one - e.g. move on to the next header + continue 3; // bust out of both of these loops and the surrounding one - e.g. move on to the next header } } } @@ -171,6 +170,7 @@ class Importer extends Component 'license' => trans('general.licenses'), 'location' => trans('general.locations'), 'user' => trans('general.users'), + 'supplier' => trans('general.suppliers'), ]; /** @@ -347,6 +347,22 @@ class Importer extends Component 'zip' => trans('general.zip'), ]; + $this->suppliers_fields = [ + 'id' => trans('general.id'), + 'name' => trans('general.item_name_var', ['item' => trans('general.supplier')]), + 'address' => trans('general.address'), + 'address2' => trans('general.importer.address2'), + 'city' => trans('general.city'), + 'notes' => trans('general.notes'), + 'state' => trans('general.state'), + 'zip' => trans('general.zip'), + 'phone' => trans('general.phone'), + 'fax' => trans('general.fax'), + 'url' => trans('general.url'), + 'contact' => trans('general.contact'), + 'email' => trans('general.email'), + ]; + $this->assetmodels_fields = [ 'category' => trans('general.category'), 'eol' => trans('general.eol'), From 12a2c71b901ba0edf730bf3588dd5e7fe939e99c Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 29 May 2025 14:47:59 +0100 Subject: [PATCH 2/9] Added icon Signed-off-by: snipe --- app/Helpers/Helper.php | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/app/Helpers/Helper.php b/app/Helpers/Helper.php index 995b7a7e4e..613bf10f7e 100644 --- a/app/Helpers/Helper.php +++ b/app/Helpers/Helper.php @@ -1313,25 +1313,20 @@ class Helper switch ($item) { case 'asset': return 'fas fa-barcode'; - break; case 'accessory': return 'fas fa-keyboard'; - break; case 'component': return 'fas fa-hdd'; - break; case 'consumable': return 'fas fa-tint'; - break; case 'license': return 'far fa-save'; - break; case 'location': return 'fas fa-map-marker-alt'; - break; case 'user': return 'fas fa-user'; - break; + case 'supplier': + return 'fa-solid fa-store'; } } From bf7cc404f8271c4b9315a910975d32d85806ae1b Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 29 May 2025 15:54:37 +0100 Subject: [PATCH 3/9] Set correct redirect Signed-off-by: snipe --- app/Http/Controllers/Api/ImportController.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/Http/Controllers/Api/ImportController.php b/app/Http/Controllers/Api/ImportController.php index 41597cd2c5..e3b644ed78 100644 --- a/app/Http/Controllers/Api/ImportController.php +++ b/app/Http/Controllers/Api/ImportController.php @@ -234,6 +234,9 @@ class ImportController extends Controller case 'location': $redirectTo = 'locations.index'; break; + case 'supplier': + $redirectTo = 'suppliers.index'; + break; } if ($errors) { //Failure From 59c6e26b2904beb6d514358732252add07fe5474 Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 29 May 2025 16:06:51 +0100 Subject: [PATCH 4/9] Fixed mapping Signed-off-by: snipe --- app/Livewire/Importer.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/Livewire/Importer.php b/app/Livewire/Importer.php index 55752a5c2f..63c9dec3e7 100644 --- a/app/Livewire/Importer.php +++ b/app/Livewire/Importer.php @@ -170,7 +170,7 @@ class Importer extends Component 'license' => trans('general.licenses'), 'location' => trans('general.locations'), 'user' => trans('general.users'), - 'supplier' => trans('general.suppliers'), + 'supplier' => trans('general.suppliers'), ]; /** @@ -332,6 +332,7 @@ class Importer extends Component $this->locations_fields = [ 'id' => trans('general.id'), + 'name' => trans('general.name'), 'address' => trans('general.address'), 'address2' => trans('general.importer.address2'), 'city' => trans('general.city'), @@ -340,7 +341,6 @@ class Importer extends Component 'ldap_ou' => trans('admin/locations/table.ldap_ou'), 'manager' => trans('general.importer.manager_full_name'), 'manager_username' => trans('general.importer.manager_username'), - 'name' => trans('general.item_name_var', ['item' => trans('general.location')]), 'notes' => trans('general.notes'), 'parent_location' => trans('admin/locations/table.parent'), 'state' => trans('general.state'), @@ -349,7 +349,7 @@ class Importer extends Component $this->suppliers_fields = [ 'id' => trans('general.id'), - 'name' => trans('general.item_name_var', ['item' => trans('general.supplier')]), + 'name' => trans('general.name'), 'address' => trans('general.address'), 'address2' => trans('general.importer.address2'), 'city' => trans('general.city'), @@ -387,6 +387,8 @@ class Importer extends Component 'consumable name', 'component name', 'name', + 'supplier name', + 'location name', ], 'item_no' => [ 'item number', From 94bd11d3c94bc955bdd229a02ccc6565b7061ef0 Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 29 May 2025 16:07:11 +0100 Subject: [PATCH 5/9] Added locations and supplier import types Signed-off-by: snipe --- database/factories/ImportFactory.php | 36 ++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/database/factories/ImportFactory.php b/database/factories/ImportFactory.php index 11fdbe17a9..f0b0bc0da4 100644 --- a/database/factories/ImportFactory.php +++ b/database/factories/ImportFactory.php @@ -165,4 +165,40 @@ class ImportFactory extends Factory }); } + /** + * Create a supplier import type. + * + * @return static + */ + public function suppliers() + { + return $this->state(function (array $attributes) { + $fileBuilder = Importing\SuppliersImportFileBuilder::new(); + $attributes['name'] = "Supplier {$attributes['name']}"; + $attributes['import_type'] = 'supplier'; + $attributes['header_row'] = $fileBuilder->toCsv()[0]; + $attributes['first_row'] = $fileBuilder->firstRow(); + + return $attributes; + }); + } + + /** + * Create an supplier import type. + * + * @return static + */ + public function locations() + { + return $this->state(function (array $attributes) { + $fileBuilder = Importing\SuppliersImportFileBuilder::new(); + $attributes['name'] = "Location {$attributes['name']}"; + $attributes['import_type'] = 'location'; + $attributes['header_row'] = $fileBuilder->toCsv()[0]; + $attributes['first_row'] = $fileBuilder->firstRow(); + + return $attributes; + }); + } + } From c08ce901cc7887b325562a46cb8e8efc0988bc97 Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 29 May 2025 16:07:19 +0100 Subject: [PATCH 6/9] Added strings Signed-off-by: snipe --- resources/lang/en-US/general.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/resources/lang/en-US/general.php b/resources/lang/en-US/general.php index d2e16aafbb..599a15c139 100644 --- a/resources/lang/en-US/general.php +++ b/resources/lang/en-US/general.php @@ -534,6 +534,9 @@ return [ 'action_source' => 'Action Source', 'or' => 'or', 'url' => 'URL', + 'phone' => 'Phone', + 'fax' => 'Fax', + 'contact' => 'Contact', 'edit_fieldset' => 'Edit fieldset fields and options', 'permission_denied_superuser_demo' => 'Permission denied. You cannot update user information for superadmins on the demo.', 'pwd_reset_not_sent' => 'User is not activated, is LDAP synced, or does not have an email address', From 13fd43c45ca460f9f055e45e18de3635642bd6e7 Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 29 May 2025 16:07:51 +0100 Subject: [PATCH 7/9] Added tests and test support Signed-off-by: snipe --- .../Importing/Api/ImportLocationsTest.php | 136 +++++++++++++++++ .../Importing/Api/ImportSuppliersTest.php | 141 ++++++++++++++++++ .../Importing/LocationsImportFileBuilder.php | 58 +++++++ .../Importing/SuppliersImportFileBuilder.php | 66 ++++++++ 4 files changed, 401 insertions(+) create mode 100644 tests/Feature/Importing/Api/ImportLocationsTest.php create mode 100644 tests/Feature/Importing/Api/ImportSuppliersTest.php create mode 100644 tests/Support/Importing/LocationsImportFileBuilder.php create mode 100644 tests/Support/Importing/SuppliersImportFileBuilder.php diff --git a/tests/Feature/Importing/Api/ImportLocationsTest.php b/tests/Feature/Importing/Api/ImportLocationsTest.php new file mode 100644 index 0000000000..88eeb5fa18 --- /dev/null +++ b/tests/Feature/Importing/Api/ImportLocationsTest.php @@ -0,0 +1,136 @@ +actingAsForApi(User::factory()->create()); + + $this->importFileResponse(['import' => 44])->assertForbidden(); + } + + #[Test] + public function importLocation(): void + { + $importFileBuilder = ImportFileBuilder::new(); + $row = $importFileBuilder->firstRow(); + $import = Import::factory()->locations()->create(['file_path' => $importFileBuilder->saveToImportsDirectory()]); + + $this->actingAsForApi(User::factory()->superuser()->create()); + $this->importFileResponse(['import' => $import->id, 'send-welcome' => 0]) + ->assertOk() + ->assertExactJson([ + 'payload' => null, + 'status' => 'success', + 'messages' => ['redirect_url' => route('locations.index')] + ]); + + $newLocation = Location::query() + ->where('name', $row['name']) + ->sole(); + + $this->assertEquals($row['name'], $newLocation->name); + + } + + #[Test] + public function willIgnoreUnknownColumnsWhenFileContainsUnknownColumns(): void + { + $row = ImportFileBuilder::new()->definition(); + $row['unknownColumnInCsvFile'] = 'foo'; + + $importFileBuilder = new ImportFileBuilder([$row]); + + $this->actingAsForApi(User::factory()->superuser()->create()); + + $import = Import::factory()->locations()->create(['file_path' => $importFileBuilder->saveToImportsDirectory()]); + + $this->importFileResponse(['import' => $import->id])->assertOk(); + } + + + #[Test] + public function whenRequiredColumnsAreMissingInImportFile(): void + { + $importFileBuilder = ImportFileBuilder::new(['name' => '']); + $import = Import::factory()->locations()->create(['file_path' => $importFileBuilder->saveToImportsDirectory()]); + + $this->actingAsForApi(User::factory()->superuser()->create()); + + $this->importFileResponse(['import' => $import->id]) + ->assertInternalServerError() + ->assertExactJson([ + 'status' => 'import-errors', + 'payload' => null, + 'messages' => [ + '' => [ + 'Location ""' => [ + 'name' => + ['The name field is required.'], + ], + ] + + ] + ]); + + $newLocation = Location::query() + ->where('name', $importFileBuilder->firstRow()['name']) + ->get(); + + $this->assertCount(0, $newLocation); + } + + + #[Test] + public function updateLocationFromImport(): void + { + $location = Location::factory()->create()->refresh(); + $importFileBuilder = ImportFileBuilder::new(['name' => $location->name, 'phone' => $location->phone]); + + $row = $importFileBuilder->firstRow(); + $import = Import::factory()->locations()->create(['file_path' => $importFileBuilder->saveToImportsDirectory()]); + + $this->actingAsForApi(User::factory()->superuser()->create()); + $this->importFileResponse(['import' => $import->id, 'import-update' => true])->assertOk(); + + $updatedLocation = Location::query()->find($location->id); + $updatedAttributes = [ + 'name', + 'phone', + ]; + + $this->assertEquals($row['name'], $updatedLocation->name); + + $this->assertEquals( + Arr::except($location->attributesToArray(), array_merge($updatedAttributes, $location->getDates())), + Arr::except($updatedLocation->attributesToArray(), array_merge($updatedAttributes, $location->getDates())), + ); + } + +} diff --git a/tests/Feature/Importing/Api/ImportSuppliersTest.php b/tests/Feature/Importing/Api/ImportSuppliersTest.php new file mode 100644 index 0000000000..c9d0b9c72e --- /dev/null +++ b/tests/Feature/Importing/Api/ImportSuppliersTest.php @@ -0,0 +1,141 @@ +actingAsForApi(User::factory()->create()); + + $this->importFileResponse(['import' => 44])->assertForbidden(); + } + + #[Test] + public function importSupplier(): void + { + $importFileBuilder = ImportFileBuilder::new(); + $row = $importFileBuilder->firstRow(); + $import = Import::factory()->suppliers()->create(['file_path' => $importFileBuilder->saveToImportsDirectory()]); + + $this->actingAsForApi(User::factory()->superuser()->create()); + $this->importFileResponse(['import' => $import->id, 'send-welcome' => 0]) + ->assertOk() + ->assertExactJson([ + 'payload' => null, + 'status' => 'success', + 'messages' => ['redirect_url' => route('suppliers.index')] + ]); + + $newSupplier = Supplier::query() + ->where('name', $row['name']) + ->sole(); + + $this->assertEquals($row['name'], $newSupplier->name); + + } + + #[Test] + public function willIgnoreUnknownColumnsWhenFileContainsUnknownColumns(): void + { + $row = ImportFileBuilder::new()->definition(); + $row['unknownColumnInCsvFile'] = 'foo'; + + $importFileBuilder = new ImportFileBuilder([$row]); + + $this->actingAsForApi(User::factory()->superuser()->create()); + + $import = Import::factory()->suppliers()->create(['file_path' => $importFileBuilder->saveToImportsDirectory()]); + + $this->importFileResponse(['import' => $import->id])->assertOk(); + } + + + #[Test] + public function whenRequiredColumnsAreMissingInImportFile(): void + { + $importFileBuilder = ImportFileBuilder::new(['name' => '']); + $import = Import::factory()->suppliers()->create(['file_path' => $importFileBuilder->saveToImportsDirectory()]); + + $this->actingAsForApi(User::factory()->superuser()->create()); + + $this->importFileResponse(['import' => $import->id]) + ->assertInternalServerError() + ->assertExactJson([ + 'status' => 'import-errors', + 'payload' => null, + 'messages' => [ + '' => [ + 'Supplier ""' => [ + 'name' => + ['The name field is required.'], + ], + ] + + ] + ]); + + $newSupplier = Supplier::query() + ->where('name', $importFileBuilder->firstRow()['name']) + ->get(); + + $this->assertCount(0, $newSupplier); + } + + + #[Test] + public function updateSupplierFromImport(): void + { + $supplier = Supplier::factory()->create()->refresh(); + $importFileBuilder = ImportFileBuilder::new(['name' => $supplier->name, 'url' => $supplier->url, 'phone' => $supplier->phone, 'fax' => $supplier->fax, 'contact' => $supplier->contact, 'email' => $supplier->email]); + + $row = $importFileBuilder->firstRow(); + $import = Import::factory()->suppliers()->create(['file_path' => $importFileBuilder->saveToImportsDirectory()]); + + $this->actingAsForApi(User::factory()->superuser()->create()); + $this->importFileResponse(['import' => $import->id, 'import-update' => true])->assertOk(); + + $updatedSupplier = Supplier::query()->find($supplier->id); + $updatedAttributes = [ + 'name', + 'url', + 'phone', + 'fax', + 'contact', + 'email', + ]; + + $this->assertEquals($row['name'], $updatedSupplier->name); + + $this->assertEquals( + Arr::except($supplier->attributesToArray(), array_merge($updatedAttributes, $supplier->getDates())), + Arr::except($updatedSupplier->attributesToArray(), array_merge($updatedAttributes, $supplier->getDates())), + ); + } + +} diff --git a/tests/Support/Importing/LocationsImportFileBuilder.php b/tests/Support/Importing/LocationsImportFileBuilder.php new file mode 100644 index 0000000000..59b7dcc416 --- /dev/null +++ b/tests/Support/Importing/LocationsImportFileBuilder.php @@ -0,0 +1,58 @@ + + */ +class LocationsImportFileBuilder extends FileBuilder +{ + /** + * @inheritdoc + */ + protected function getDictionary(): array + { + return [ + 'name' => 'name', + 'phone' => 'Phone', + 'address' => 'address', + 'address2' => 'address2', + 'city' => 'city', + 'state' => 'state', + 'country' => 'country', + 'zip' => 'zip', + 'notes' => 'notes', + ]; + } + + /** + * @inheritdoc + */ + public function definition(): array + { + $faker = fake(); + + return [ + 'name' => $faker->company, + 'phone' => $faker->phoneNumber, + ]; + } +} diff --git a/tests/Support/Importing/SuppliersImportFileBuilder.php b/tests/Support/Importing/SuppliersImportFileBuilder.php new file mode 100644 index 0000000000..7666174993 --- /dev/null +++ b/tests/Support/Importing/SuppliersImportFileBuilder.php @@ -0,0 +1,66 @@ + + */ +class SuppliersImportFileBuilder extends FileBuilder +{ + /** + * @inheritdoc + */ + protected function getDictionary(): array + { + return [ + 'name' => 'name', + 'email' => 'email', + 'contact' => 'contact', + 'phone' => 'Phone', + 'address' => 'address', + 'address2' => 'address2', + 'city' => 'city', + 'state' => 'state', + 'country' => 'country', + 'zip' => 'zip', + 'notes' => 'notes', + 'fax' => 'fax', + 'url' => 'url', + ]; + } + + /** + * @inheritdoc + */ + public function definition(): array + { + $faker = fake(); + + return [ + 'name' => $faker->company, + 'email' => Str::random(32) . "@{$faker->freeEmailDomain}", + 'contact' => $faker->firstName, + 'phone' => $faker->phoneNumber, + 'fax' => $faker->phoneNumber, + 'url' => $faker->url(), + ]; + } +} From d5f7579e9f6924b916766dbc27526945a0d1fed5 Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 29 May 2025 16:08:01 +0100 Subject: [PATCH 8/9] Added columns to suppliers Signed-off-by: snipe --- resources/views/suppliers/index.blade.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/resources/views/suppliers/index.blade.php b/resources/views/suppliers/index.blade.php index d0b911bf1a..f35ad983d8 100755 --- a/resources/views/suppliers/index.blade.php +++ b/resources/views/suppliers/index.blade.php @@ -54,6 +54,9 @@ {{ trans('admin/suppliers/table.licenses') }} {{ trans('general.components') }} {{ trans('general.consumables') }} + {{ trans('general.notes') }} + {{ trans('general.created_at') }} + {{ trans('general.created_by') }} {{ trans('table.actions') }} From 7bb29a02777fb015434ce443266f20c3295b7e0e Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 29 May 2025 16:08:17 +0100 Subject: [PATCH 9/9] Added sample import CSVs Signed-off-by: snipe --- sample_csvs/locations-sample.csv | 31 +++++++++++-------------------- sample_csvs/suppliers-sample.csv | 11 +++++++++++ 2 files changed, 22 insertions(+), 20 deletions(-) create mode 100644 sample_csvs/suppliers-sample.csv diff --git a/sample_csvs/locations-sample.csv b/sample_csvs/locations-sample.csv index 42285f2168..707e2830d5 100644 --- a/sample_csvs/locations-sample.csv +++ b/sample_csvs/locations-sample.csv @@ -1,20 +1,11 @@ -name,address,address2,city,state,country,zip,manager,manager username,currency -Peace River,8 Brentwood Court,,Birendranagar,AB,CA,T8S,Danika Mostyn,dmostyn0,CAD -Airdrie,14 Summer Ridge Court,306 Buhler Parkway,Poniatowa,AB,CA,T4B,Clementina Van Halen,cvan1,CAD -Calgary,3 Fieldstone Drive,,Iwanai,AB,CA,,Harwilll Heffernan,hheffernan2,CAD -High Prairie,1906 Weeping Birch Park,,Lopar,AB,CA,,Christian Pache,cpache3,CAD -Sundre,20 Summer Ridge Court,,Burujul,AB,CA,,,, -Athabasca,22 Browning Drive,424 Rieder Court,Itambacuri,AB,CA,,Alphonso Ashbridge,aashbridge5,CAD -Drayton Valley,56064 Onsgard Center,,Bahía Honda,AB,CA,,,, -Crossfield,0 Lighthouse Bay Place,,Bengras,AB,CA,,Vania Dufton,vdufton7,CAD -Beaverlodge,6 Katie Terrace,,Zhajin,AB,CA,,Papageno Baldi,pbaldi8,CAD -Grande Prairie,0 Ridgeview Parkway,,Yunxi,AB,CA,R3J,Selia Biggadike,sbiggadike9,CAD -Sherwood Park,263 Aberg Alley,,El Paso,AB,CA,,,, -Vegreville,9039 Shoshone Parkway,,Huazhou,AB,CA,,Georgy Eversfield,geversfieldb,CAD -Rocky Mountain House,8617 Arapahoe Parkway,,Paraipaba,AB,CA,,Mara Gilfoyle,mgilfoylec,CAD -Calmar,14 Green Ridge Circle,,Medveditskiy,AB,CA,S0G,Paulette Rylatt,prylattd,CAD -Rocky Mountain House,517 Bowman Terrace,,Viana,AB,CA,,Neal Gabitis,ngabitise,CAD -Pincher Creek,6054 Anzinger Hill,,Chlumec,AB,CA,,Bonnee Fowle,bfowlef,CAD -Airdrie,8 Lien Drive,,Reims,AB,CA,,Kerry Aherne,kaherneg,CAD -Camrose,4 Summit Parkway,,Xinqiao,AB,CA,T4V,Sherlock Stobbart,sstobbarth,CAD -Lamont,12 Ilene Park,,Huangtang,AB,CA,N2E,Karlotta Pinckstone,kpinckstonei,CAD +name,address,address2,city,state,country,zip,notes,phone,fax,currency +Shizi,811 Algoma Center,1690,Shimen,,CN,,ipsum ac tellus semper interdum mauris ullamcorper purus sit amet nulla quisque arcu libero rutrum ac lobortis vel dapibus,280-997-3795,673-737-7438,CNY +Takum,354 Sugar Way,88222,Old Shinyanga,,NG,,proin risus praesent lectus vestibulum quam sapien varius ut blandit non interdum in ante vestibulum ante,810-325-0609,746-868-1843,NGN +Unaizah,56243 Lawn Drive,14,Irecê,,SA,,in blandit ultrices enim lorem ipsum dolor sit amet consectetuer adipiscing elit proin interdum mauris,841-568-9664,419-246-9966,SAR +Pontarlier,80411 Lyons Alley,0,Colinas,Franche-Comté,FR,25304 CEDEX,enim in tempor turpis nec euismod scelerisque quam turpis adipiscing lorem vitae,927-638-2175,683-361-5521,EUR +Inongo,377 Nancy Lane,236,Placencia,,CD,,nam dui proin leo odio porttitor id consequat in consequat ut nulla sed accumsan felis ut at dolor quis,278-277-8326,744-879-3383,CDF +San Diego,294 Spohn Center,04,Yanmen,,CO,202038,quis orci eget orci vehicula condimentum curabitur in libero ut,255-785-7948,874-491-7898,COP +Lewotola,22308 Oriole Way,505,Celso Ramos,,ID,,nam nulla integer pede justo lacinia eget tincidunt eget tempus vel pede morbi porttitor lorem id ligula suspendisse ornare,431-503-0615,960-849-7404,IDR +Pieńsk,7 Maryland Junction,77656,Cela,,PL,59-930,ut blandit non interdum in ante vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae,723-739-7799,431-889-4342,PLN +Mataguži,5 Mayfield Drive,0,Zhaogezhuang,,ME,,nulla neque libero convallis eget eleifend luctus ultricies eu nibh quisque id justo sit amet sapien dignissim vestibulum vestibulum,356-728-4662,689-866-7531,EUR +Xixiang,2540 Rockefeller Place,2,Alegria,,CN,,vivamus metus arcu adipiscing molestie hendrerit at vulputate vitae nisl aenean lectus,388-760-0441,110-938-9032,CNY diff --git a/sample_csvs/suppliers-sample.csv b/sample_csvs/suppliers-sample.csv new file mode 100644 index 0000000000..4383a5f703 --- /dev/null +++ b/sample_csvs/suppliers-sample.csv @@ -0,0 +1,11 @@ +name,address,address2,city,state,country,zip,notes,contact,phone,fax +Mybuzz,1 Hoffman Circle,55,New York City,New York,US,10045,et tempus semper est quam pharetra magna ac consequat metus sapien,Debee Gouldstone,347-266-3178,995-892-7579 +Jabbersphere,0 Coolidge Circle,20357,Mapalad,,PH,3132,neque vestibulum eget vulputate ut ultrices vel augue vestibulum ante ipsum primis in faucibus orci luctus et ultrices,Malia Weatherdon,197-981-5379,488-325-1715 +Topicblab,88612 Fair Oaks Way,7989,Cogon,,PH,1686,aliquam convallis nunc proin at turpis a pede posuere nonummy integer,Wiley Brigdale,958-422-9615,899-962-6225 +Trupe,4861 Sheridan Pass,8,San Pedro,,PH,4023,vulputate nonummy maecenas tincidunt lacus at velit vivamus vel nulla eget eros elementum pellentesque quisque porta,Tobin Madill,387-755-4972,784-700-7390 +Yotz,40370 Stang Road,8,Kairouan,,TN,,in tempus sit amet sem fusce consequat nulla nisl nunc nisl,Obadiah Sample,656-536-9835,682-787-3779 +Fatz,5 Scoville Court,75043,Krasiczyn,,PL,37-741,metus sapien ut nunc vestibulum ante ipsum primis in faucibus orci luctus et ultrices,Caprice Cadagan,985-361-5597,543-332-3487 +Mycat,66 Sugar Parkway,4946,Andalucía,,CO,763008,velit nec nisi vulputate nonummy maecenas tincidunt lacus at velit vivamus vel nulla eget eros,Jody Veasey,954-596-9805,404-452-3171 +Livefish,24 Artisan Street,0,Brest,Bretagne,FR,29213 CEDEX 1,suspendisse ornare consequat lectus in est risus auctor sed tristique in tempus sit amet sem,Eddie Decayette,102-873-3656,558-233-6215 +Roomm,292 Crest Line Drive,10,Gribanovskiy,,RU,397243,nonummy maecenas tincidunt lacus at velit vivamus vel nulla eget eros elementum pellentesque quisque porta volutpat,Cesare Fosten,247-353-7043,248-710-4887 +Yodel,29457 Eastlawn Crossing,019,Divnomorskoye,,RU,353490,turpis a pede posuere nonummy integer non velit donec diam neque,Delmer Milton,499-847-6224,868-912-6630