329 lines
10 KiB
Perl
329 lines
10 KiB
Perl
package WebGUI::Shop::Tax;
|
|
|
|
=head1 LEGAL
|
|
|
|
-------------------------------------------------------------------
|
|
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
|
|
-------------------------------------------------------------------
|
|
|
|
=cut
|
|
|
|
use strict;
|
|
|
|
use Class::InsideOut qw{ :std };
|
|
use WebGUI::Exception::Shop;
|
|
use WebGUI::Shop::Admin;
|
|
use WebGUI::Pluggable;
|
|
use List::Util qw{sum};
|
|
|
|
=head1 NAME
|
|
|
|
Package WebGUI::Shop::Tax
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
This package manages tax information, and calculates taxes on a shopping cart. It isn't a classic object
|
|
in that the only data it contains is a WebGUI::Session object, but it does provide several methods for
|
|
handling the information in the tax tables.
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
use WebGUI::Shop::Tax;
|
|
|
|
my $tax = WebGUI::Shop::Tax->new($session);
|
|
|
|
=head1 METHODS
|
|
|
|
These subroutines are available from this package:
|
|
|
|
=cut
|
|
|
|
readonly session => my %session;
|
|
|
|
##-------------------------------------------------------------------
|
|
#sub appendSkuForm {
|
|
# my $self = shift;
|
|
# my $assetId = shift;
|
|
# my $form = shift;
|
|
# my $db = $self->session->db;
|
|
#
|
|
# my $values = $db->buildHashRef( 'select name, value from skuTaxConfiguration where assetId=?', [
|
|
# $assetId,
|
|
# ] );
|
|
#
|
|
# my $definition = $self->getDriver->skuFormDefinition;
|
|
# foreach my $fieldName (keys %{ $definition }) {
|
|
# $form->dynamicField(
|
|
# %{ $definition->{ $fieldName } },
|
|
# name => $fieldName,
|
|
# value => $values->{ $fieldName },
|
|
# );
|
|
# }
|
|
#}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 calculate ( $cart )
|
|
|
|
Calculate the tax for the contents of the cart.
|
|
|
|
=head3 cart
|
|
|
|
An instanciated cart object.
|
|
|
|
=cut
|
|
|
|
sub calculate {
|
|
my $self = shift;
|
|
my $cart = shift;
|
|
WebGUI::Error::InvalidParam->throw(error => 'Must pass in a WebGUI::Shop::Cart object')
|
|
unless ref($cart) eq 'WebGUI::Shop::Cart';
|
|
my $book = $cart->getAddressBook;
|
|
|
|
# Fetch the default shipping address for each item in the cart that hasn't set its own.
|
|
my $shippingAddress = $book->getAddress( $cart->get('shippingAddressId') ) if $cart->get('shippingAddressId');
|
|
|
|
my $driver = $self->getDriver;
|
|
my $tax = 0;
|
|
|
|
foreach my $item (@{ $cart->getItems }) {
|
|
my $sku = $item->getSku;
|
|
my $quantity = $item->get('quantity');
|
|
my $unitPrice = $sku->getPrice;
|
|
|
|
# Check if this cart item overrides the shipping address. If it doesn't, use the default shipping address.
|
|
my $itemAddress = $shippingAddress;
|
|
if (defined $item->get('shippingAddressId')) {
|
|
$itemAddress = $book->getAddress($item->get('shippingAddressId'));
|
|
}
|
|
|
|
my $taxRate = $driver->getTaxRate( $sku, $itemAddress );
|
|
|
|
# Calc the monetary tax for the given quantity of this item and add it to the total.
|
|
$tax += $unitPrice * $quantity * $taxRate / 100;
|
|
}
|
|
|
|
return $tax;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getDriver ( [ $session ] )
|
|
|
|
Return an instance of the enabled tax driver. This method can be invoked both as class or instance method. If you
|
|
invoke this method as a class method you must pass a WebGUI::Session object.
|
|
|
|
=head3 session
|
|
|
|
A WebGUI::Session object. Required in class context, optional in instance context.
|
|
|
|
=cut
|
|
|
|
sub getDriver {
|
|
my $self = shift;
|
|
my $session = shift || $self->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 $driver = eval {
|
|
WebGUI::Pluggable::instanciate( $className, 'new', [ $session ] );
|
|
};
|
|
if ($@) {
|
|
$session->log->error("Can't instanciate tax driver [$className] because $@");
|
|
return undef;
|
|
}
|
|
|
|
return $driver;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 new ( $session )
|
|
|
|
Constructor for the WebGUI::Shop::Tax. Returns a WebGUI::Shop::Tax object.
|
|
|
|
=cut
|
|
|
|
sub new {
|
|
my $class = 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 = {};
|
|
bless $self, $class;
|
|
register $self;
|
|
$session{ id $self } = $session;
|
|
return $self;
|
|
}
|
|
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 session ( )
|
|
|
|
Accessor for the session object. Returns the session object.
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 www_do ( )
|
|
|
|
Allows tax drivers to define their own www_ methods. Pass the www_ method that must be executed in the 'do' form
|
|
var.
|
|
|
|
=cut
|
|
|
|
sub www_do {
|
|
my $self = shift;
|
|
my $session = $self->session;
|
|
|
|
my $taxDriver = $self->getDriver;
|
|
my $method = 'www_' . $session->form->process( 'do' );
|
|
|
|
return "Invalid method name" unless $method =~ m{ ^[a-zA-Z0-9_]+$ }xms;
|
|
|
|
if ( $taxDriver->can( $method ) ) {
|
|
my $output = eval{ $taxDriver->$method };
|
|
|
|
if ($@) {
|
|
$session->log->error("An error occurred while executing method [$method] on active tax driver: $@");
|
|
return "An error occurred while executing a method on a tax driver. Please consult the webgui log.";
|
|
}
|
|
else {
|
|
return $output || $self->www_manage;
|
|
}
|
|
}
|
|
|
|
return "Cannot call method [$method] on active tax driver.";
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 www_manage ( $status_message )
|
|
|
|
User interface to manage taxes. Provides a list of current taxes, and forms for adding
|
|
new tax info, exporting and importing sets of taxes, and deleting individual tax data.
|
|
|
|
=head3 $status_message
|
|
|
|
A message to display to the user. This is usually a problem that was found during
|
|
import.
|
|
|
|
=cut
|
|
|
|
sub www_manage {
|
|
my $self = shift;
|
|
my $status_message = shift;
|
|
my $session = $self->session;
|
|
my $admin = WebGUI::Shop::Admin->new( $session );
|
|
|
|
return $session->privilege->insufficient unless $admin->canManage;
|
|
|
|
my ($style, $url) = $session->quick( qw(style url) );
|
|
my $i18n = WebGUI::International->new( $session, 'Tax' );
|
|
|
|
my $activePlugin = $session->setting->get( 'activeTaxPlugin' );
|
|
my $plugins = $session->config->get( 'taxDrivers' );
|
|
my %options = map { $_ => $_ } @{ $plugins };
|
|
|
|
my $pluginSwitcher =
|
|
'<fieldset><legend>'.$i18n->get('Active tax plugin') . '</legend>'
|
|
. WebGUI::Form::formHeader( $session )
|
|
. WebGUI::Form::hidden( $session, { name => 'shop', value => 'tax' } )
|
|
. WebGUI::Form::hidden( $session, { name => 'method', value => 'setActivePlugin' } )
|
|
. $i18n->get('Active tax plugin') . ' '
|
|
. WebGUI::Form::selectBox( $session, { name => 'className', value => $activePlugin, options => \%options } )
|
|
. WebGUI::Form::submit( $session, { value => $i18n->get('Switch') } )
|
|
. WebGUI::Form::formFooter( $session )
|
|
. '</fieldset>'
|
|
;
|
|
|
|
# my $output;
|
|
# if ($status_message) {
|
|
# $output = qq{<div class="error">$status_message</div>};
|
|
# }
|
|
|
|
my $taxDriver = $self->getDriver;
|
|
my $output =
|
|
$pluginSwitcher
|
|
. '<fieldset><legend>Plugin configuration</legend>'
|
|
. $taxDriver->getConfigurationScreen
|
|
. '</fieldset>'
|
|
;
|
|
|
|
return $admin->getAdminConsole->render($output, $i18n->get('taxes', 'Shop'));
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 www_setActivePlugin ( )
|
|
|
|
Displays a warning that informs users that they're about to change the active taxing plugin. Includes a confirm and
|
|
cancel button.
|
|
|
|
=cut
|
|
|
|
sub www_setActivePlugin {
|
|
my $self = shift;
|
|
my $session = $self->session;
|
|
my $admin = WebGUI::Shop::Admin->new( $session );
|
|
|
|
return $session->privilege->insufficient unless $admin->canManage;
|
|
|
|
my $i18n = WebGUI::International->new( $session, 'Tax' );
|
|
my $message = $i18n->get('Stern tax warning');
|
|
|
|
my $proceedForm =
|
|
WebGUI::Form::formHeader( $session )
|
|
. WebGUI::Form::hidden( $session, { name => 'shop', value => 'tax' } )
|
|
. WebGUI::Form::hidden( $session, { name => 'method', value => 'setActivePluginConfirm' } )
|
|
. WebGUI::Form::hidden( $session, { name => 'className', value => $session->form->process('className') } )
|
|
. WebGUI::Form::submit( $session, { value => $i18n->get('Proceed') } )
|
|
. WebGUI::Form::formFooter( $session );
|
|
|
|
my $cancelForm =
|
|
WebGUI::Form::formHeader( $session )
|
|
. WebGUI::Form::hidden( $session, { name => 'shop', value => 'tax' } )
|
|
. WebGUI::Form::hidden( $session, { name => 'method', value => 'manage' } )
|
|
. WebGUI::Form::submit( $session, { value => $i18n->get('cancel','WebGUI'), extras => 'class="backwardButton"' } )
|
|
. WebGUI::Form::formFooter( $session );
|
|
|
|
my $output = $message . $proceedForm . $cancelForm;
|
|
return $admin->getAdminConsole->render( $output, $i18n->get('Switch tax plugin') );
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 www_setActivePluginConfirm ( )
|
|
|
|
Actually changes the active tax driver.
|
|
|
|
=cut
|
|
|
|
sub www_setActivePluginConfirm {
|
|
my $self = shift;
|
|
my $session = $self->session;
|
|
my $admin = WebGUI::Shop::Admin->new( $session );
|
|
|
|
return $session->privilege->insufficient unless $admin->canManage;
|
|
|
|
my $className = $session->form->process( 'className', 'className' );
|
|
#### TODO: Check aginst list of available plugins.
|
|
$session->setting->set( 'activeTaxPlugin', $className );
|
|
|
|
return $self->www_manage;
|
|
}
|
|
|
|
1;
|