Ready for 7.10.29 development.

This commit is contained in:
Colin Kuskie 2013-03-20 21:38:23 -07:00
commit c806f99b7b
4236 changed files with 1217679 additions and 0 deletions

577
t/Shop/TaxDriver/EU.t Normal file
View file

@ -0,0 +1,577 @@
# vim:syntax=perl
#-------------------------------------------------------------------
# WebGUI is Copyright 2001-2009 Plain Black Corporation.
#-------------------------------------------------------------------
# Please read the legal notices (docs/legal.txt) and the license
# (docs/license.txt) that came with this distribution before using
# this software.
#------------------------------------------------------------------
# http://www.plainblack.com info@plainblack.com
#------------------------------------------------------------------
# Write a little about what this script tests.
#
#
use FindBin;
use strict;
use lib "$FindBin::Bin/../../lib";
use Test::More;
use Test::Deep;
use Test::MockObject::Extends;
use Exception::Class;
use Data::Dumper;
use WebGUI::Test; # Must use this before any other WebGUI modules
use WebGUI::Session;
use WebGUI::Text;
use WebGUI::Shop::Cart;
use WebGUI::Shop::AddressBook;
use WebGUI::Shop::TaxDriver::EU;
#----------------------------------------------------------------------------
# Init
my $session = WebGUI::Test->session;
# Test user
my $taxUser = WebGUI::User->new( $session, 'new' );
$taxUser->username( 'Tex Evasion' );
$session->user({userId => $taxUser->getId});
WebGUI::Test->addToCleanup($taxUser);
# Test VAT numbers
my $testVAT_NL = 'NL123456789B12';
my $testVAT_BE = 'BE0123456789';
my $noServiceVAT= 'NotGonnaWork';
my $invalidVAT = 'ByNoMeansAllowed';
my $visitorUser = WebGUI::User->new( $session, 1 );
my @EU_COUNTRIES = (
'Austria', 'Belgium', 'Bulgaria', 'Cyprus', 'Czech Republic',
'Germany', 'Denmark', 'Estonia', 'Greece', 'Spain', 'Finland',
'France', 'United Kingdom', 'Hungary', 'Ireland', 'Italy',
'Lithuania', 'Luxembourg', 'Latvia', 'Malta', 'Netherlands',
'Poland', 'Portugal', 'Romania', 'Sweden', 'Slovenia', 'Slovakia',
);
# Test SKU
my $sku = WebGUI::Asset->getRoot($session)->addChild( {
className => 'WebGUI::Asset::Sku::Donation',
title => 'Taxable donation',
defaultPrice => 100.00,
} );
WebGUI::Test->addToCleanup($sku);
my $book = WebGUI::Shop::AddressBook->create($session);
WebGUI::Test->addToCleanup($book);
# setup address in EU but not in residential country of merchant
my $beAddress = $book->addAddress({
label => 'BE',
city => 'Antwerpen',
country => 'Belgium',
});
# setup address in residential country of merchant
my $nlAddress = $book->addAddress({
label => 'NL',
city => 'Delft',
country => 'Netherlands',
});
# setup address outside EU
my $usAddress = $book->addAddress({
label => 'outside eu',
city => 'New Amsterdam',
country => 'US',
});
#----------------------------------------------------------------------------
# Tests
my $tests = 342;
plan tests => $tests;
#----------------------------------------------------------------------------
# put your tests here
#######################################################################
#
# new
#
#######################################################################
{
my $taxer = WebGUI::Shop::TaxDriver::EU->new($session);
isa_ok($taxer, 'WebGUI::Shop::TaxDriver::EU');
isa_ok($taxer->session, 'WebGUI::Session', 'session method returns a session object');
is($session->getId, $taxer->session->getId, 'session method returns OUR session object');
}
#######################################################################
#
# className
#
#######################################################################
{
my $taxer = WebGUI::Shop::TaxDriver::EU->new($session);
is( $taxer->className, 'WebGUI::Shop::TaxDriver::EU', 'className returns correct class name' );
}
#######################################################################
#
# getConfigurationScreen
#
#######################################################################
#### TODO: Figure out how to test this.
#######################################################################
#
# getCountryCode / getCOuntryName
#
#######################################################################
{
my $taxer = WebGUI::Shop::TaxDriver::EU->new($session);
is( $taxer->getCountryCode( 'Netherlands' ), 'NL', 'getCountryCode returns correct code for country inside EU.' );
is( $taxer->getCountryCode( 'United States' ), undef, 'getCountryCode returns undef for countries outside EU.' );
is( $taxer->getCountryName( 'NL' ), 'Netherlands', 'getCountryName returns correct name for country code within EU.' );
is( $taxer->getCountryName( 'US' ), undef, 'getCountryName returns undef for county codes outside EU.' );
}
#######################################################################
#
# updateVATNumber
#
#######################################################################
{
my $taxer = WebGUI::Shop::TaxDriver::EU->new($session);
$session->user( {userId=>$taxUser->userId} );
# Mock the Validation module
my $validator = Test::MockObject::Extends->new( Business::Tax::VAT::Validation->new );
local *Business::Tax::VAT::Validation::new;
$validator->fake_new( 'Business::Tax::VAT::Validation' );
eval { $taxer->updateVATNumber };
my $e = Exception::Class->caught();
isa_ok( $e, 'WebGUI::Error::InvalidParam', 'A VAT number is required' );
is( $e, 'A VAT number is required', 'updateVATNumber returns correct message for missing VAT number' );
eval { $taxer->updateVATNumber( $testVAT_NL, 'NotAUserObject' ) };
$e = Exception::Class->caught();
isa_ok( $e, 'WebGUI::Error::InvalidParam', 'Second argument must be a user object' );
is( $e, 'The second argument must be an instanciated WebGUI::User object', 'updateVATNumber returns correct message when user object is of wrong type' );
eval { $taxer->updateVATNumber( $testVAT_NL, $visitorUser ) };
$e = Exception::Class->caught();
isa_ok( $e, 'WebGUI::Error::InvalidParam', 'User may not be visitor' );
is( $e, 'Visitor cannot add VAT numbers', 'updateVATNumber returns correct message when user is visitor' );
for my $errorCode ( 0 .. 16 ) {
$validator->set_always( 'check', 0 );
$validator->set_always( 'get_last_error_code', $errorCode );
is(
$taxer->updateVATNumber( $invalidVAT, $taxUser ),
'INVALID',
"updateVATNumber returns INVALID for error $errorCode",
);
}
for my $errorCode ( 17 .. 255 ) {
$validator->set_always( 'check', 0 );
$validator->set_always( 'get_last_error_code', $errorCode );
is(
$taxer->updateVATNumber( $invalidVAT, $taxUser ),
'UNKNOWN',
"updateVATNumber returns UNKNOWN for error $errorCode",
);
}
$validator->set_always( 'check', 1 );
$validator->set_always( 'get_last_error_code', undef );
is(
$taxer->updateVATNumber( $testVAT_NL, $taxUser ),
'VALID',
"updateVATNumber returns VALID for valid numbers",
);
}
#######################################################################
#
# addVATNumber
#
#######################################################################
{
my $taxer = WebGUI::Shop::TaxDriver::EU->new($session);
my $response;
local *WebGUI::Shop::TaxDriver::EU::updateVATNumber = sub { return $response };
#----- invalid vat number
$response = 'INVALID';
is(
$taxer->addVATNumber( $invalidVAT, $taxUser ),
'The entered VAT number is invalid.',
'addVATNumber returns the correct error message for invalid numbers',
);
#----- service unavailable
$response = 'UNKNOWN';
like(
$taxer->addVATNumber( $noServiceVAT, $taxUser ),
qr{^Number validation is currently not available.},
'addVATNumber returns the correct message when VIES is unavailable',
);
my $workflows = WebGUI::Workflow::Instance->getAllInstances( $session );
my ($workflow) = grep { $_->get('parameters')->{ vatNumber } eq $noServiceVAT } @{ $workflows };
ok( defined $workflow , 'addVATNumber fires a recheck workflow when VIES is down' );
#----- valid number
$response = 'VALID';
ok(
!defined $taxer->addVATNumber( $testVAT_NL, $taxUser ),
'Valid VAT numbers return undef.',
);
}
#######################################################################
#
# recheckVATNumber
#
#######################################################################
{
my $taxer = WebGUI::Shop::TaxDriver::EU->new($session);
for my $response ( qw{ INVALID VALID UNKNOWN } ) {
local *WebGUI::Shop::TaxDriver::EU::updateVATNumber = sub { return $response };
is(
$taxer->recheckVATNumber( $invalidVAT, $taxUser ),
$response,
"recheckVATNumber returns correct value when updateVATNumber returns $response",
);
}
}
#######################################################################
#
# getVATNumbers / deleteVATNumber
#
#######################################################################
{
my $taxer = setupTestNumbers();
my $expectNL = {
userId => $taxUser->userId,
countryCode => 'NL',
vatNumber => $testVAT_NL,
viesValidated => 1,
viesErrorCode => undef,
approved => 0,
};
my $expectBE = {
userId => $taxUser->userId,
countryCode => 'BE',
vatNumber => $testVAT_BE,
approved => 0,
viesErrorCode => undef,
viesValidated => 1,
};
my $vatNumbers = $taxer->getVATNumbers( undef, $taxUser );
cmp_bag( $vatNumbers, [ $expectNL, $expectBE ], 'VAT Numbers are correctly returned by getVATNumbers' );
$vatNumbers = $taxer->getVATNumbers( 'BE', $taxUser );
cmp_bag( $vatNumbers, [ $expectBE ], 'getVATNumbers filters on country code when one is passed' );
$taxer->deleteVATNumber( $testVAT_BE, $taxUser );
$vatNumbers = $taxer->getVATNumbers( undef, $taxUser );
cmp_bag( $vatNumbers, [ $expectNL ], 'deleteVATNumber deletes number' );
$taxer->deleteVATNumber( $testVAT_NL, $taxUser );
}
#######################################################################
#
# addGroup / getGroupRate / deleteGroup
#
#######################################################################
{
my $taxer = setupTestNumbers();
eval { $taxer->addGroup };
my $e = Exception::Class->caught();
isa_ok( $e, 'WebGUI::Error::InvalidParam', 'addGroup requires a group name' );
is( $e, 'A group name is required', 'addGroup returns correct message for omitted group name' );
eval { $taxer->addGroup( 'Dummy' ) };
$e = Exception::Class->caught();
isa_ok( $e, 'WebGUI::Error::InvalidParam', 'addGroup requires a tax rate' );
is( $e, 'Group rate must be within 0 and 100', 'addGroup returns correct message on omitted tax rate' );
eval { $taxer->addGroup( 'Dummy', -1 ) };
$e = Exception::Class->caught();
isa_ok( $e, 'WebGUI::Error::InvalidParam', 'addGroup: tax rate cannot be < 0' );
is( $e, 'Group rate must be within 0 and 100', 'addGroup returns correct message on tax rate < 0' );
eval { $taxer->addGroup( 'Dummy', 101 ) };
$e = Exception::Class->caught();
isa_ok( $e, 'WebGUI::Error::InvalidParam', 'addGroup: tax rate cannot be > 100' );
is( $e, 'Group rate must be within 0 and 100', 'addGroup returns correct message on tax rate > 100' );
my $id0 = eval { $taxer->addGroup( 'Group0', 0 ) };
$e = Exception::Class->caught();
ok( !$e, 'addGroup: 0% is a valid group rate' );
my $id100 = eval { $taxer->addGroup( 'Group100', 100 ) };
$e = Exception::Class->caught();
ok( !$e, 'addGroup: 100% is a valid group rate' );
my $id50_5 = eval { $taxer->addGroup( 'Group50.5', 50.5 ) };
$e = Exception::Class->caught();
ok( !$e, 'addGroup: floats are a valid group rate' );
my $taxGroups = $taxer->get( 'taxGroups' );
my $expectGroups = [
{
name => 'Group0',
rate => 0,
id => $id0,
},
{
name => 'Group100',
rate => 100,
id => $id100,
},
{
name => 'Group50.5',
rate => 50.5,
id => $id50_5,
},
];
cmp_bag( $taxGroups, $expectGroups, 'addGroup saves correctly' );
# getGroupRate
ok(
$taxer->getGroupRate( $id0 ) == 0
&& $taxer->getGroupRate( $id100 ) == 100
&& $taxer->getGroupRate( $id50_5 ) == 50.5,
'getGroup rate gets correct rates'
);
# deleteGroup
eval { $taxer->deleteGroup };
my $e = Exception::Class->caught();
isa_ok( $e, 'WebGUI::Error::InvalidParam', 'addGroup requires a group id' );
is( $e, 'A group id is required', 'addGroup returns correct message for missing group id' );
$taxer->deleteGroup( $id50_5 );
$taxGroups = $taxer->get( 'taxGroups' );
cmp_bag( $taxGroups, [
{
name => 'Group0',
rate => 0,
id => $id0,
},
{
name => 'Group100',
rate => 100,
id => $id100,
},
], 'deleteGroup deletes correctly' );
# Clean up a bit.
$taxer->deleteGroup( $_ ) for ( $id0, $id100 );
}
#######################################################################
#
# getTaxRate
#
#######################################################################
{
my $taxer = setupTestNumbers();
my $id100 = $taxer->addGroup( 'Group100', 100 );
my $id50_5 = $taxer->addGroup( 'Group50.5', 50.5 );
$taxer->update( { 'automaticViesApproval' => 1 } );
eval { $taxer->getTaxRate(); };
my $e = Exception::Class->caught();
isa_ok($e, 'WebGUI::Error::InvalidParam', 'getTaxRate: error handling for not sending a sku');
is($e->error, 'Must pass in a WebGUI::Asset::Sku object', 'getTaxRate: error handling for not sending a sku');
# Set defaultTaxGroup and residential country
$taxer->update( { defaultGroup => $id50_5, shopCountry => 'NL' } );
# Check default tax group
is( $taxer->getTaxRate( $sku ), 50.5, 'getTaxRate returns default tax group when no address is given and sku has no tax group set');
# Check case when no address is given
$sku->setTaxConfiguration( 'WebGUI::Shop::TaxDriver::EU', { taxGroup => $id100 } );
is( $taxer->getTaxRate( $sku ), 100, 'getTaxRate returns tax group set by sku when no address is given');
# Addresses inside EU with VAT number
is( $taxer->getTaxRate( $sku, $beAddress ), 0,
'getTaxRate: shipping addresses inside EU but other country than merchant w/ VAT number are tax exempt.'
);
is( $taxer->getTaxRate( $sku, $nlAddress ), 100, 'getTaxRate: shipping addresses in country of merchant w/ VAT number pay tax' );
$taxer->deleteVATNumber( $testVAT_NL, $taxUser );
$taxer->deleteVATNumber( $testVAT_BE, $taxUser );
# Addresses inside EU without VAT number
foreach my $country ( @EU_COUNTRIES ) {
next if $country eq $nlAddress->get('country'); # Residents of merchant country should be checked separately.
$beAddress->update( { country => $country } );
is( $taxer->getTaxRate( $sku, $beAddress ), 100, "getTaxRate: shipping addresses in $country w/o VAT number pay tax" );
}
$beAddress->update( { country => 'Belgium' } );
is( $taxer->getTaxRate( $sku, $nlAddress ), 100, 'getTaxRate: shipping addresses in country of merchant w/o VAT number pay tax' );
# Address outside EU
is( $taxer->getTaxRate( $sku, $usAddress ), 0, 'getTaxRate: shipping addresses outside EU are tax exempt' );
}
#######################################################################
#
# appendCartItemVars
#
#######################################################################
{
my $taxer = setupTestNumbers();
eval { $taxer->appendCartItemVars };
my $e = Exception::Class->caught();
isa_ok( $e, 'WebGUI::Error::InvalidParam', 'appendCartItemVars requires a hash ref.' );
is( $e, 'Must supply a hash ref', 'appendCartItemVars returns correct message for missing hash ref' );
eval { $taxer->appendCartItemVars( {}, 'NotAUserObject' ) };
$e = Exception::Class->caught();
isa_ok( $e, 'WebGUI::Error::InvalidObject', 'appendCartItemVars: Second argument must be a cart item object' );
cmp_deeply( $e, methods(
error => 'Must pass a cart item',
expected => 'WebGUI::Shop::CartItem',
got => '',
), 'appendCartItemVars returns correct error for missing CartItem' );
my $cart = WebGUI::Shop::Cart->newBySession( $session );
WebGUI::Test->addToCleanup($cart);
my $item = $cart->addItem( $sku );
$item->setQuantity( 2 );
$item->update( { shippingAddressId => $nlAddress->getId } );
my $cartItemVars = { must => 'be kept' };
$taxer->appendCartItemVars( $cartItemVars, $item );
cmp_deeply( $cartItemVars, {
pricePlusTax => '200.00',
extendedPricePlusTax => '400.00',
taxRate => '100',
taxAmount => '100.00',
VATNumber => $testVAT_NL,
must => 'be kept',
}, 'appendCartItemVars returns correct data for address in shopy country.' );
$item->update( { shippingAddressId => $beAddress->getId } );
$cartItemVars = { must => 'be kept' };
$taxer->appendCartItemVars( $cartItemVars, $item );
cmp_deeply( $cartItemVars, {
pricePlusTax => '100.00',
extendedPricePlusTax => '200.00',
taxRate => '0',
taxAmount => '0.00',
VATNumber => $testVAT_BE,
must => 'be kept',
}, 'appendCartItemVars returns correct data for address in otrher country in EU.' );
$item->update( { shippingAddressId => $usAddress->getId } );
$cartItemVars = { must => 'be kept' };
$taxer->appendCartItemVars( $cartItemVars, $item );
cmp_deeply( $cartItemVars, {
pricePlusTax => '100.00',
extendedPricePlusTax => '200.00',
taxRate => '0',
taxAmount => '0.00',
must => 'be kept',
}, 'appendCartItemVars returns correct data for address outside EU.' );
}
#######################################################################
#
# getTransactionTaxData
#
#######################################################################
{
my $taxer = setupTestNumbers();
$taxer->update( { 'automaticViesApproval' => 1 } );
my $details = $taxer->getTransactionTaxData( $sku, $usAddress );
cmp_deeply( $details, {
className => 'WebGUI::Shop::TaxDriver::EU',
outsideEU => 1,
}, 'getTransactionTaxData returns correct hashref for addresses outside EU' );
$details = $taxer->getTransactionTaxData( $sku, $beAddress );
cmp_deeply( $details, {
className => 'WebGUI::Shop::TaxDriver::EU',
useVATNumber => 1,
VATNumber => $testVAT_BE,
}, 'getTransactionTaxData returns correct hashref for addresses inside EU but not shop country w/ VAT number' );
$details = $taxer->getTransactionTaxData( $sku, $nlAddress );
cmp_deeply( $details, {
className => 'WebGUI::Shop::TaxDriver::EU',
useVATNumber => 1,
VATNumber => $testVAT_NL,
}, 'getTransactionTaxData returns correct hashref for addresses in shop country w/ VAT number' );
$taxer->deleteVATNumber( $testVAT_NL );
$details = $taxer->getTransactionTaxData( $sku, $nlAddress );
cmp_deeply( $details, {
className => 'WebGUI::Shop::TaxDriver::EU',
useVATNumber => 0,
}, 'getTransactionTaxData returns correct hashref for addresses in EU w/o VAT number' );
}
#----------------------------------------------------------------------------
sub setupTestNumbers {
my $taxer = WebGUI::Shop::TaxDriver::EU->new($session);
$session->db->write('delete from taxDriver where className=?', [ 'WebGUI::Shop::TaxDriver::EU' ]);
$session->db->write('delete from tax_eu_vatNumbers');
$taxer->addVATNumber( $testVAT_NL, $taxUser, 1);
$taxer->addVATNumber( $testVAT_BE, $taxUser, 1);
return $taxer;
}
#----------------------------------------------------------------------------
# Cleanup
END {
$session->db->write('delete from tax_eu_vatNumbers');
$session->db->write('delete from addressBook');
$session->db->write('delete from address');
$session->db->write('delete from taxDriver where className=?', [ 'WebGUI::Shop::TaxDriver::EU' ]);
}

