diff --git a/lib/WebGUI/Shop/Products.pm b/lib/WebGUI/Shop/Products.pm index 1f6d1d5ac..99aa045aa 100644 --- a/lib/WebGUI/Shop/Products.pm +++ b/lib/WebGUI/Shop/Products.pm @@ -70,7 +70,6 @@ quantity =back - The following lines will contain product information. Blank lines and anything following a '#' sign will be ignored from the second line of the file, on to the end. @@ -96,7 +95,7 @@ sub importProducts { chomp $headers; my @headers = WebGUI::Text::splitCSV($headers); WebGUI::Error::InvalidFile->throw(error => qq{Bad header found in the CSV file}, brokenFile => $filePath) - unless (join(q{-}, sort @headers) eq 'city-code-country-state-taxRate') + unless (join(q{-}, sort @headers) eq 'mastersku-price-quantity-shortdescription-sku-title-weight') and (scalar @headers == 5); my @productData = (); my $line = 1; diff --git a/t/Shop/Products.t b/t/Shop/Products.t index a2f186812..eb5837b73 100644 --- a/t/Shop/Products.t +++ b/t/Shop/Products.t @@ -32,7 +32,7 @@ my $session = WebGUI::Test->session; #---------------------------------------------------------------------------- # Tests -my $tests = 5; +my $tests = 14; plan tests => 1 + $tests; #---------------------------------------------------------------------------- @@ -41,23 +41,23 @@ plan tests => 1 + $tests; my $loaded = use_ok('WebGUI::Shop::Products'); my $storage; -my $e; +my ($e, $failure); SKIP: { skip 'Unable to load module WebGUI::Shop::Products', $tests unless $loaded; - + ####################################################################### # # import # ####################################################################### - + eval { WebGUI::Shop::Products::importProducts($session); }; $e = Exception::Class->caught(); isa_ok($e, 'WebGUI::Error::InvalidParam', 'importProducts: error handling for an undefined path to file'); is($e->error, 'Must provide the path to a file', 'importProducts: error handling for an undefined path to file'); - + eval { WebGUI::Shop::Products::importProducts($session, '/path/to/nowhere'); }; $e = Exception::Class->caught(); isa_ok($e, 'WebGUI::Error::InvalidFile', 'importProducts: error handling for file that does not exist in the filesystem'); @@ -69,7 +69,68 @@ SKIP: { ), 'importTaxData: error handling for file that does not exist in the filesystem', ); - + + my $productsFile = WebGUI::Test->getTestCollateralPath('productTables/goodProductTable.csv'); + + SKIP: { + skip 'Root will cause this test to fail since it does not obey file permissions', 3 + if $< == 0; + + my $originalChmod = (stat $productsFile)[2]; + chmod oct(0000), $productsFile; + + eval { WebGUI::Shop::Products::importProducts($session, $productsFile); }; + $e = Exception::Class->caught(); + isa_ok($e, 'WebGUI::Error::InvalidFile', 'importProducts: error handling for file that cannot be read'); + is($e->error, 'File is not readable', 'importProducts: error handling for file that that cannot be read'); + cmp_deeply( + $e, + methods( + brokenFile => $productsFile, + ), + 'importProducts: error handling for file that that cannot be read', + ); + + chmod $originalChmod, $productsFile; + + } + + eval { + $failure = WebGUI::Shop::Products::importProducts( + $session, + WebGUI::Test->getTestCollateralPath('productTables/missingHeaders.csv'), + ); + }; + ok (!$failure, 'Product data is not imported when headers are missing'); + $e = Exception::Class->caught(); + isa_ok($e, 'WebGUI::Error::InvalidFile', 'importProducts: a file with a missing header column'); + cmp_deeply( + $e, + methods( + error => 'Bad header found in the CSV file', + brokenFile => WebGUI::Test->getTestCollateralPath('productTables/missingHeaders.csv'), + ), + 'importProducts: error handling for a file with a missing header', + ); + + eval { + $failure = WebGUI::Shop::Products::importProducts( + $session, + WebGUI::Test->getTestCollateralPath('productTables/badHeaders.csv'), + ); + }; + ok (!$failure, 'Product data is not imported when the headers are wrong'); + $e = Exception::Class->caught(); + isa_ok($e, 'WebGUI::Error::InvalidFile', 'importProducts: a file with bad headers'); + cmp_deeply( + $e, + methods( + error => 'Bad header found in the CSV file', + brokenFile => WebGUI::Test->getTestCollateralPath('productTables/badHeaders.csv'), + ), + 'importProducts: error handling for a file with a missing header', + ); + } #---------------------------------------------------------------------------- diff --git a/t/Shop/Tax.t b/t/Shop/Tax.t index 9cde10dce..cca2d0968 100644 --- a/t/Shop/Tax.t +++ b/t/Shop/Tax.t @@ -49,47 +49,47 @@ my $storage; SKIP: { skip 'Unable to load module WebGUI::Shop::Tax', $tests unless $loaded; - + ####################################################################### # # new # ####################################################################### - + my $taxer = WebGUI::Shop::Tax->new($session); - + isa_ok($taxer, 'WebGUI::Shop::Tax'); - + isa_ok($taxer->session, 'WebGUI::Session', 'session method returns a session object'); - + is($session->getId, $taxer->session->getId, 'session method returns OUR session object'); - + ####################################################################### # # getItems # ####################################################################### - + my $taxIterator = $taxer->getItems; - + isa_ok($taxIterator, 'WebGUI::SQL::ResultSet'); - + is($taxIterator->rows, 0, 'WebGUI ships with no predefined tax data'); - + ####################################################################### # # add # ####################################################################### - + my $e; - + eval{$taxer->add()}; - + $e = Exception::Class->caught(); isa_ok($e, 'WebGUI::Error::InvalidParam', 'add: correct type of exception thrown for missing hashref'); is($e->error, 'Must pass in a hashref of params', 'add: correct message for a missing hashref'); - + foreach my $inputSet ( @{ $addExceptions } ){ eval{$taxer->add($inputSet->{args})}; $e = Exception::Class->caught(); @@ -103,27 +103,27 @@ SKIP: { 'add: '.$inputSet->{comment}, ); } - + my $taxData = { country => 'USA', state => 'OR', taxRate => '0', }; - + my $oregonTaxId = $taxer->add($taxData); - + ok($session->id->valid($oregonTaxId), 'add method returns a valid GUID'); - + $taxIterator = $taxer->getItems; is($taxIterator->rows, 1, 'add added only 1 row to the tax table'); - + my $addedData = $taxIterator->hashRef; $taxData->{taxId} = $oregonTaxId; $taxData->{city} = undef; $taxData->{code} = undef; - + cmp_deeply($addedData, $taxData, 'add put the right data into the database for Oregon'); - + $taxData = { country => 'USA', state => 'Wisconsin', @@ -131,34 +131,34 @@ SKIP: { code => '53702', taxRate => '5', }; - + my $wisconsinTaxId = $taxer->add($taxData); - + $taxIterator = $taxer->getItems; is($taxIterator->rows, 2, 'add added another row to the tax table'); - + $taxData = { country => 'USA', state => 'Oregon', taxRate => '0.1', }; - + my $dupId = $taxer->add($taxData); - + $taxIterator = $taxer->getItems; is($taxIterator->rows, 3, 'add permits adding duplicate information.'); - + ##Madison zip codes: ##53701-53709 ##city rate: 0.5% ##Wisconsin rate 5.0% - + ####################################################################### # # getAllItems # ####################################################################### - + my $expectedTaxData = [ { country => 'USA', @@ -182,54 +182,54 @@ SKIP: { taxRate => 0.1, }, ]; - + cmp_bag( $taxer->getAllItems, $expectedTaxData, 'getAllItems returns the whole set of tax data', ); - + ####################################################################### # # delete # ####################################################################### - + eval{$taxer->delete()}; $e = Exception::Class->caught(); isa_ok($e, 'WebGUI::Error::InvalidParam', 'delete: error handling for missing hashref'); is($e->error, 'Must pass in a hashref of params', 'delete: error message for missing hashref'); - + eval{$taxer->delete({})}; $e = Exception::Class->caught(); isa_ok($e, 'WebGUI::Error::InvalidParam', 'delete: error handling for missing key in hashref'); is($e->error, 'Hash ref must contain a taxId key with a defined value', 'delete: error message for missing key in hashref'); - + eval{$taxer->delete({ taxId => undef })}; $e = Exception::Class->caught(); isa_ok($e, 'WebGUI::Error::InvalidParam', 'delete: error handling for an undefined taxId value'); is($e->error, 'Hash ref must contain a taxId key with a defined value', 'delete: error message for an undefined taxId value'); - + $taxer->delete({ taxId => $dupId }); $taxIterator = $taxer->getItems; is($taxIterator->rows, 2, 'One row was deleted from the tax table, even though another row has duplicate information'); - + $taxer->delete({ taxId => $oregonTaxId }); $taxIterator = $taxer->getItems; is($taxIterator->rows, 1, 'Another row was deleted from the tax table'); - + $taxer->delete({ taxId => $session->id->generate }); - + $taxIterator = $taxer->getItems; is($taxIterator->rows, 1, 'No rows were deleted from the table since the requested id does not exist'); is($taxIterator->hashRef->{taxId}, $wisconsinTaxId, 'The correct tax information was deleted'); - + ######################################################################## ## ## exportTaxData ## ######################################################################## - + $storage = $taxer->exportTaxData(); isa_ok($storage, 'WebGUI::Storage', 'exportTaxData returns a WebGUI::Storage object'); is($storage->{_part1}, 'temp', 'The storage object is in the temporary area'); @@ -244,7 +244,7 @@ SKIP: { my $wiData = $taxer->getItems->hashRef; ##Need to ignore the taxId from the database cmp_bag([ @{ $wiData }{ @expectedHeader } ], \@row1, 'exportTaxData: first line of data is correct'); - + my $newTaxId = $taxer->add({ country => 'USA|U.S.A.', state => 'washington|WA', @@ -259,20 +259,20 @@ SKIP: { my $wiData = $taxer->getItems->hashRef; ##Need to ignore the taxId from the database cmp_bag([ @{ $wiData }{ @expectedHeader } ], \@row1, 'exportTaxData: first line of data is correct'); - + $taxer->delete({taxId => $newTaxId}); - + ####################################################################### # # import # ####################################################################### - + eval { $taxer->importTaxData(); }; $e = Exception::Class->caught(); isa_ok($e, 'WebGUI::Error::InvalidParam', 'importTaxData: error handling for an undefined taxId value'); is($e->error, 'Must provide the path to a file', 'importTaxData: error handling for an undefined taxId value'); - + eval { $taxer->importTaxData('/path/to/nowhere'); }; $e = Exception::Class->caught(); isa_ok($e, 'WebGUI::Error::InvalidFile', 'importTaxData: error handling for file that does not exist in the filesystem'); @@ -284,16 +284,16 @@ SKIP: { ), 'importTaxData: error handling for file that does not exist in the filesystem', ); - + my $taxFile = WebGUI::Test->getTestCollateralPath('taxTables/goodTaxTable.csv'); - + SKIP: { skip 'Root will cause this test to fail since it does not obey file permissions', 3 if $< == 0; - + my $originalChmod = (stat $taxFile)[2]; chmod oct(0000), $taxFile; - + eval { $taxer->importTaxData($taxFile); }; $e = Exception::Class->caught(); isa_ok($e, 'WebGUI::Error::InvalidFile', 'importTaxData: error handling for file that cannot be read'); @@ -305,11 +305,11 @@ SKIP: { ), 'importTaxData: error handling for file that that cannot be read', ); - + chmod $originalChmod, $taxFile; - + } - + my $expectedTaxData = [ { country => 'USA', @@ -333,14 +333,14 @@ SKIP: { taxRate => 0.5, }, ]; - + ok( $taxer->importTaxData( $taxFile ), 'Good tax data inserted', ); - + $taxIterator = $taxer->getItems; is($taxIterator->rows, 3, 'import: Old data deleted, new data imported'); cmp_bag( @@ -348,14 +348,14 @@ SKIP: { $expectedTaxData, 'Correct data inserted.', ); - + ok( $taxer->importTaxData( WebGUI::Test->getTestCollateralPath('taxTables/orderedTaxTable.csv') ), 'Reordered tax data inserted', ); - + $taxIterator = $taxer->getItems; is($taxIterator->rows, 3, 'import: Old data deleted, new data imported again'); cmp_bag( @@ -363,14 +363,14 @@ SKIP: { $expectedTaxData, 'Correct data inserted, with CSV in different columnar order.', ); - + ok( $taxer->importTaxData( WebGUI::Test->getTestCollateralPath('taxTables/commentedTaxTable.csv') ), 'Commented tax data inserted', ); - + $taxIterator = $taxer->getItems; is($taxIterator->rows, 3, 'import: Old data deleted, new data imported the third time'); cmp_bag( @@ -378,17 +378,17 @@ SKIP: { $expectedTaxData, 'Correct data inserted, with comments in the CSV file', ); - + ok( ! $taxer->importTaxData( WebGUI::Test->getTestCollateralPath('taxTables/emptyTaxTable.csv') ), 'Empty tax data not inserted', ); - + $taxIterator = $taxer->getItems; is($taxIterator->rows, 3, 'import: Old data still exists and was not deleted'); - + my $failure; eval { $failure = $taxer->importTaxData( @@ -407,7 +407,7 @@ SKIP: { ), 'importTaxData: error handling for file with errors in the CSV data', ); - + eval { $failure = $taxer->importTaxData( WebGUI::Test->getTestCollateralPath('taxTables/missingHeaders.csv') @@ -424,7 +424,7 @@ SKIP: { ), 'importTaxData: error handling for a file with a missing header', ); - + eval { $failure = $taxer->importTaxData( WebGUI::Test->getTestCollateralPath('taxTables/badHeaders.csv') @@ -441,14 +441,14 @@ SKIP: { ), 'importTaxData: error handling for a file with a bad header', ); - + ok( $taxer->importTaxData( WebGUI::Test->getTestCollateralPath('taxTables/alternations.csv') ), 'Tax data with alternations inserted', ); - + my $altData = $taxer->getItems->hashRef; ##Just 1 row cmp_deeply( $altData, @@ -462,13 +462,13 @@ SKIP: { }, 'import: Data correctly loaded with alternations' ); - + ####################################################################### # # getTaxRates # ####################################################################### - + ##Set up the tax information $taxer->importTaxData( WebGUI::Test->getTestCollateralPath('taxTables/largeTaxTable.csv') @@ -495,7 +495,7 @@ SKIP: { code => '92801', country => 'USA', }); - + eval { $taxer->getTaxRates(); }; $e = Exception::Class->caught(); isa_ok($e, 'WebGUI::Error::InvalidObject', 'calculate: error handling for not sending a cart'); @@ -508,74 +508,74 @@ SKIP: { ), 'importTaxData: error handling for file that does not exist in the filesystem', ); - + cmp_deeply( $taxer->getTaxRates($taxingAddress), [0, 5, 0.5], 'getTaxRates: return correct data for a state with tax data' ); - + cmp_deeply( $taxer->getTaxRates($taxFreeAddress), [0,0], 'getTaxRates: return correct data for a state with no tax data' ); - + cmp_deeply( $taxer->getTaxRates($alternateAddress), [0.0, 8.25], #Hits USA and Los Angeles, California using the alternate spelling of the state 'getTaxRates: return correct data for a state when the address has alternations' ); - + ####################################################################### # # calculate # ####################################################################### - + eval { $taxer->calculate(); }; $e = Exception::Class->caught(); isa_ok($e, 'WebGUI::Error::InvalidParam', 'calculate: error handling for not sending a cart'); is($e->error, 'Must pass in a WebGUI::Shop::Cart object', 'calculate: error handling for not sending a cart'); - + ##Build a cart, add some Donation SKUs to it. Set one to be taxable. - + my $cart = WebGUI::Shop::Cart->newBySession($session); - + is($taxer->calculate($cart), 0, 'calculate returns 0 if there is no shippingAddressId in the cart'); - + $cart->update({ shippingAddressId => $taxingAddress->getId}); - + ##Set up the tax information $taxer->importTaxData( WebGUI::Test->getTestCollateralPath('taxTables/largeTaxTable.csv') ), - + my $taxableDonation = WebGUI::Asset->getRoot($session)->addChild({ className => 'WebGUI::Asset::Sku::Donation', title => 'Taxable donation', defaultPrice => 100.00, }); - + $cart->addItem($taxableDonation); - + foreach my $item (@{ $cart->getItems }) { $item->setQuantity(1); } - + my $tax = $taxer->calculate($cart); is($tax, 5.5, 'calculate: simple tax calculation on 1 item in the cart'); - + $cart->update({ shippingAddressId => $taxFreeAddress->getId}); is($taxer->calculate($cart), 0, 'calculate: simple tax calculation on 1 item in the cart, tax free location'); - + foreach my $item (@{ $cart->getItems }) { $item->setQuantity(2); } - + $cart->update({ shippingAddressId => $taxingAddress->getId}); is($taxer->calculate($cart), 11, 'calculate: simple tax calculation on 1 item in the cart, qty 2'); - + my $taxFreeDonation = WebGUI::Asset->getRoot($session)->addChild({ className => 'WebGUI::Asset::Sku::Donation', title => 'Tax Free Donation', @@ -583,28 +583,28 @@ SKIP: { overrideTaxRate => 1, taxRateOverride => 0, }); - + $cart->addItem($taxFreeDonation); - + foreach my $item (@{ $cart->getItems }) { $item->setQuantity(1); } is($taxer->calculate($cart), 5.5, 'calculate: simple tax calculation on 2 items in the cart, 1 without taxes'); - + my $remoteItem = $cart->addItem($taxableDonation); $remoteItem->update({shippingAddressId => $taxFreeAddress->getId}); - + foreach my $item (@{ $cart->getItems }) { $item->setQuantity(1); } is($taxer->calculate($cart), 5.5, 'calculate: simple tax calculation on 2 items in the cart, 1 without taxes, 1 shipped to a location with no taxes'); - + ####################################################################### # # www_getTaxesAsJson # ####################################################################### - + $session->user({userId=>3}); my $json = $taxer->www_getTaxesAsJson(); ok($json, 'www_getTaxesAsJson returned something'); @@ -628,7 +628,7 @@ SKIP: { }, 'Check major elements of tax JSON', ); - + TODO: { local $TODO = 'More getTaxesAsJson tests'; ok(0, 'test group privileges to this method'); @@ -636,7 +636,7 @@ SKIP: { ok(0, 'test results form variable'); ok(0, 'test keywords'); } - + $cart->delete; $book->delete; $taxableDonation->purge; diff --git a/t/supporting_collateral/productTables/badHeaders.csv b/t/supporting_collateral/productTables/badHeaders.csv new file mode 100644 index 000000000..57aaf1054 --- /dev/null +++ b/t/supporting_collateral/productTables/badHeaders.csv @@ -0,0 +1,4 @@ +mastersku,skew,title,shortdescription,price,weight,quantity +t-shirt,red-t-shirt,Red T-Shirt,Red T-Shirt,5.00,1.33,1000 +t-shirt,blue-t-shirt,Blue T-Shirt,Blue T-Shirt,5.25,1.33,2000 +soda,soda-sweet,Sweet Soda-bottled in Oregon,Sweet Soda,0.95,0.95,500 diff --git a/t/supporting_collateral/productTables/goodProductTable.csv b/t/supporting_collateral/productTables/goodProductTable.csv new file mode 100644 index 000000000..407252bfe --- /dev/null +++ b/t/supporting_collateral/productTables/goodProductTable.csv @@ -0,0 +1,4 @@ +mastersku,sku,title,shortdescription,price,weight,quantity +t-shirt,red-t-shirt,Red T-Shirt,Red T-Shirt,5.00,1.33,1000 +t-shirt,blue-t-shirt,Blue T-Shirt,Blue T-Shirt,5.25,1.33,2000 +soda,soda-sweet,Sweet Soda-bottled in Oregon,Sweet Soda,0.95,0.95,500 diff --git a/t/supporting_collateral/productTables/missingHeaders.csv b/t/supporting_collateral/productTables/missingHeaders.csv new file mode 100644 index 000000000..2c50e2165 --- /dev/null +++ b/t/supporting_collateral/productTables/missingHeaders.csv @@ -0,0 +1,3 @@ +t-shirt,red-t-shirt,Red T-Shirt,Red T-Shirt,5.00,1.33,1000 +t-shirt,blue-t-shirt,Blue T-Shirt,Blue T-Shirt,5.25,1.33,2000 +soda,soda-sweet,Sweet Soda-bottled in Oregon,Sweet Soda,0.95,0.95,500