From bee1dfc4a68f3facf703b9966fccd0e6657cda61 Mon Sep 17 00:00:00 2001 From: Daniel Meltzer Date: Fri, 24 Nov 2017 13:42:11 -0500 Subject: [PATCH] More importer fixes (#4516) * The default locale of en does not include dollar sign in default currency. Assume if there is no currency symbol set that the dollar sign is a good thing to look for in parsefloat. * Fix for 4485. Serial not serial_number Also fix bug where updating with a csv that does not include custom field columns should not overwrite current values. * Rename serial_number to serial in default imports to avoid needing to map weirdly. * Add Test for 4359. Not reproducable at current though --- app/Helpers/Helper.php | 8 +++- app/Importer/AssetImporter.php | 9 +++- app/Importer/ConsumableImporter.php | 1 + app/Importer/ItemImporter.php | 3 +- app/Models/SnipeModel.php | 1 + sample_csvs/MOCK_ASSETS.csv | 2 +- tests/unit/ImporterTest.php | 71 +++++++++++++++++++++++++---- 7 files changed, 81 insertions(+), 14 deletions(-) diff --git a/app/Helpers/Helper.php b/app/Helpers/Helper.php index 1e0a2b7ede..429fd7bf32 100644 --- a/app/Helpers/Helper.php +++ b/app/Helpers/Helper.php @@ -127,7 +127,13 @@ class Helper $floatString = str_replace(",", "", $floatString); $floatString = str_replace($LocaleInfo["decimal_point"], ".", $floatString); // Strip Currency symbol - $floatString = str_replace($LocaleInfo['currency_symbol'], '', $floatString); + // If no currency symbol is set, default to $ because Murica + $currencySymbol = $LocaleInfo['currency_symbol']; + if (empty($currencySymbol)) { + $currencySymbol = '$'; + } + + $floatString = str_replace($currencySymbol, '', $floatString); return floatval($floatString); } diff --git a/app/Importer/AssetImporter.php b/app/Importer/AssetImporter.php index e2987ed2e0..511957290c 100644 --- a/app/Importer/AssetImporter.php +++ b/app/Importer/AssetImporter.php @@ -31,7 +31,9 @@ class AssetImporter extends ItemImporter $this->item['custom_fields'][$customField->db_column_name()] = $customFieldValue; $this->log('Custom Field '. $customField->name.': '.$customFieldValue); } else { - $this->item['custom_fields'][$customField->db_column_name()] = ''; + // This removes custom fields when updating if the column doesn't exist in file. + // Commented out becausee not sure if it's needed anywhere. + // $this->item['custom_fields'][$customField->db_column_name()] = ''; } } } @@ -77,17 +79,20 @@ class AssetImporter extends ItemImporter } $this->item['asset_tag'] = $asset_tag; - // By default we're set this to location_id in the item. $item = $this->sanitizeItemForStoring($asset, $editingAsset); + // By default we're set this to location_id in the item. if (isset($this->item["location_id"])) { $item['rtd_location_id'] = $this->item['location_id']; unset($item['location_id']); } + if ($editingAsset) { $asset->update($item); } else { $asset->fill($item); } + // If we're updating, we don't want to overwrite old fields. + if (array_key_exists('custom_fields', $this->item)) { foreach ($this->item['custom_fields'] as $custom_field => $val) { $asset->{$custom_field} = $val; diff --git a/app/Importer/ConsumableImporter.php b/app/Importer/ConsumableImporter.php index c54b935539..07d3b28b28 100644 --- a/app/Importer/ConsumableImporter.php +++ b/app/Importer/ConsumableImporter.php @@ -40,6 +40,7 @@ class ConsumableImporter extends ItemImporter $this->log("No matching consumable, creating one"); $consumable = new Consumable(); $consumable->fill($this->sanitizeItemForStoring($consumable)); + if ($consumable->save()) { $consumable->logCreate('Imported using CSV Importer'); $this->log("Consumable " . $this->item["name"] . ' was created'); diff --git a/app/Importer/ItemImporter.php b/app/Importer/ItemImporter.php index 4cc85545fb..c43edae106 100644 --- a/app/Importer/ItemImporter.php +++ b/app/Importer/ItemImporter.php @@ -63,7 +63,7 @@ class ItemImporter extends Importer $this->item["qty"] = $this->findCsvMatch($row, "quantity"); $this->item["requestable"] = $this->findCsvMatch($row, "requestable"); $this->item["user_id"] = $this->user_id; - $this->item['serial'] = $this->findCsvMatch($row, "serial_number"); + $this->item['serial'] = $this->findCsvMatch($row, "serial"); // NO need to call this method if we're running the user import. // TODO: Merge these methods. if(get_class($this) !== UserImporter::class) { @@ -92,6 +92,7 @@ class ItemImporter extends Importer $item = collect($this->item); // First Filter the item down to the model's fillable fields $item = $item->only($model->getFillable()); + // Then iterate through the item and, if we are updating, remove any blank values. if ($updating) { $item = $item->reject(function ($value) { diff --git a/app/Models/SnipeModel.php b/app/Models/SnipeModel.php index e650cb6624..c20b56c8a9 100644 --- a/app/Models/SnipeModel.php +++ b/app/Models/SnipeModel.php @@ -24,6 +24,7 @@ class SnipeModel extends Model public function setPurchaseCostAttribute($value) { $value = Helper::ParseFloat($value); + if ($value == '0.0') { $value = null; } diff --git a/sample_csvs/MOCK_ASSETS.csv b/sample_csvs/MOCK_ASSETS.csv index eafbb5b804..7528a89b83 100644 --- a/sample_csvs/MOCK_ASSETS.csv +++ b/sample_csvs/MOCK_ASSETS.csv @@ -1,4 +1,4 @@ -Name,Email,Username,item Name,Category,Model name,Manufacturer,Model Number,Serial number,Asset Tag,Location,Notes,Purchase Date,Purchase Cost,Company,Status,Warranty,Supplier +Name,Email,Username,item Name,Category,Model name,Manufacturer,Model Number,Serial,Asset Tag,Location,Notes,Purchase Date,Purchase Cost,Company,Status,Warranty,Supplier Bonnie Nelson,bnelson0@cdbaby.com,bnelson0,eget nunc donec quis,quam,massa id,Linkbridge,6377018600094472,27aa8378-b0f4-4289-84a4-405da95c6147,970882174-8,Daping,"Curabitur in libero ut massa volutpat convallis. Morbi odio odio, elementum eu, interdum eu, tincidunt in, leo. Maecenas pulvinar lobortis est.",2016-04-05,133289.59,Alpha,Undeployable,14,Blogspan Judith Ferguson,jferguson1@state.tx.us,jferguson1,mi in porttitor,justo,congue diam id,Flipstorm,5.02043359569189E+018,4bc7fc90-5a97-412f-8eed-77ecacc643fc,544574073-0,Cirangga Kidul,,2016-03-08,763.46,,Undeployable,12,Oyope Mildred Gibson,mgibson2@wiley.com,mgibson2,morbi quis tortor id,nunc nisl duis,convallis tortor risus,Lajo,374622546776765,2837ab20-8f0d-4935-8a52-226392f2b1b0,710141467-2,Shekou,In congue. Etiam justo. Etiam pretium iaculis justo.,2015-08-09,233.57,Konklab,Lost,, diff --git a/tests/unit/ImporterTest.php b/tests/unit/ImporterTest.php index 7cd206b799..206605d1d2 100644 --- a/tests/unit/ImporterTest.php +++ b/tests/unit/ImporterTest.php @@ -24,7 +24,7 @@ class ImporterTest extends BaseTest public function testDefaultImportAssetWithCustomFields() { $csv = <<<'EOT' -Name,Email,Username,item Name,Category,Model name,Manufacturer,Model Number,Serial number,Asset Tag,Location,Notes,Purchase Date,Purchase Cost,Company,Status,Warranty,Supplier,Weight +Name,Email,Username,item Name,Category,Model name,Manufacturer,Model Number,Serial,Asset Tag,Location,Notes,Purchase Date,Purchase Cost,Company,Status,Warranty,Supplier,Weight Bonnie Nelson,bnelson0@cdbaby.com,bnelson0,eget nunc donec quis,quam,massa id,Linkbridge,6377018600094472,27aa8378-b0f4-4289-84a4-405da95c6147,970882174-8,Daping,"Curabitur in libero ut massa volutpat convallis. Morbi odio odio, elementum eu, interdum eu, tincidunt in, leo. Maecenas pulvinar lobortis est.",2016-04-05,133289.59,Alpha,Undeployable,14,Blogspan,35 EOT; @@ -64,6 +64,7 @@ EOT; $this->tester->seeRecord('suppliers', [ 'name' => 'Blogspan' ]); + $this->tester->seeRecord('assets', [ 'name' => 'eget nunc donec quis', 'serial' => '27aa8378-b0f4-4289-84a4-405da95c6147', @@ -79,14 +80,14 @@ EOT; public function testUpdateAssetIncludingCustomFields() { $csv = <<<'EOT' -Name,Email,Username,item Name,Category,Model name,Manufacturer,Model Number,Serial number,Asset Tag,Location,Notes,Purchase Date,Purchase Cost,Company,Status,Warranty,Supplier,weight +Name,Email,Username,item Name,Category,Model name,Manufacturer,Model Number,Serial,Asset Tag,Location,Notes,Purchase Date,Purchase Cost,Company,Status,Warranty,Supplier,weight Bonnie Nelson,bnelson0@cdbaby.com,bnelson0,eget nunc donec quis,quam,massa id,Linkbridge,6377018600094472,27aa8378-b0f4-4289-84a4-405da95c6147,970882174-8,Daping,"Curabitur in libero ut massa volutpat convallis. Morbi odio odio, elementum eu, interdum eu, tincidunt in, leo. Maecenas pulvinar lobortis est.",2016-04-05,133289.59,Alpha,Undeployable,14,Blogspan,95 EOT; $this->initializeCustomFields(); $this->import(new AssetImporter($csv)); $updatedCSV = <<<'EOT' -item Name,Category,Model name,Manufacturer,Model Number,Serial number,Asset Tag,Location,Notes,Purchase Date,Purchase Cost,Company,Status,Warranty,Supplier +item Name,Category,Model name,Manufacturer,Model Number,Serial,Asset Tag,Location,Notes,Purchase Date,Purchase Cost,Company,Status,Warranty,Supplier A new name,some other category,Another Model,Linkbridge 32,356,67433477,970882174-8,New Location,I have no notes,2018-04-05,25.59,Another Company,Ready To Go,18,Not Creative EOT; $importer = new AssetImporter($updatedCSV); @@ -136,6 +137,58 @@ EOT; ]); } + public function testAssetModelNumber4359() + { + // As per bug #4359 + // 1) Create model with blank model # and custom field. + // 2 ) Update custom fields with a csv not including model # + // 3 ) Not updated. NULL vs. empty issue. + $csv = <<<'EOT' +Name,Email,Username,item Name,Category,Model name,Manufacturer,Serial,Asset Tag,Location,Notes,Purchase Date,Purchase Cost,Company,Status,Warranty,Supplier +Bonnie Nelson,bnelson0@cdbaby.com,bnelson0,eget nunc donec quis,quam,massa id,Linkbridge,27aa8378-b0f4-4289-84a4-405da95c6147,970882174-8,Daping,"Curabitur in libero ut massa volutpat convallis. Morbi odio odio, elementum eu, interdum eu, tincidunt in, leo. Maecenas pulvinar lobortis est.",2016-04-05,133289.59,Alpha,Undeployable,14,Blogspan +EOT; + + // Need to do this manually... + $customField = factory(App\Models\CustomField::class)->create(['name' => 'Weight']); + $customFieldSet = factory(App\Models\CustomFieldset::class)->create(['name' => 'Default']); + $customFieldSet->fields()->attach($customField, [ + 'required' => false, + 'order' => 'asc']); + + factory(App\Models\Category::class)->states('asset-laptop-category')->create([ + 'name' => 'quam' + ]); + + factory(App\Models\Manufacturer::class)->states('apple')->create([ + 'name' => 'Linkbridge' + ]); + + + $am = factory(App\Models\AssetModel::class)->create([ + 'name' => 'massa id', + 'fieldset_id' => $customFieldSet->id, + 'category_id' => 1, + 'manufacturer_id' => 1, + 'model_number' => null + ]); + + $this->import(new AssetImporter($csv)); + $updatedCSV = <<<'EOT' +Serial,Asset Tag,weight +67433477,970882174-8,115 +EOT; + $importer = new AssetImporter($updatedCSV); + $importer->setUserId(1) + ->setUpdating(true) + ->setUsernameFormat('firstname.lastname') + ->import(); + + $this->tester->seeRecord('assets', [ + 'asset_tag' => '970882174-8', + '_snipeit_weight_2' => 115 + ]); + } + public function initializeCustomFields() { $customField = factory(App\Models\CustomField::class)->create(['name' => 'Weight']); @@ -153,7 +206,7 @@ EOT; public function testCustomMappingImport() { $csv = <<<'EOT' -Name,Email,Username,object name,Cat,Model name,Manufacturer,Model Number,Serial number,Asset,Loc,Some Notes,Purchase Date,Purchase Cost,comp,Status,Warranty,Supplier +Name,Email,Username,object name,Cat,Model name,Manufacturer,Model Number,Serial,Asset,Loc,Some Notes,Purchase Date,Purchase Cost,comp,Status,Warranty,Supplier Bonnie Nelson,bnelson0@cdbaby.com,bnelson0,eget nunc donec quis,quam,massa id,Linkbridge,6377018600094472,27aa8378-b0f4-4289-84a4-405da95c6147,970882174-8,Daping,"Curabitur in libero ut massa volutpat convallis. Morbi odio odio, elementum eu, interdum eu, tincidunt in, leo. Maecenas pulvinar lobortis est.",2016-04-05,133289.59,Alpha,Undeployable,14,Blogspan EOT; @@ -331,7 +384,7 @@ Item Name,Purchase Date,Purchase Cost,Location,Company,Order Number,Category,Req eget,01/03/2011,$85.91,mauris blandit mattis.,Lycos,T295T06V,Triamterene/Hydrochlorothiazide,No,322 EOT; $this->import(new ConsumableImporter($csv)); - // dd($this->tester->grabRecord('consumables')); + $this->tester->seeRecord('consumables', [ 'name' => 'eget', 'purchase_date' => '2011-01-03 00:00:01', @@ -429,7 +482,7 @@ EOT; public function testDefaultLicenseImport() { $csv = <<<'EOT' -Name,Email,Username,Item name,serial number,manufacturer,purchase date,purchase cost,purchase order,order number,Licensed To Name,Licensed to Email,expiration date,maintained,reassignable,seats,company,supplier,notes +Name,Email,Username,Item name,serial,manufacturer,purchase date,purchase cost,purchase order,order number,Licensed To Name,Licensed to Email,expiration date,maintained,reassignable,seats,company,supplier,notes Helen Anderson,cspencer0@privacy.gov.au,cspencer0,Argentum Malachite Athletes Foot Relief,1aa5b0eb-79c5-40b2-8943-5472a6893c3c,"Beer, Leannon and Lubowitz",07/13/2012,$79.66,53008,386436062-5,Cynthia Spencer,cspencer0@gov.uk,01/27/2016,false,no,80,"Haag, Schmidt and Farrell","Hegmann, Mohr and Cremin",Sed ante. Vivamus tortor. Duis mattis egestas metus. EOT; $this->import(new LicenseImporter($csv)); @@ -469,7 +522,7 @@ EOT; public function testDefaultLicenseUpdate() { $csv = <<<'EOT' -Name,Email,Username,Item name,serial number,manufacturer,purchase date,purchase cost,purchase order,order number,Licensed To Name,Licensed to Email,expiration date,maintained,reassignable,seats,company,supplier,notes +Name,Email,Username,Item name,serial,manufacturer,purchase date,purchase cost,purchase order,order number,Licensed To Name,Licensed to Email,expiration date,maintained,reassignable,seats,company,supplier,notes Helen Anderson,cspencer0@privacy.gov.au,cspencer0,Argentum Malachite Athletes Foot Relief,1aa5b0eb-79c5-40b2-8943-5472a6893c3c,"Beer, Leannon and Lubowitz",07/13/2012,$79.66,53008,386436062-5,Cynthia Spencer,cspencer0@gov.uk,01/27/2016,false,no,80,"Haag, Schmidt and Farrell","Hegmann, Mohr and Cremin",Sed ante. Vivamus tortor. Duis mattis egestas metus. EOT; $this->import(new LicenseImporter($csv)); @@ -477,7 +530,7 @@ EOT; $updatedCSV = <<<'EOT' -Item name,serial number,manufacturer,purchase date,purchase cost,purchase order,order number,Licensed To Name,Licensed to Email,expiration date,maintained,reassignable,seats,company,supplier,notes +Item name,serial,manufacturer,purchase date,purchase cost,purchase order,order number,Licensed To Name,Licensed to Email,expiration date,maintained,reassignable,seats,company,supplier,notes Argentum Malachite Athletes Foot Relief,1aa5b0eb-79c5-40b2-8943-5472a6893c3c,"Beer, Leannon and Lubowitz",05/15/2019,$1865.34,63 ar,18334,A Legend,Legendary@gov.uk,04/27/2016,yes,true,64,"Haag, Schmidt and Farrell","Hegmann, Mohr and Cremin",Sed ante. Vivamus tortor. Duis mattis egestas metus. EOT; $importer = new LicenseImporter($updatedCSV); @@ -531,7 +584,7 @@ EOT; 'reassignable' => 'reass', 'requestable' => 'Request', 'seats' => 'seat', - 'serial_number' => 'serial num', + 'serial' => 'serial num', ]; $this->import(new LicenseImporter($csv), $customFieldMap); // dd($this->tester->grabRecord('licenses'));