webgui/lib/WebGUI/Shop/Ship.pm
2011-02-25 15:45:40 -06:00

307 lines
9.8 KiB
Perl

package WebGUI::Shop::Ship;
use strict;
use Moose;
use WebGUI::Exception;
use WebGUI::International;
use WebGUI::Pluggable;
use WebGUI::Shop::Admin;
use WebGUI::Shop::ShipDriver;
use Scalar::Util;
=head1 NAME
Package WebGUI::Shop::Ship
=head1 DESCRIPTION
This is the master class to manage ship drivers.
=head1 SYNOPSIS
use WebGUI::Shop::Ship;
=head1 METHODS
These subroutines are available from this package:
=cut
has session => (
is => 'ro',
required => 1,
);
around BUILDARGS => sub {
my $orig = shift;
my $className = shift;
##Original arguments start here.
my $protoSession = $_[0];
if (blessed $protoSession && $protoSession->isa('WebGUI::Session')) {
return $className->$orig(session => $protoSession);
}
return $className->$orig(@_);
};
#-------------------------------------------------------------------
=head2 addShipper ( $class, $options )
The interface method for creating new, configured instances of ShipDriver. If the ShipperDriver throws an exception, it is propagated
back up to the top.
=head4 $class
The class of the new ShipDriver object to create.
=head4 $options
A list of properties to assign to this ShipperDriver. See C<definition> for details.
=cut
sub addShipper {
my $self = shift;
my $requestedClass = shift;
my $options = shift;
WebGUI::Error::InvalidParam->throw(error => q{Must provide a class to create an object})
unless defined $requestedClass;
WebGUI::Error::InvalidParam->throw(error => q{The requested class is not enabled in your WebGUI configuration file}, param => $requestedClass)
unless exists $self->getDrivers->{$requestedClass};
WebGUI::Error::InvalidParam->throw(error => q{You must pass a hashref of options to create a new ShipDriver object})
unless defined($options) and ref $options eq 'HASH' and scalar keys %{ $options };
my $driver = eval { WebGUI::Pluggable::instanciate($requestedClass, 'new', [ $self->session, $options ]) };
$driver->write;
return $driver;
}
#-------------------------------------------------------------------
=head2 getDrivers ( )
This method returns a hash reference of available shipping driver classes as keys with their human readable names as values, read from the WebGUI config file in the shippingDrivers directive.
=cut
sub getDrivers {
my $self = shift;
my %drivers = ();
foreach my $class (@{$self->session->config->get('shippingDrivers')}) {
$drivers{$class} = eval { WebGUI::Pluggable::instanciate($class, 'getName', [ $self->session ])};
}
return \%drivers;
}
#-------------------------------------------------------------------
=head2 getOptions ( $cart )
Returns a list of options for the user to ship, along with the cost of using each one. It is a hash of hashrefs,
with the key of the primary hash being the shipperId of the driver, and sub keys of label, price, and whether the
price actually exists, to tell the difference between 0 and unknown.
{
label => 'ShipDriver label',
price => \d+,
hasPrice => 1 || 0,
}
=head3 $cart
A WebGUI::Shop::Cart object. A WebGUI::Error::InvalidParam exception will be thrown if it doesn't get one.
=cut
sub getOptions {
my ($self, $cart) = @_;
WebGUI::Error::InvalidParam->throw(error => q{Need a cart.}) unless defined $cart and $cart->isa("WebGUI::Shop::Cart");
my $session = $cart->session;
my %options = ();
SHIPPER: foreach my $shipper (@{$self->getShippers()}) {
next SHIPPER unless $shipper->get('enabled');
next SHIPPER unless $shipper->canUse;
my ($price, $hasPrice);
if ($cart->get('shippingAddressId')) {
$price = eval { $shipper->calculate($cart) };
if (my $e = WebGUI::Error->caught()) {
$self->session->log->warn($e->error);
next SHIPPER;
}
$hasPrice = 1;
}
else {
$price = 0;
$hasPrice = 0;
}
$options{$shipper->getId} = {
label => $shipper->get("label"),
price => $price,
hasPrice => $hasPrice,
};
}
return \%options;
}
#-------------------------------------------------------------------
=head2 getShipper ( )
Looks up an existing ShipperDriver in the db by shipperId and returns
that object. If the ShipperDriver throws an exception, it is propagated
back up to the top.
=head3 id
The id of the shipper to instanciate.
=cut
sub getShipper {
my ($self, $shipperId) = @_;
my $session = $self->session;
WebGUI::Error::InvalidParam->throw(error => q{Must provide a shipperId})
unless defined $shipperId;
my $requestedClass = $session->db->quickScalar('select className from shipper where shipperId=?',[$shipperId]);
WebGUI::Error::ObjectNotFound->throw(error => q{shipperId not found in db}, id => $shipperId)
unless $requestedClass;
my $driver = eval { WebGUI::Pluggable::instanciate($requestedClass, 'new', [ $session, $shipperId ]) };
return $driver;
}
#-------------------------------------------------------------------
=head2 getShippers ( )
Returns an array ref of all shipping objects in the db.
=cut
sub getShippers {
my $self = shift;
my @drivers = ();
my $sth = $self->session->db->prepare('select shipperId from shipper');
$sth->execute();
SHIPPER: while (my $driver = $sth->hashRef()) {
my $shipper = $self->getShipper($driver->{shipperId});
next SHIPPER unless $shipper->canUse;
push @drivers, $shipper;
}
$sth->finish;
return \@drivers;
}
#-------------------------------------------------------------------
=head2 session ()
Returns a reference to the current session.
=cut
#-------------------------------------------------------------------
=head2 www_addDriver ()
Adds a ship driver to the shop, then displays it's edit screen.
=cut
sub www_addDriver {
my $self = shift;
my $form = $self->session->form;
WebGUI::Error::InvalidParam->throw(error => q{must have a form var called className with a driver class name }) if ($form->get("className") eq "");
my $shipper = $self->addShipper($form->get("className"), { $form->get("className")->getName($self->session), enabled=>0});
return $shipper->www_edit;
}
#-------------------------------------------------------------------
=head2 www_deleteDriver ()
Deletes a ship driver from the shop.
=cut
sub www_deleteDriver {
my $self = shift;
my $form = $self->session->form;
WebGUI::Error::InvalidParam->throw(error => q{must have a form var called driverId with guid }) if ($form->get("driverId") eq "");
$self->getShipper($form->get("driverId"))->delete;
return $self->www_manage;
}
#-------------------------------------------------------------------
=head2 www_do ( )
Let's ship drivers do method calls. Requires a driverId param in the post form vars which contains the id of the driver to load.
=cut
sub www_do {
my ($self) = @_;
my $form = $self->session->form;
WebGUI::Error::InvalidParam->throw(error => q{must have a form var called driverId with a driver id }) if ($form->get("driverId") eq "");
WebGUI::Error::InvalidParam->throw(error => q{must have a form var called do with a method name in the driver }) if ($form->get("do") eq "");
my $driver = $self->getShipper($form->get("driverId"));
my $output = undef;
my $method = "www_". ( $form->get("do"));
if ($driver->can($method)) {
$output = $driver->$method();
}
return $output;
}
#-------------------------------------------------------------------
=head2 www_manage ( )
The main management screen for shippers.
=cut
sub www_manage {
my ($self) = @_;
my $session = $self->session;
my $admin = WebGUI::Shop::Admin->new($session);
return $session->privilege->adminOnly() unless ($admin->canManage);
my $i18n = WebGUI::International->new($session, "Shop");
my $output = WebGUI::Form::formHeader($session)
.WebGUI::Form::hidden($session, {name=>"shop", value=>"ship"})
.WebGUI::Form::hidden($session, {name=>"method", value=>"addDriver"})
.WebGUI::Form::selectBox($session, {name=>"className", options=>$self->getDrivers})
.WebGUI::Form::submit($session, {name => 'add', value=>$i18n->get("add shipper")})
.WebGUI::Form::formFooter($session);
my $hasShipper = 0;
foreach my $shipper (@{$self->getShippers}) {
$output .= '<div style="clear: both;">'
.WebGUI::Form::formHeader($session, {extras=>'style="float: left;"'})
.WebGUI::Form::hidden($session, {name=>"shop", value=>"ship"})
.WebGUI::Form::hidden($session, {name=>"method", value=>"deleteDriver"})
.WebGUI::Form::hidden($session, {name=>"driverId", value=>$shipper->getId})
.WebGUI::Form::submit($session, {name => 'delete', value=>$i18n->get("delete"), extras=>'class="backwardButton"'})
.WebGUI::Form::formFooter($session)
.WebGUI::Form::formHeader($session, {extras=>'style="float: left;"'})
.WebGUI::Form::hidden($session, {name=>"shop", value=>"ship"})
.WebGUI::Form::hidden($session, {name=>"method", value=>"do"})
.WebGUI::Form::hidden($session, {name=>"do", value=>"edit"})
.WebGUI::Form::hidden($session, {name=>"driverId", value=>$shipper->getId})
.WebGUI::Form::submit($session, {name => 'edit', value=>$i18n->get("edit"), extras=>'class="normalButton"'})
.WebGUI::Form::formFooter($session)
.' '
.$shipper->get("label")
.'</div>';
$hasShipper = 1;
}
my $console = $admin->getAdminConsole;
if (! $hasShipper) {
my $noShipper = $i18n->get('No shippers');
$output = qq|<div class="error">$noShipper</div>\n| . $output;
}
return $console->render($output, $i18n->get("shipping methods"));
}
1;