723
t/Shop/TaxDriver/Generic.t Normal file
View file

@ -0,0 +1,723 @@
# vim:syntax=perl
#-------------------------------------------------------------------
# WebGUI is Copyright 2001-2009 Plain Black Corporation.
#-------------------------------------------------------------------
# Please read the legal notices (docs/legal.txt) and the license
# (docs/license.txt) that came with this distribution before using
# this software.
#------------------------------------------------------------------
# http://www.plainblack.com info@plainblack.com
#------------------------------------------------------------------
# Write a little about what this script tests.
#
#
use FindBin;
use strict;
use lib "$FindBin::Bin/../../lib";
use Test::More;
use Test::Deep;
use Exception::Class;
use Data::Dumper;
use WebGUI::Test; # Must use this before any other WebGUI modules
use WebGUI::Session;
use WebGUI::Text;
use WebGUI::Shop::Cart;
use WebGUI::Shop::AddressBook;
use WebGUI::Shop::TaxDriver::Generic;
#----------------------------------------------------------------------------
# Init
my $session = WebGUI::Test->session;
$session->user({userId => 3});
#----------------------------------------------------------------------------
# Tests
my $addExceptions = getAddExceptions($session);
my $tests = 80 + 2*scalar(@{$addExceptions});
plan tests => $tests;
#WebGUI::Test->addToCleanup(SQL => 'delete from tax_generic_rates');
#----------------------------------------------------------------------------
# put your tests here
my ($taxableDonation, $taxFreeDonation);
#######################################################################
#
# new
#
#######################################################################
my $taxer = WebGUI::Shop::TaxDriver::Generic->new($session);
isa_ok($taxer, 'WebGUI::Shop::TaxDriver::Generic');
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();
isa_ok($e, 'WebGUI::Error::InvalidParam', 'add: '.$inputSet->{comment});
cmp_deeply(
$e,
methods(
error => $inputSet->{error},
param => $inputSet->{param},
),
'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',
city => 'Madcity',
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.');
my $spaceId = $taxer->add({
country => 'USA, United States , United States Of America ,U.S.A',
state => 'Wisconsin, WI',
city => 'MADCITY, madcity, Madison , WebGUIVille',
code => '77575, 54703 , 97424',
taxRate => '7.77',
});
my $no_spaces = $taxer->getItem($spaceId);
cmp_deeply (
$no_spaces,
{
country => 'USA,United States,United States Of America,U.S.A',
state => 'Wisconsin,WI',
city => 'MADCITY,madcity,Madison,WebGUIVille',
taxRate => '7.77',
taxId => $spaceId,
code => '77575,54703,97424',
},
'Spaces removed from content when adding'
);
$taxer->delete({taxId => $spaceId});
##Madison zip codes:
##53701-53709
##city rate: 0.5%
##Wisconsin rate 5.0%
#######################################################################
#
# getAllItems
#
#######################################################################
my $expectedTaxData = [
{
country => 'USA',
state => 'OR',
city => undef,
code => undef,
taxRate => 0,
},
{
country => 'USA',
state => 'Wisconsin',
city => 'Madcity',
code => '53702',
taxRate => 5,
},
{
country => 'USA',
state => 'Oregon',
city => undef,
code => undef,
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
##
########################################################################
my $storage = $taxer->exportTaxData();
WebGUI::Test->addToCleanup($storage);
isa_ok($storage, 'WebGUI::Storage', 'exportTaxData returns a WebGUI::Storage object');
is(substr($storage->getPathFrag, 0, 5), 'temp/', 'The storage object is in the temporary area');
ok(-e $storage->getPath('siteTaxData.csv'), 'siteTaxData.csv file exists in the storage object');
cmp_ok($storage->getFileSize('siteTaxData.csv'), '!=', 0, 'CSV file is not empty');
my @fileLines = split /\n+/, $storage->getFileContentsAsScalar('siteTaxData.csv');
#my @fileLines = ();
my @header = WebGUI::Text::splitCSV($fileLines[0]);
my @expectedHeader = qw/country state city code taxRate/;
cmp_deeply(\@header, \@expectedHeader, 'exportTaxData: header line is correct');
my @row1 = WebGUI::Text::splitCSV($fileLines[1]);
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',
taxRate => '7',
code => '',
city => '',
});
$taxer->delete({taxId => $wisconsinTaxId});
$storage = $taxer->exportTaxData();
@fileLines = split /\n+/, $storage->getFileContentsAsScalar('siteTaxData.csv');
my @row1 = WebGUI::Text::splitCSV($fileLines[1]);
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');
is($e->error, 'File could not be found', 'importTaxData: error handling for file that does not exist in the filesystem');
cmp_deeply(
$e,
methods(
brokenFile => '/path/to/nowhere',
),
'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');
is($e->error, 'File is not readable', 'importTaxData: error handling for file that that cannot be read');
cmp_deeply(
$e,
methods(
brokenFile => $taxFile,
),
'importTaxData: error handling for file that that cannot be read',
);
chmod $originalChmod, $taxFile;
}
my $expectedTaxData = [
{
country => 'USA',
state => '',
city => '',
code => '',
taxRate => 0,
},
{
country => 'USA',
state => 'Wisconsin',
city => '',
code => '',
taxRate => 5,
},
{
country => 'USA',
state => 'Wisconsin',
city => 'Madison',
code => '53701',
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(
$taxer->getAllItems,
$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(
$taxer->getAllItems,
$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(
$taxer->getAllItems,
$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(
WebGUI::Test->getTestCollateralPath('taxTables/badTaxTable.csv')
);
};
ok (!$failure, 'Tax data not imported');
$e = Exception::Class->caught();
isa_ok($e, 'WebGUI::Error::InvalidFile', 'importTaxData: a file with an error on 1 line');
cmp_deeply(
$e,
methods(
error => 'Error found in the CSV file',
brokenFile => WebGUI::Test->getTestCollateralPath('taxTables/badTaxTable.csv'),
brokenLine => 1,
),
'importTaxData: error handling for file with errors in the CSV data',
);
eval {
$failure = $taxer->importTaxData(
WebGUI::Test->getTestCollateralPath('taxTables/missingHeaders.csv')
);
};
ok (!$failure, 'Tax data not imported when headers are missing');
$e = Exception::Class->caught();
isa_ok($e, 'WebGUI::Error::InvalidFile', 'importTaxData: a file with a missing header column');
cmp_deeply(
$e,
methods(
error => 'Bad header found in the CSV file',
brokenFile => WebGUI::Test->getTestCollateralPath('taxTables/missingHeaders.csv'),
),
'importTaxData: error handling for a file with a missing header',
);
eval {
$failure = $taxer->importTaxData(
WebGUI::Test->getTestCollateralPath('taxTables/badHeaders.csv')
);
};
ok (!$failure, 'Tax data not imported when headers are wrong');
$e = Exception::Class->caught();
isa_ok($e, 'WebGUI::Error::InvalidFile', 'importTaxData: a file with a bad header column');
cmp_deeply(
$e,
methods(
error => 'Bad header found in the CSV file',
brokenFile => WebGUI::Test->getTestCollateralPath('taxTables/badHeaders.csv'),
),
'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,
{
taxId => ignore,
country => q{U.S.A.,USA},
state => q{WI,Wisconsin},
city => q{Madison},
code => 53701,
taxRate => 0.5,
},
'import: Data correctly loaded with alternations'
);
#######################################################################
#
# getTaxRates
#
#######################################################################
##Set up the tax information
$taxer->importTaxData(
WebGUI::Test->getTestCollateralPath('taxTables/largeTaxTable.csv')
),
my $book = WebGUI::Shop::AddressBook->create($session);
WebGUI::Test->addToCleanup($book);
my $taxingAddress = $book->addAddress({
label => 'taxing',
city => 'Madison',
state => 'WI',
code => '53701',
country => 'USA',
});
my $taxFreeAddress = $book->addAddress({
label => 'no tax',
city => 'Portland',
state => 'OR',
code => '97123',
country => 'USA',
});
my $alternateAddress = $book->addAddress({
label => 'using alternations',
city => 'Los Angeles',
state => 'CalifornIA',
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');
cmp_deeply(
$e,
methods(
error => 'Need an address.',
got => '',
expected => 'WebGUI::Shop::Address',
),
'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'
);
my $capitalized = $taxer->add({
country => 'USA',
state => 'wi',
taxRate => '50',
});
cmp_deeply(
$taxer->getTaxRates($taxingAddress),
[0, 5, 0.5],
'... multiple entries with different capitalization, first matches'
);
$taxer->delete({ taxId => $capitalized });
#######################################################################
#
# calculate
#
#######################################################################
eval { $taxer->getTaxRate(); };
$e = Exception::Class->caught();
isa_ok($e, 'WebGUI::Error::InvalidParam', 'getTaxRate: error handling for not sending a sku');
is($e->error, 'Must pass in a WebGUI::Asset::Sku object', 'getTaxRate: error handling for not sending a sku');
##Build a cart, add some Donation SKUs to it. Set one to be taxable.
my $cart = WebGUI::Shop::Cart->newBySession($session);
WebGUI::Test->addToCleanup($cart);
# 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')
),
$taxableDonation = WebGUI::Asset->getRoot($session)->addChild({
className => 'WebGUI::Asset::Sku::Donation',
title => 'Taxable donation',
defaultPrice => 100.00,
});
WebGUI::Test->addToCleanup($taxableDonation);
is($taxer->getTaxRate($taxableDonation), 0, 'calculate returns 0 if there is no shippingAddressId in the cart');
# $cart->addItem($taxableDonation);
# foreach my $item (@{ $cart->getItems }) {
# $item->setQuantity(1);
# }
my $tax = $taxer->getTaxRate( $taxableDonation, $taxingAddress );
is($tax, 5.5, 'calculate: simple tax calculation on 1 item in the cart');
$cart->update({ shippingAddressId => $taxFreeAddress->getId});
is($taxer->getTaxRate( $taxableDonation, $taxFreeAddress ), 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');
$taxFreeDonation = WebGUI::Asset->getRoot($session)->addChild({
className => 'WebGUI::Asset::Sku::Donation',
title => 'Tax Free Donation',
defaultPrice => 100.00,
});
WebGUI::Test->addToCleanup($taxFreeDonation);
$taxFreeDonation->setTaxConfiguration( 'WebGUI::Shop::TaxDriver::Generic', {
overrideTaxRate => 1,
taxRateOverride => 0,
});
# $cart->addItem($taxFreeDonation);
# foreach my $item (@{ $cart->getItems }) {
# $item->setQuantity(1);
# }
is($taxer->getTaxRate( $taxFreeDonation, $taxingAddress), 0, 'getTaxRate: tax rate override should override tax derived from address');
# 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');
is($session->http->getMimeType, 'application/json', 'MIME type set to application/json');
my $jsonTax = JSON::from_json($json);
cmp_deeply(
$jsonTax,
{
sort => undef,
startIndex => 0,
totalRecords => 1778,
recordsReturned => 25,
dir => 'asc',
records => array_each({
taxId=>ignore,
country => 'USA',
state=>ignore,
city=>ignore,
code=>ignore,
taxRate=>re('^\d+(\.\d+)?$')
}),
},
'Check major elements of tax JSON',
);
TODO: {
local $TODO = 'More getTaxesAsJson tests';
ok(0, 'test group privileges to this method');
ok(0, 'test startIndex variable');
ok(0, 'test results form variable');
ok(0, 'test keywords');
}
sub getAddExceptions {
my $session = shift;
my $inputValidion = [
{
args => {},
error => q{Missing required information.},
param => q{country},
comment => q{missing country},
},
{
args => {country => undef},
error => q{Missing required information.},
param => q{country},
comment => q{undef country},
},
{
args => {country => ''},
error => q{Missing required information.},
param => q{country},
comment => q{empty country},
},
{
args => {country => 'USA'},
error => q{Missing required information.},
param => q{taxRate},
comment => q{missing taxRate},
},
{
args => {country => 'USA', taxRate => undef},
error => q{Missing required information.},
param => q{taxRate},
comment => q{empty taxRate},
},
];
}
#vim:ft=perl