package WebGUI::Shop::TaxDriver; =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 =head1 NAME Package WebGUI::Shop::TaxDriver =head1 DESCRIPTION This package is the base class for all modules which implement a tax driver. =head1 SYNOPSIS use WebGUI::Shop::TaxDriver; my $taxDriver = WebGUI::Shop::TaxDriver->new($session); =head1 METHODS These subroutines are available from this package: =cut use strict; use Class::InsideOut qw{ :std }; use JSON qw{ from_json to_json }; =head1 NAME Package WebGUI::Shop::TaxDriver =head1 DESCRIPTION Base class for all modules which do tax calculations in the Shop. =head1 SYNOPSIS use base WebGUI::Shop::TaxDriver; my $driver = WebGUI::Shop::TaxDriver->new($session); =head1 METHODS These subroutines are available from this package: =cut readonly session => my %session; readonly messages => my %messages; private options => my %options; =head2 appendCartItemVars ( var, cartItem ) Adds tax driver specific template variables for the given cart item to the supplied hashref. =head3 var The template variable hash ref to add the tax vars to. =head3 cartItem The instanstance of WebGUI::Shop::CartItem to add the vars for. =cut sub appendCartItemVars { my $self = shift; my $var = shift; my $item = shift; WebGUI::Error::InvalidParam->throw( 'Must supply a hash ref' ) unless $var && ref $var eq 'HASH'; WebGUI::Error::InvalidObject->throw( expected => 'WebGUI::Shop::CartItem', got => ref $item, error => 'Must pass a cart item' ) unless $item && $item->isa( 'WebGUI::Shop::CartItem' ); my $sku = $item->getSku; my $address = eval { $item->getShippingAddress }; my $taxRate = $self->getTaxRate( $sku, $address ); my $quantity = $item->get( 'quantity' ); my $price = $sku->getPrice; my $tax = $price * $taxRate / 100; $var->{ taxRate } = $taxRate; $var->{ taxAmount } = $item->cart->formatCurrency( $tax ); $var->{ pricePlusTax } = $item->cart->formatCurrency( $price + $tax ); $var->{ extendedPricePlusTax } = $item->cart->formatCurrency( $quantity * ( $price + $tax ) ); } #----------------------------------------------------------- =head2 canManage ( ) Returns true if the current user can manage taxes. =cut sub canManage { my $self = shift; my $admin = WebGUI::Shop::Admin->new( $self->session ); return $admin->canManage; } #----------------------------------------------------------- =head2 className { Returns the class name of your plugin. You must overload this method in you own plugin. =cut sub className { my $self = shift; $self->session->log->fatal( "Tax plugin (".$self->className.") is required to overload the className method" ); return 'WebGUI::Shop::TaxDriver'; } #----------------------------------------------------------- =head2 get ( [ property ] ) Returns the value of the requested configuration property. Returns a hash ref of all property/value pairs when no specific property is passed. =head3 property The property whose value should be returned. =cut sub get { my $self = shift; my $key = shift; my $options = $options{ id $self }; # Return safe copy of options hash if no key is passed. return { %{ $options } } unless $key; # Return option if key is passed. return $options->{ $key } if exists $options->{ $key }; # Key does not exist. $self->session->log->warn( "Non-existant option [$key] was queried by tax plugin $self" ); return undef; } #----------------------------------------------------------- =head2 getConfigurationScreen ( ) Returns the configuration screen that contains the configuration options for this plugin in the admin console. =cut sub getConfigurationScreen { return 'This plugin has no configuration options'; } #----------------------------------------------------------- =head2 getTaxRate ( sku, [ address ] ) Returns the tax rate in percents (eg. 19 for a rate of 19%) for the given sku and shipping address. Your tax driver must overload this method. Note that address is optional and that it's up to your plugin to handle that case. =head3 sku The sku for which the tax rate must be determined. Should be a WebGUI::Asset::Sku::* instance. =head3 address Optional, the shipping address for which to calculate the tax. Must be an instance of WebGUI::Shop::Address. =cut sub getTaxRate { my $self = shift; $self->session->log->fatal("Tax plugin ". $self->className ." is required to overload getTaxRate"); } #----------------------------------------------------------- =head2 getTransactionTaxData ( sku, address ) Returns a hashref containing tax information that should be stored along with transaction items. =head3 sku The sku belonging to the transaction item. =head3 address The address belonging to the transaction item. =cut sub getTransactionTaxData { my $self = shift; my $config = { className => $self->className, }; return $config; } #----------------------------------------------------------- =head2 getUserScreen ( ) Returns the screen for entering per user configuration for this tax driver. =cut sub getUserScreen { return 'There are no tax options to configure.'; } #----------------------------------------------------------- =head2 skuFormDefinition ( ) Returns a hash ref containing the form definition for the per sku options for this tax driver. =cut sub skuFormDefinition { return {}; } #------------------------------------------------------------------- =head2 new ( $session ) Constructor =head3 session Instanciated WebGUI::Session 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; my $id = id $self; $session{ $id } = $session; $messages{ $id } = []; # Load plugin configuration my $optionsJSON = $session->db->quickScalar( 'select options from taxDriver where className=?', [ $self->className, ] ); $options{ $id } = $optionsJSON ? from_json( $optionsJSON ) : {}; return $self; } #------------------------------------------------------------------- =head2 processSkuFormPost ( ) Processes the form parameters defined in the skuFormDefinition method and returns a hash ref containing the result. =cut sub processSkuFormPost { my $self = shift; my $form = $self->session->form; my $configuration = {}; my $definition = $self->skuFormDefinition; foreach my $fieldName ( keys %{ $definition } ) { my ($fieldType, $defaultValue) = @{ $definition->{ $fieldName } }{ qw{ fieldType defaultValue } }; $configuration->{ $fieldName } = $form->process( $fieldName, $fieldType, $defaultValue ); } return $configuration; } #----------------------------------------------------------- =head2 update ( properties ) Updates the properties of the tax driver according to those passed. =head3 properties Hash ref containing the properties to set. =cut sub update { my $self = shift; my $update = shift; my $db = $self->session->db; # update local options hash $options{ id $self } = { %{ $options{ id $self } }, %{ $update } }; # Persist to db $db->write( 'replace into taxDriver (className, options) values (?,?)', [ $self->className, to_json( $options{ id $self } ), ] ); } 1;