Pluggable Tax: more POD, more tests, better code and less bugs
This commit is contained in:
parent
f3ed30d939
commit
461c80a6b8
7 changed files with 602 additions and 57 deletions
|
|
@ -8,6 +8,10 @@ versions. Be sure to heed the warnings contained herein as they will
|
||||||
save you many hours of grief.
|
save you many hours of grief.
|
||||||
|
|
||||||
|
|
||||||
|
7.7.6
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
* WebGUI now requires Business::Tax::VAT::Validation.
|
||||||
|
|
||||||
7.7.5
|
7.7.5
|
||||||
--------------------------------------------------------------------
|
--------------------------------------------------------------------
|
||||||
* Due to a long standing bug in the Profile system, if the type of a
|
* Due to a long standing bug in the Profile system, if the type of a
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ my $session = start();
|
||||||
# upgrade functions go here
|
# upgrade functions go here
|
||||||
addTemplateAttachmentsTable($session);
|
addTemplateAttachmentsTable($session);
|
||||||
revertUsePacked( $session );
|
revertUsePacked( $session );
|
||||||
|
addEuVatDbColumns( $session );
|
||||||
|
|
||||||
finish($session);
|
finish($session);
|
||||||
|
|
||||||
|
|
@ -77,6 +78,16 @@ sub revertUsePacked {
|
||||||
print "DONE!\n" unless $quiet;
|
print "DONE!\n" unless $quiet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------
|
||||||
|
sub addEuVatDbColumns {
|
||||||
|
my $session = shift;
|
||||||
|
print "\tAdding columns for improved VAT number checking..." unless $quiet;
|
||||||
|
|
||||||
|
$session->db->write( 'alter table tax_eu_vatNumbers add column viesErrorCode int(3) default NULL' );
|
||||||
|
|
||||||
|
print "Done\n" unless $quiet;
|
||||||
|
}
|
||||||
|
|
||||||
# -------------- DO NOT EDIT BELOW THIS LINE --------------------------------
|
# -------------- DO NOT EDIT BELOW THIS LINE --------------------------------
|
||||||
|
|
||||||
#----------------------------------------------------------------------------
|
#----------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -128,9 +128,9 @@ A WebGUI::Session object. Required in class context, optional in instance contex
|
||||||
sub getDriver {
|
sub getDriver {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $session = shift || $self->session;
|
my $session = shift || $self->session;
|
||||||
unless (defined $session && $session->isa("WebGUI::Session")) {
|
|
||||||
WebGUI::Error::InvalidObject->throw(expected=>"WebGUI::Session", got=>(ref $session), error=>"Need a session.");
|
WebGUI::Error::InvalidObject->throw( expected => "WebGUI::Session", got => (ref $session), error => "Need a session." )
|
||||||
}
|
unless $session && $session->isa( 'WebGUI::Session' );
|
||||||
|
|
||||||
my $className = $session->setting->get( 'activeTaxPlugin' );
|
my $className = $session->setting->get( 'activeTaxPlugin' );
|
||||||
my $driver = eval {
|
my $driver = eval {
|
||||||
|
|
@ -155,9 +155,10 @@ Constructor for the WebGUI::Shop::Tax. Returns a WebGUI::Shop::Tax object.
|
||||||
sub new {
|
sub new {
|
||||||
my $class = shift;
|
my $class = shift;
|
||||||
my $session = shift;
|
my $session = shift;
|
||||||
unless (defined $session && $session->isa("WebGUI::Session")) {
|
|
||||||
WebGUI::Error::InvalidObject->throw(expected=>"WebGUI::Session", got=>(ref $session), error=>"Need a session.");
|
WebGUI::Error::InvalidObject->throw( expected => "WebGUI::Session", got => (ref $session), error => "Need a session." )
|
||||||
}
|
unless $session && $session->isa( 'WebGUI::Session' );
|
||||||
|
|
||||||
my $self = {};
|
my $self = {};
|
||||||
bless $self, $class;
|
bless $self, $class;
|
||||||
register $self;
|
register $self;
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,8 @@ sub className {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
$self->session->log->fatal( "Tax plugin ($self) is required to overload the className method" );
|
$self->session->log->fatal( "Tax plugin ($self) is required to overload the className method" );
|
||||||
|
|
||||||
|
return 'WebGUI::Shop:TaxDriver';
|
||||||
}
|
}
|
||||||
|
|
||||||
#-----------------------------------------------------------
|
#-----------------------------------------------------------
|
||||||
|
|
@ -214,6 +216,9 @@ sub new {
|
||||||
my $class = shift;
|
my $class = shift;
|
||||||
my $session = shift;
|
my $session = shift;
|
||||||
|
|
||||||
|
WebGUI::Error::InvalidObject->throw( expected => "WebGUI::Session", got => (ref $session), error => "Need a session." )
|
||||||
|
unless $session && $session->isa( 'WebGUI::Session' );
|
||||||
|
|
||||||
my $self = {};
|
my $self = {};
|
||||||
bless $self, $class;
|
bless $self, $class;
|
||||||
register $self;
|
register $self;
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@ use SOAP::Lite;
|
||||||
use WebGUI::Content::Account;
|
use WebGUI::Content::Account;
|
||||||
use WebGUI::TabForm;
|
use WebGUI::TabForm;
|
||||||
use WebGUI::Utility qw{ isIn };
|
use WebGUI::Utility qw{ isIn };
|
||||||
|
use Business::Tax::VAT::Validation;
|
||||||
|
use Tie::IxHash;
|
||||||
|
|
||||||
use base qw{ WebGUI::Shop::TaxDriver };
|
use base qw{ WebGUI::Shop::TaxDriver };
|
||||||
|
|
||||||
|
|
@ -30,7 +32,8 @@ Package WebGUI::Shop::TaxDriver::EU
|
||||||
=head1 DESCRIPTION
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
This package manages tax information, and calculates taxes on a shopping cart specifically handling
|
This package manages tax information, and calculates taxes on a shopping cart specifically handling
|
||||||
European Union VAT taxes.
|
European Union VAT taxes. It allows you to define VAT groups (eg. in the Netherlands there are two VAT tariffs:
|
||||||
|
high (19%) and low (6%) ) that can be applied to SKU assets.
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
|
@ -44,7 +47,8 @@ These subroutines are available from this package:
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
my $EU_COUNTRIES = {
|
|
||||||
|
tie my %EU_COUNTRIES, 'Tie::IxHash', (
|
||||||
AT => 'Austria',
|
AT => 'Austria',
|
||||||
BE => 'Belgium',
|
BE => 'Belgium',
|
||||||
BG => 'Bulgaria',
|
BG => 'Bulgaria',
|
||||||
|
|
@ -72,7 +76,105 @@ my $EU_COUNTRIES = {
|
||||||
SE => 'Sweden',
|
SE => 'Sweden',
|
||||||
SI => 'Slovenia',
|
SI => 'Slovenia',
|
||||||
SK => 'Slovakia',
|
SK => 'Slovakia',
|
||||||
};
|
);
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------
|
||||||
|
|
||||||
|
=head2 addGroup ( name, rate )
|
||||||
|
|
||||||
|
Adds a tax group. Returns the group id.
|
||||||
|
|
||||||
|
=head3 name
|
||||||
|
|
||||||
|
The display name of the tax group.
|
||||||
|
|
||||||
|
=head3 rate
|
||||||
|
|
||||||
|
The tax rate for this group in percents.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub addGroup {
|
||||||
|
my $self = shift;
|
||||||
|
my $name = shift;
|
||||||
|
my $rate = shift;
|
||||||
|
|
||||||
|
WebGUI::Error::InvalidParam->throw( 'A group name is required' )
|
||||||
|
unless $name;
|
||||||
|
WebGUI::Error::InvalidParam->throw( 'Group rate must be within 0 and 100' )
|
||||||
|
unless defined $rate && $rate >= 0 && $rate <= 100;
|
||||||
|
|
||||||
|
my $id = $self->session->id->generate;
|
||||||
|
my $groups = $self->get( 'taxGroups' ) || [];
|
||||||
|
|
||||||
|
push @{ $groups }, {
|
||||||
|
name => $name,
|
||||||
|
rate => $rate,
|
||||||
|
id => $id,
|
||||||
|
};
|
||||||
|
|
||||||
|
$self->update( { taxGroups => $groups } );
|
||||||
|
|
||||||
|
return $id;
|
||||||
|
}
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------
|
||||||
|
|
||||||
|
=head2 addVATNumber ( VATNumber, localCheckOnly )
|
||||||
|
|
||||||
|
Adds a VAT number to the database. Checks the number through the VIES database. Returns and error message if a
|
||||||
|
validation error occurred. If the number validates undef is returned.
|
||||||
|
|
||||||
|
=head3 VATNumber
|
||||||
|
|
||||||
|
The number that is to be added.
|
||||||
|
|
||||||
|
=head3 user
|
||||||
|
|
||||||
|
The user for which the number should be added. Defaults to the session user.
|
||||||
|
|
||||||
|
=head3 localCheckOnly
|
||||||
|
|
||||||
|
If set to a true value the the remote VAT number validation in the VIES database will not be preformed. The VAT
|
||||||
|
number will be checked against regexes, however. Mostly convenient for testing purposes.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub addVATNumber {
|
||||||
|
my $self = shift;
|
||||||
|
my $number = shift;
|
||||||
|
my $user = shift || $self->session->user;
|
||||||
|
my $localCheckOnly = shift;
|
||||||
|
my $db = $self->session->db;
|
||||||
|
|
||||||
|
WebGUI::Error::InvalidParam->throw( 'A VAT number is required' )
|
||||||
|
unless $number;
|
||||||
|
WebGUI::Error::InvalidParam->throw( 'The second argument must be an instanciated WebGUI::User object' )
|
||||||
|
unless ref $user eq 'WebGUI::User';
|
||||||
|
WebGUI::Error::InvalidParam->throw( 'Visitor cannot add VAT numbers' )
|
||||||
|
if $user->isVisitor;
|
||||||
|
|
||||||
|
# Check number
|
||||||
|
my $validator = Business::Tax::VAT::Validation->new;
|
||||||
|
my $numberIsValid = $localCheckOnly ? $validator->local_check( $number ) : $validator->check( $number );
|
||||||
|
|
||||||
|
# Number contains syntax error does not exist. Do not write the code to the db.
|
||||||
|
if ( !$numberIsValid && $validator->get_last_error_code <= 16 ) {
|
||||||
|
return 'The entered VAT number is invalid.';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Write the code to the db.
|
||||||
|
$db->write( 'replace into tax_eu_vatNumbers (userId,countryCode,vatNumber,approved,viesErrorCode) values (?,?,?,?,?)', [
|
||||||
|
$user->userId,
|
||||||
|
substr( $number, 0 , 2 ),
|
||||||
|
$number,
|
||||||
|
$numberIsValid ? 1 : 0,
|
||||||
|
$numberIsValid ? undef : $validator->get_last_error_code,
|
||||||
|
] );
|
||||||
|
|
||||||
|
return $numberIsValid ? undef : 'Number validation currently not available. Check later.';
|
||||||
|
}
|
||||||
|
|
||||||
#-------------------------------------------------------------------
|
#-------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
@ -86,6 +188,59 @@ sub className {
|
||||||
return 'WebGUI::Shop::TaxDriver::EU';
|
return 'WebGUI::Shop::TaxDriver::EU';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------
|
||||||
|
|
||||||
|
=head2 deleteGroup ( groupId )
|
||||||
|
|
||||||
|
Deletes a tax group.
|
||||||
|
|
||||||
|
=head3 groupId
|
||||||
|
|
||||||
|
The id of the tax group that is to be deleted.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub deleteGroup {
|
||||||
|
my $self = shift;
|
||||||
|
my $removeGroupId = shift;
|
||||||
|
|
||||||
|
WebGUI::Error::InvalidParam->throw( 'A group id is required' )
|
||||||
|
unless $removeGroupId;
|
||||||
|
|
||||||
|
my $taxGroups = $self->get( 'taxGroups' );
|
||||||
|
my @newGroups = grep { $_->{ id } ne $removeGroupId } @{ $taxGroups };
|
||||||
|
|
||||||
|
$self->update( { taxGroups => \@newGroups } );
|
||||||
|
}
|
||||||
|
|
||||||
|
#-----------------------------------------------------------
|
||||||
|
|
||||||
|
=head2 deleteVATNumber ( VATNumber, [ user ] )
|
||||||
|
|
||||||
|
Deletes a VAT number.
|
||||||
|
|
||||||
|
=head3 VATNumber
|
||||||
|
|
||||||
|
The VATNumber to delete.
|
||||||
|
|
||||||
|
=head3 user
|
||||||
|
|
||||||
|
The user whose VATNumber must be deleted, in the form of a WebGUI::User object.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub deleteVATNumber {
|
||||||
|
my $self = shift;
|
||||||
|
my $number = shift;
|
||||||
|
my $user = shift || $self->session->user;
|
||||||
|
my $session = $self->session;
|
||||||
|
|
||||||
|
$session->db->write( 'delete from tax_eu_vatNumbers where userId=? and vatNumber=?', [
|
||||||
|
$user->userId,
|
||||||
|
$number,
|
||||||
|
] );
|
||||||
|
}
|
||||||
|
|
||||||
#-----------------------------------------------------------
|
#-----------------------------------------------------------
|
||||||
|
|
||||||
=head2 getConfigurationScreen ( )
|
=head2 getConfigurationScreen ( )
|
||||||
|
|
@ -100,6 +255,11 @@ sub getConfigurationScreen {
|
||||||
|
|
||||||
my $taxGroups = $self->get( 'taxGroups' ) || [];
|
my $taxGroups = $self->get( 'taxGroups' ) || [];
|
||||||
|
|
||||||
|
tie my %countryOptions, 'Tie::IxHash', (
|
||||||
|
'' => ' - select a country - ',
|
||||||
|
%EU_COUNTRIES,
|
||||||
|
);
|
||||||
|
|
||||||
# General setting form
|
# General setting form
|
||||||
my $f = WebGUI::HTMLForm->new( $session );
|
my $f = WebGUI::HTMLForm->new( $session );
|
||||||
$f->hidden(
|
$f->hidden(
|
||||||
|
|
@ -119,7 +279,7 @@ sub getConfigurationScreen {
|
||||||
value => $self->get( 'shopCountry' ),
|
value => $self->get( 'shopCountry' ),
|
||||||
label => 'Residential country',
|
label => 'Residential country',
|
||||||
hoverHelp => 'The country where your shop resides.',
|
hoverHelp => 'The country where your shop resides.',
|
||||||
options => $EU_COUNTRIES,
|
options => \%countryOptions,
|
||||||
);
|
);
|
||||||
$f->submit;
|
$f->submit;
|
||||||
my $general = $f->print;
|
my $general = $f->print;
|
||||||
|
|
@ -203,12 +363,12 @@ sub getCountryCode {
|
||||||
my $countryName = shift;
|
my $countryName = shift;
|
||||||
|
|
||||||
# Do reverse lookup on eu countries hash
|
# Do reverse lookup on eu countries hash
|
||||||
return { reverse %{ $EU_COUNTRIES } }->{ $countryName };
|
return { reverse %EU_COUNTRIES }->{ $countryName };
|
||||||
}
|
}
|
||||||
|
|
||||||
#-------------------------------------------------------------------
|
#-------------------------------------------------------------------
|
||||||
|
|
||||||
=head2 getCountryName ($countryCode)
|
=head2 getCountryName ( $countryCode )
|
||||||
|
|
||||||
Given a 2 character country code, return the name of the country.
|
Given a 2 character country code, return the name of the country.
|
||||||
|
|
||||||
|
|
@ -222,15 +382,19 @@ sub getCountryName {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $countryCode = shift;
|
my $countryCode = shift;
|
||||||
|
|
||||||
return $EU_COUNTRIES->{ $countryCode };
|
return $EU_COUNTRIES{ $countryCode };
|
||||||
}
|
}
|
||||||
|
|
||||||
#-------------------------------------------------------------------
|
#-------------------------------------------------------------------
|
||||||
|
|
||||||
=head2 getGroupRate ($taxGroupId)
|
=head2 getGroupRate ( $taxGroupId )
|
||||||
|
|
||||||
|
Returns the tax rate for a given tax group.
|
||||||
|
|
||||||
=head3 $taxGroupId
|
=head3 $taxGroupId
|
||||||
|
|
||||||
|
The id of the tax group whose rate should be returned.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
sub getGroupRate {
|
sub getGroupRate {
|
||||||
|
|
@ -303,7 +467,7 @@ sub getUserScreen {
|
||||||
|
|
||||||
#-------------------------------------------------------------------
|
#-------------------------------------------------------------------
|
||||||
|
|
||||||
=head2 getTaxRate ( sku, [ address ] )
|
=head2 getTaxRate ( sku, [ address, user ] )
|
||||||
|
|
||||||
Returns the tax rate in percents (eg. 19 for a rate of 19%) for the given sku and shipping address. Implements
|
Returns the tax rate in percents (eg. 19 for a rate of 19%) for the given sku and shipping address. Implements
|
||||||
EU VAT taxes and group rates.
|
EU VAT taxes and group rates.
|
||||||
|
|
@ -315,6 +479,11 @@ sub getTaxRate {
|
||||||
my $sku = shift;
|
my $sku = shift;
|
||||||
my $address = shift;
|
my $address = shift;
|
||||||
|
|
||||||
|
WebGUI::Error::InvalidParam->throw(error => 'Must pass in a WebGUI::Asset::Sku object')
|
||||||
|
unless $sku && $sku->isa( 'WebGUI::Asset::Sku' );
|
||||||
|
WebGUI::Error::InvalidParam->throw(error => 'Must pass in a WebGUI::Shop::Address object')
|
||||||
|
if $address && !$address->isa( 'WebGUI::Shop::Address' );
|
||||||
|
|
||||||
my $config = $sku->getTaxConfiguration( $self->className );
|
my $config = $sku->getTaxConfiguration( $self->className );
|
||||||
|
|
||||||
# Fetch the tax group from the sku. If the sku has none, use the default tax group.
|
# Fetch the tax group from the sku. If the sku has none, use the default tax group.
|
||||||
|
|
@ -340,26 +509,34 @@ sub getTaxRate {
|
||||||
|
|
||||||
#-------------------------------------------------------------------
|
#-------------------------------------------------------------------
|
||||||
|
|
||||||
=head2 getVATNumbers ($countryCode)
|
=head2 getVATNumbers ( $countryCode )
|
||||||
|
|
||||||
|
Returns an array ref of hash refs containing the properties of the VAT numbers a user s registered for a given
|
||||||
|
country. Returns an empty array ref if the user has no VAT numbers in the requested country.
|
||||||
|
|
||||||
|
The hash keys of interest for most people are vatNumber, which contains the actual number, and approved, which
|
||||||
|
indicates whether or not the number has been approved for use yet.
|
||||||
|
|
||||||
=head3 $countryCode
|
=head3 $countryCode
|
||||||
|
|
||||||
|
The two letter country code of the country the VAT numbers are requested for.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
sub getVATNumbers {
|
sub getVATNumbers {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $countryCode = shift;
|
my $countryCode = shift;
|
||||||
my $session = $self->session;
|
my $user = shift || $self->session->user;
|
||||||
|
|
||||||
my $sql = 'select * from tax_eu_vatNumbers where userId=?';
|
my $sql = 'select * from tax_eu_vatNumbers where userId=?';
|
||||||
my $placeHolders = [ $session->user->userId ];
|
my $placeHolders = [ $user->userId ];
|
||||||
|
|
||||||
if ( $countryCode ) {
|
if ( $countryCode ) {
|
||||||
$sql .= ' and countryCode=?';
|
$sql .= ' and countryCode=?';
|
||||||
push @{ $placeHolders }, $countryCode;
|
push @{ $placeHolders }, $countryCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $numbers = $session->db->buildArrayRefOfHashRefs( $sql, $placeHolders );
|
my $numbers = $self->session->db->buildArrayRefOfHashRefs( $sql, $placeHolders );
|
||||||
|
|
||||||
return $numbers;
|
return $numbers;
|
||||||
}
|
}
|
||||||
|
|
@ -368,8 +545,12 @@ sub getVATNumbers {
|
||||||
|
|
||||||
=head2 hasVATNumber ($countrycode)
|
=head2 hasVATNumber ($countrycode)
|
||||||
|
|
||||||
|
Returns a boolean indicating whether or not the user has VAT numbers registered for the given country.
|
||||||
|
|
||||||
=head3 $countryCode
|
=head3 $countryCode
|
||||||
|
|
||||||
|
The two letter country code of contry for which the existance of VAT numbers is requested.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
sub hasVATNumber {
|
sub hasVATNumber {
|
||||||
|
|
@ -417,6 +598,8 @@ sub skuFormDefinition {
|
||||||
|
|
||||||
=head2 www_addGroup
|
=head2 www_addGroup
|
||||||
|
|
||||||
|
Adds a VAT group.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
sub www_addGroup {
|
sub www_addGroup {
|
||||||
|
|
@ -425,18 +608,7 @@ sub www_addGroup {
|
||||||
|
|
||||||
return $self->session->privilege->insufficient unless $self->canManage;
|
return $self->session->privilege->insufficient unless $self->canManage;
|
||||||
|
|
||||||
my $groups = $self->get( 'taxGroups' ) || [];
|
$self->addGroup( $form->process( 'name' ), $form->process( 'rate' ) );
|
||||||
my $name = $form->process( 'name' );
|
|
||||||
my $rate = $form->process( 'rate' );
|
|
||||||
my $id = $self->session->id->generate;
|
|
||||||
|
|
||||||
push @{ $groups }, {
|
|
||||||
name => $name,
|
|
||||||
rate => $rate,
|
|
||||||
id => $id,
|
|
||||||
};
|
|
||||||
|
|
||||||
$self->update( { taxGroups => $groups } );
|
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
@ -445,6 +617,11 @@ sub www_addGroup {
|
||||||
|
|
||||||
=head2 www_addVATNumber
|
=head2 www_addVATNumber
|
||||||
|
|
||||||
|
Allows a user to add a VAT number. The validity of VAT numbers will be automatically checked using the VIES service
|
||||||
|
provided by the European Union. See http://ec.europa.eu/taxation_customs/vies/vieshome.do for more information
|
||||||
|
conerning the service. Please also read the disclamer information located at
|
||||||
|
http://ec.europa.eu/taxation_customs/vies/viesdisc.do.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
sub www_addVATNumber {
|
sub www_addVATNumber {
|
||||||
|
|
@ -457,22 +634,12 @@ sub www_addVATNumber {
|
||||||
my $vatNumber = uc $form->process( 'vatNumber' );
|
my $vatNumber = uc $form->process( 'vatNumber' );
|
||||||
my ($countryCode, $number) = $vatNumber =~ m/^([A-Z]{2})([A-Z0-9]+)$/;
|
my ($countryCode, $number) = $vatNumber =~ m/^([A-Z]{2})([A-Z0-9]+)$/;
|
||||||
|
|
||||||
return 'Illegal country code' unless isIn( $countryCode, keys %{ $EU_COUNTRIES } );
|
return 'Illegal country code' unless isIn( $countryCode, keys %EU_COUNTRIES );
|
||||||
|
|
||||||
return 'You already have a VAT number for this country.' if @{ $self->getVATNumbers( $countryCode ) };
|
return 'You already have a VAT number for this country.' if @{ $self->getVATNumbers( $countryCode ) };
|
||||||
|
|
||||||
# Check VAT number via SOAP interface.
|
#### TODO: Handle errorMessage.
|
||||||
# TODO: Handle timeouts.
|
my $errorMessage = $self->addVATNumber( $vatNumber );
|
||||||
my $soap = SOAP::Lite->service('http://ec.europa.eu/taxation_customs/vies/api/checkVatPort?wsdl');
|
|
||||||
my $isValid = ( $soap->checkVat( $countryCode, $number ) )[ 3 ] || 0;
|
|
||||||
|
|
||||||
# Write the code to the db.
|
|
||||||
$db->write( 'replace into tax_eu_vatNumbers (userId,countryCode,vatNumber,approved) values (?,?,?,?)', [
|
|
||||||
$self->session->user->userId,
|
|
||||||
$countryCode,
|
|
||||||
$vatNumber,
|
|
||||||
$isValid,
|
|
||||||
] );
|
|
||||||
|
|
||||||
my $instance = WebGUI::Content::Account->createInstance($session,"shop");
|
my $instance = WebGUI::Content::Account->createInstance($session,"shop");
|
||||||
return $instance->displayContent( $instance->callMethod("manageTaxData", [], $session->user->userId) );
|
return $instance->displayContent( $instance->callMethod("manageTaxData", [], $session->user->userId) );
|
||||||
|
|
@ -482,6 +649,8 @@ sub www_addVATNumber {
|
||||||
|
|
||||||
=head2 www_deleteGroup
|
=head2 www_deleteGroup
|
||||||
|
|
||||||
|
Deletes a VAT group.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
sub www_deleteGroup {
|
sub www_deleteGroup {
|
||||||
|
|
@ -490,11 +659,7 @@ sub www_deleteGroup {
|
||||||
|
|
||||||
return $self->session->privilege->insufficient unless $self->canManage;
|
return $self->session->privilege->insufficient unless $self->canManage;
|
||||||
|
|
||||||
my $taxGroups = $self->get( 'taxGroups' );
|
$self->deleteGroup( $form->process( 'groupId' ) );
|
||||||
my $removeGroupId = $form->process( 'groupId' );
|
|
||||||
my @newGroups = grep { $_->{ id } ne $removeGroupId } @{ $taxGroups };
|
|
||||||
|
|
||||||
$self->update( { taxGroups => \@newGroups } );
|
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
@ -503,18 +668,17 @@ sub www_deleteGroup {
|
||||||
|
|
||||||
=head2 www_deleteVATNumber
|
=head2 www_deleteVATNumber
|
||||||
|
|
||||||
|
Deletes a VAT number.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
sub www_deleteVATNumber {
|
sub www_deleteVATNumber {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $session = $self->session;
|
my $session = $self->session;
|
||||||
|
|
||||||
return $session->privilege->insufficient unless $session->user->isVisitor;
|
return $session->privilege->insufficient if $session->user->isVisitor;
|
||||||
|
|
||||||
$session->db->write( 'delete from tax_eu_vatNumbers where userId=? and vatNumber=?', [
|
$self->deleteVATNumber( $session->form->process( 'vatNumber' ) );
|
||||||
$session->user->userId,
|
|
||||||
$session->form->process( 'vatNumber' ),
|
|
||||||
] );
|
|
||||||
|
|
||||||
my $instance = WebGUI::Content::Account->createInstance($session,"shop");
|
my $instance = WebGUI::Content::Account->createInstance($session,"shop");
|
||||||
return $instance->displayContent( $instance->callMethod("manageTaxData", [], $session->user->userId) );
|
return $instance->displayContent( $instance->callMethod("manageTaxData", [], $session->user->userId) );
|
||||||
|
|
@ -524,6 +688,8 @@ sub www_deleteVATNumber {
|
||||||
|
|
||||||
=head2 www_saveConfiguration
|
=head2 www_saveConfiguration
|
||||||
|
|
||||||
|
Updates the configuration properties for this plugin, as passed by the form on the configuration screen.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
sub www_saveConfiguration {
|
sub www_saveConfiguration {
|
||||||
|
|
@ -543,6 +709,8 @@ sub www_saveConfiguration {
|
||||||
|
|
||||||
=head2 www_setDefaultGroup
|
=head2 www_setDefaultGroup
|
||||||
|
|
||||||
|
Sets a VAT group to be used as default for SKU's that do not have a VAT group defined yet.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
sub www_setDefaultGroup {
|
sub www_setDefaultGroup {
|
||||||
|
|
|
||||||
|
|
@ -126,6 +126,7 @@ checkModule("Clone", "0.31" );
|
||||||
checkModule('HTML::Packer', "0.4" );
|
checkModule('HTML::Packer', "0.4" );
|
||||||
checkModule('JavaScript::Packer', '0.02' );
|
checkModule('JavaScript::Packer', '0.02' );
|
||||||
checkModule('CSS::Packer', '0.2' );
|
checkModule('CSS::Packer', '0.2' );
|
||||||
|
checkModule('Business::Tax::VAT::Validation', '0.20' );
|
||||||
|
|
||||||
failAndExit("Required modules are missing, running no more checks.") if $missingModule;
|
failAndExit("Required modules are missing, running no more checks.") if $missingModule;
|
||||||
|
|
||||||
|
|
|
||||||
355
t/Shop/TaxDriver/EU.t
Normal file
355
t/Shop/TaxDriver/EU.t
Normal file
|
|
@ -0,0 +1,355 @@
|
||||||
|
# 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;
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------
|
||||||
|
# Init
|
||||||
|
my $session = WebGUI::Test->session;
|
||||||
|
|
||||||
|
my $taxUser = WebGUI::User->new( $session, 'new' );
|
||||||
|
$taxUser->username( 'MrEvasion' );
|
||||||
|
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------
|
||||||
|
# Tests
|
||||||
|
|
||||||
|
my $tests = 44;
|
||||||
|
plan tests => 1 + $tests;
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------
|
||||||
|
# put your tests here
|
||||||
|
|
||||||
|
my $loaded = use_ok('WebGUI::Shop::TaxDriver::EU');
|
||||||
|
|
||||||
|
SKIP: {
|
||||||
|
|
||||||
|
skip 'Unable to load module WebGUI::Shop::TaxDriver::EU', $tests unless $loaded;
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
#
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
is( $taxer->className, 'WebGUI::Shop::TaxDriver::EU', 'className returns correct class name' );
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
#
|
||||||
|
# getConfigurationScreen
|
||||||
|
#
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
#### TODO: Figure out how to test this.
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
#
|
||||||
|
# getCountryCode
|
||||||
|
#
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
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.' );
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
#
|
||||||
|
# getCountryName
|
||||||
|
#
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
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.' );
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
#
|
||||||
|
# addVATNumber
|
||||||
|
#
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
$session->user( {userId=>$taxUser->userId} );
|
||||||
|
|
||||||
|
my $testVAT_NL = 'NL123456789B12';
|
||||||
|
my $testVAT_BE = 'BE0123456789';
|
||||||
|
my $invalidVAT = 'ByNoMeansAllowed';
|
||||||
|
my $visitorUser = WebGUI::User->new( $session, 1 );
|
||||||
|
|
||||||
|
eval { $taxer->addVATNumber };
|
||||||
|
my $e = Exception::Class->caught();
|
||||||
|
isa_ok( $e, 'WebGUI::Error::InvalidParam', 'A VAT number is required' );
|
||||||
|
is( $e, 'A VAT number is required', 'addVATNumber returns correct message for missing VAT number' );
|
||||||
|
|
||||||
|
eval { $taxer->addVATNumber( $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', 'addVATNumber returns correct message when user object is of wrong type' );
|
||||||
|
|
||||||
|
eval { $taxer->addVATNumber( $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', 'addVATNumber returns correct message when user is visitor' );
|
||||||
|
|
||||||
|
my $response = $taxer->addVATNumber( $invalidVAT, $taxUser, 1 );
|
||||||
|
is( $response, 'The entered VAT number is invalid.', 'Invalid VAT numbers return an error message' );
|
||||||
|
|
||||||
|
my $responseNL = $taxer->addVATNumber( $testVAT_NL, $taxUser, 1 );
|
||||||
|
my $responseBE = $taxer->addVATNumber( $testVAT_BE, $taxUser, 1 );
|
||||||
|
|
||||||
|
ok( !defined $responseNL && !defined $responseBE, 'Valid VAT numbers return undef.' );
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
#
|
||||||
|
# getVATNumbers
|
||||||
|
#
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
my $expectNL = {
|
||||||
|
userId => $taxUser->userId,
|
||||||
|
countryCode => 'NL',
|
||||||
|
vatNumber => $testVAT_NL,
|
||||||
|
approved => 1,
|
||||||
|
viesErrorCode => undef,
|
||||||
|
};
|
||||||
|
my $expectBE = {
|
||||||
|
userId => $taxUser->userId,
|
||||||
|
countryCode => 'BE',
|
||||||
|
vatNumber => $testVAT_BE,
|
||||||
|
approved => 1,
|
||||||
|
viesErrorCode => undef,
|
||||||
|
};
|
||||||
|
|
||||||
|
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' );
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
#
|
||||||
|
# deleteVATNumber
|
||||||
|
#
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
$taxer->deleteVATNumber( $testVAT_BE, $taxUser );
|
||||||
|
$vatNumbers = $taxer->getVATNumbers( undef, $taxUser );
|
||||||
|
cmp_bag( $vatNumbers, [ $expectNL ], 'deleteVATNumber deletes number' );
|
||||||
|
|
||||||
|
$taxer->deleteVATNumber( $testVAT_NL, $taxUser );
|
||||||
|
#######################################################################
|
||||||
|
#
|
||||||
|
# addGroupRate
|
||||||
|
#
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
eval { $taxer->addGroup };
|
||||||
|
$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'
|
||||||
|
);
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
#
|
||||||
|
# getTaxRate
|
||||||
|
#
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
my $book = WebGUI::Shop::AddressBook->create($session);
|
||||||
|
|
||||||
|
# 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',
|
||||||
|
});
|
||||||
|
|
||||||
|
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 );
|
||||||
|
|
||||||
|
my $sku = WebGUI::Asset->getRoot($session)->addChild( {
|
||||||
|
className => 'WebGUI::Asset::Sku::Donation',
|
||||||
|
title => 'Taxable donation',
|
||||||
|
defaultPrice => 100.00,
|
||||||
|
} );
|
||||||
|
|
||||||
|
# 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');
|
||||||
|
|
||||||
|
# Address outside EU
|
||||||
|
is( $taxer->getTaxRate( $sku, $usAddress ), 0, 'getTaxRate: shipping addresses outside EU are tax exempt' );
|
||||||
|
|
||||||
|
# Addresses inside EU
|
||||||
|
is( $taxer->getTaxRate( $sku, $beAddress ), 100, 'getTaxRate: shipping addresses inside EU w/o VAT number pay tax' );
|
||||||
|
is( $taxer->getTaxRate( $sku, $nlAddress ), 100, 'getTaxRate: shipping addresses in country of merchant w/o VAT number pay tax' );
|
||||||
|
|
||||||
|
# Add VAT numbers
|
||||||
|
$taxer->addVATNumber( $testVAT_NL, $taxUser, 1);
|
||||||
|
$taxer->addVATNumber( $testVAT_BE, $taxUser, 1);
|
||||||
|
|
||||||
|
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' );
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
#
|
||||||
|
# deleteGroup
|
||||||
|
#
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
eval { $taxer->deleteGroup };
|
||||||
|
$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' );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------
|
||||||
|
# Cleanup
|
||||||
|
END {
|
||||||
|
$session->db->write('delete from tax_eu_vatNumbers');
|
||||||
|
$session->db->write('delete from cart');
|
||||||
|
$session->db->write('delete from addressBook');
|
||||||
|
$session->db->write('delete from address');
|
||||||
|
|
||||||
|
$taxUser->delete;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue