Add USPS Shipping Driver with tests, and i18n.
Change the Ship, Cart to do exception handling when calling a shipping driver, as that's the message passing interface between the modules. Add a noFormProcess field property that is recognized by processPropertiesFromFormPost.
This commit is contained in:
parent
909c8f62ae
commit
cbdd6077d5
10 changed files with 1209 additions and 18 deletions
|
|
@ -21,6 +21,7 @@
|
|||
transactions. (Martin Kamerbeek / Oqapi )
|
||||
- Added better Survey Expression Engine validation warnings
|
||||
- added #9203: Survey Visualization
|
||||
- Added: United States Postal Service Shipping Driver.
|
||||
|
||||
7.7.5
|
||||
- Adding StoryManager.
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ addTemplateAttachmentsTable($session);
|
|||
revertUsePacked( $session );
|
||||
fixDefaultPostReceived($session);
|
||||
addEuVatDbColumns( $session );
|
||||
addShippingDrivers( $session );
|
||||
addTransactionTaxColumns( $session );
|
||||
|
||||
finish($session);
|
||||
|
|
@ -91,6 +92,15 @@ EOSQL
|
|||
print "DONE!\n" unless $quiet;
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Describe what our function does
|
||||
sub addShippingDrivers {
|
||||
my $session = shift;
|
||||
print "\tAdding columns for improved VAT number checking..." unless $quiet;
|
||||
$session->config->addToArray('shippingDrivers', 'WebGUI::Shop::ShipDriver::USPS');
|
||||
print "DONE!\n" unless $quiet;
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
sub addEuVatDbColumns {
|
||||
my $session = shift;
|
||||
|
|
|
|||
|
|
@ -183,7 +183,8 @@
|
|||
# available for configuration on the site.
|
||||
|
||||
"shippingDrivers" : [
|
||||
"WebGUI::Shop::ShipDriver::FlatRate"
|
||||
"WebGUI::Shop::ShipDriver::FlatRate",
|
||||
"WebGUI::Shop::ShipDriver::USPS"
|
||||
],
|
||||
|
||||
# Specify the list of template parsers available in the system.
|
||||
|
|
|
|||
|
|
@ -20,7 +20,12 @@ use Exception::Class (
|
|||
|
||||
'WebGUI::Error::Shop::MaxOfItemInCartReached' => {
|
||||
description => "Some items restrict how many you can put into your cart.",
|
||||
},
|
||||
},
|
||||
|
||||
'WebGUI::Error::Shop::RemoteShippingRate' => {
|
||||
description => "Errors during the remote rate lookups.",
|
||||
},
|
||||
|
||||
);
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -510,9 +510,14 @@ sub readyForCheckout {
|
|||
return 0 if ($self->hasMixedItems);
|
||||
|
||||
# Check minimum cart checkout requirement
|
||||
my $total = eval { $self->calculateTotal };
|
||||
if (my $e = WebGUI::Error->caught) {
|
||||
$error{id $self} = $e->error;
|
||||
return 0;
|
||||
}
|
||||
my $requiredAmount = $self->session->setting->get( 'shopCartCheckoutMinimum' );
|
||||
if ( $requiredAmount > 0 ) {
|
||||
return 0 if $self->calculateTotal < $requiredAmount;
|
||||
return 0 if $total < $requiredAmount;
|
||||
}
|
||||
|
||||
# All checks passed so return true
|
||||
|
|
|
|||
|
|
@ -97,12 +97,17 @@ sub getOptions {
|
|||
WebGUI::Error::InvalidParam->throw(error => q{Need a cart.}) unless defined $cart and $cart->isa("WebGUI::Shop::Cart");
|
||||
my $session = $cart->session;
|
||||
my %options = ();
|
||||
foreach my $shipper (@{$self->getShippers()}) {
|
||||
next unless $shipper->get('enabled');
|
||||
SHIPPER: foreach my $shipper (@{$self->getShippers()}) {
|
||||
next SHIPPER unless $shipper->get('enabled');
|
||||
my $price = eval { $shipper->calculate($cart) };
|
||||
if (my $e = WebGUI::Error->caught()) {
|
||||
$self->session->log->warn($e->error);
|
||||
next SHIPPER;
|
||||
}
|
||||
$options{$shipper->getId} = {
|
||||
label => $shipper->get("label"),
|
||||
price => $shipper->calculate($cart),
|
||||
};
|
||||
price => $price,
|
||||
};
|
||||
}
|
||||
return \%options;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ These subroutines are available from this package:
|
|||
=cut
|
||||
|
||||
readonly session => my %session;
|
||||
private options => my %options;
|
||||
private shipperId => my %shipperId;
|
||||
private options => my %options;
|
||||
private shipperId => my %shipperId;
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
|
|
@ -88,6 +88,9 @@ This subroutine returns an arrayref of hashrefs, used to validate data put into
|
|||
the object by the user, and to automatically generate the edit form to show
|
||||
the user.
|
||||
|
||||
The optional hash key noFormProcess may be added to any field definition.
|
||||
This will prevent that field from being processed by processPropertiesFromFormPost.
|
||||
|
||||
=cut
|
||||
|
||||
sub definition {
|
||||
|
|
@ -261,17 +264,20 @@ Updates ship driver with data from Form.
|
|||
=cut
|
||||
|
||||
sub processPropertiesFromFormPost {
|
||||
my $self = shift;
|
||||
my $self = shift;
|
||||
my $session = $self->session;
|
||||
my $form = $session->form;
|
||||
my %properties;
|
||||
my $fullDefinition = $self->definition($self->session);
|
||||
my $fullDefinition = $self->definition($session);
|
||||
foreach my $definition (@{$fullDefinition}) {
|
||||
foreach my $property (keys %{$definition->{properties}}) {
|
||||
$properties{$property} = $self->session->form->process(
|
||||
$property,
|
||||
$definition->{properties}{$property}{fieldType},
|
||||
$definition->{properties}{$property}{defaultValue}
|
||||
);
|
||||
}
|
||||
PROPERTY: foreach my $property (keys %{$definition->{properties}}) {
|
||||
next PROPERTY if $definition->{properties}{$property}->{noFormProcess};
|
||||
$properties{$property} = $form->process(
|
||||
$property,
|
||||
$definition->{properties}{$property}{fieldType},
|
||||
$definition->{properties}{$property}{defaultValue}
|
||||
);
|
||||
}
|
||||
}
|
||||
$properties{title} = $fullDefinition->[0]{name} if ($properties{title} eq "" || lc($properties{title}) eq "untitled");
|
||||
$self->update(\%properties);
|
||||
|
|
|
|||
347
lib/WebGUI/Shop/ShipDriver/USPS.pm
Normal file
347
lib/WebGUI/Shop/ShipDriver/USPS.pm
Normal file
|
|
@ -0,0 +1,347 @@
|
|||
package WebGUI::Shop::ShipDriver::USPS;
|
||||
|
||||
use strict;
|
||||
use base qw/WebGUI::Shop::ShipDriver/;
|
||||
use WebGUI::Exception;
|
||||
use XML::Simple;
|
||||
use LWP;
|
||||
use Tie::IxHash;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Package WebGUI::Shop::ShipDriver::USPS
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Shipping driver for the United States Postal Service.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
See the master class, WebGUI::Shop::ShipDriver for information about
|
||||
base methods. These methods are customized in this class:
|
||||
|
||||
=cut
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 buildXML ( $cart, @packages )
|
||||
|
||||
Returns XML for submitting to the US Postal Service servers
|
||||
|
||||
=head3 $cart
|
||||
|
||||
A WebGUI::Shop::Cart object. This allows us access to the user's
|
||||
address book
|
||||
|
||||
=head3 @packages
|
||||
|
||||
An array of array references. Each array element is 1 set of items. The
|
||||
quantity of items will vary in each set. If the quantity of an item
|
||||
is more than 1, then we will check for shipping 1 item, and multiple the
|
||||
result by the quantity, rather than doing several identical checks.
|
||||
|
||||
=cut
|
||||
|
||||
sub buildXML {
|
||||
my ($self, $cart, @packages) = @_;
|
||||
tie my %xmlHash, 'Tie::IxHash';
|
||||
%xmlHash = ( RateV3Request => {}, );
|
||||
my $xmlTop = $xmlHash{RateV3Request};
|
||||
$xmlTop->{USERID} = $self->get('userId');
|
||||
$xmlTop->{Package} = [];
|
||||
##Do a request for each package.
|
||||
my $packageIndex;
|
||||
PACKAGE: for(my $packageIndex = 0; $packageIndex < scalar @packages; $packageIndex++) {
|
||||
my $package = $packages[$packageIndex];
|
||||
next PACKAGE unless scalar @{ $package };
|
||||
tie my %packageData, 'Tie::IxHash';
|
||||
my $weight = 0;
|
||||
foreach my $item (@{ $package }) {
|
||||
my $sku = $item->getSku;
|
||||
my $itemWeight = $sku->getWeight();
|
||||
##Items that ship separately with a quantity > 1 are rate estimated as 1 item and then the
|
||||
##shipping cost is multiplied by the quantity.
|
||||
if (! $sku->shipsSeparately ) {
|
||||
$itemWeight *= $item->get('quantity');
|
||||
}
|
||||
$weight += $itemWeight;
|
||||
}
|
||||
my $pounds = int($weight);
|
||||
my $ounces = int(16 * ($weight - $pounds));
|
||||
my $destination = $package->[0]->getShippingAddress;
|
||||
my $destZipCode = $destination->get('code');
|
||||
$packageData{ID} = $packageIndex;
|
||||
$packageData{Service} = [ $self->get('shipType') ];
|
||||
$packageData{ZipOrigination} = [ $self->get('sourceZip') ];
|
||||
$packageData{ZipDestination} = [ $destZipCode ];
|
||||
$packageData{Pounds} = [ $pounds ];
|
||||
$packageData{Ounces} = [ $ounces ];
|
||||
if ($self->get('shipType') eq 'PRIORITY') {
|
||||
$packageData{Container} = [ 'FLAT RATE BOX' ];
|
||||
}
|
||||
$packageData{Size} = [ 'REGULAR' ];
|
||||
$packageData{Machinable} = [ 'true' ];
|
||||
push @{ $xmlTop->{Package} }, \%packageData;
|
||||
}
|
||||
my $xml = XMLout(\%xmlHash,
|
||||
KeepRoot => 1,
|
||||
NoSort => 1,
|
||||
NoIndent => 1,
|
||||
KeyAttr => {
|
||||
Package => 'ID',
|
||||
},
|
||||
SuppressEmpty => 0,
|
||||
);
|
||||
return $xml;
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 calculate ( $cart )
|
||||
|
||||
Returns a shipping price.
|
||||
|
||||
=head3 $cart
|
||||
|
||||
A WebGUI::Shop::Cart object. The contents of the cart are analyzed to calculate
|
||||
the shipping costs. If no items in the cart require shipping, then no shipping
|
||||
costs are assessed.
|
||||
|
||||
=cut
|
||||
|
||||
sub calculate {
|
||||
my ($self, $cart) = @_;
|
||||
if (! $self->get('sourceZip')) {
|
||||
WebGUI::Error::InvalidParam->throw(error => q{Driver configured without a source zipcode.});
|
||||
}
|
||||
if (! $self->get('userId')) {
|
||||
WebGUI::Error::InvalidParam->throw(error => q{Driver configured without a USPS userId.});
|
||||
}
|
||||
my $cost = 0;
|
||||
##Sort the items into shippable bundles.
|
||||
my @shippableUnits = $self->_getShippableUnits($cart);
|
||||
my $packageCount = scalar @shippableUnits;
|
||||
if ($packageCount > 25) {
|
||||
WebGUI::Error::InvalidParam->throw(error => q{Cannot do USPS lookups for more than 25 items.});
|
||||
}
|
||||
my $anyShippable = $packageCount > 0 ? 1 : 0;
|
||||
return $cost unless $anyShippable;
|
||||
#$cost = scalar @shippableUnits * $self->get('flatFee');
|
||||
##Build XML ($cart, @shippableUnits)
|
||||
my $xml = $self->buildXML($cart, @shippableUnits);
|
||||
##Do request ($xml)
|
||||
my $response = $self->_doXmlRequest($xml);
|
||||
##Error handling
|
||||
if (! $response->is_success) {
|
||||
WebGUI::Error::RemoteShippingRate->throw(error => 'Problem connecting to USPS Web Tools: '. $response->status_line);
|
||||
}
|
||||
my $returnedXML = $response->content;
|
||||
my $xmlData = XMLin($returnedXML, ForceArray => [qw/Package/]);
|
||||
if (exists $xmlData->{Error}) {
|
||||
WebGUI::Error::RemoteShippingRate->throw(error => 'Problem with USPS Web Tools XML: '. $xmlData->{Description});
|
||||
}
|
||||
##Summarize costs from returned data
|
||||
$cost = $self->_calculateFromXML($xmlData, @shippableUnits);
|
||||
return $cost;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 _calculateFromXML ( $xmlData, @shippableUnits )
|
||||
|
||||
Takes data from the USPS and returns the calculated shipping price.
|
||||
|
||||
=head3 $xmlData
|
||||
|
||||
Processed XML data from an XML rate request, processed in perl data structure. The data is expected to
|
||||
have this structure:
|
||||
|
||||
{
|
||||
Package => [
|
||||
{
|
||||
ID => 0,
|
||||
Postage => {
|
||||
Rate => some_number
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
=head3 @shippableUnits
|
||||
|
||||
The set of shippable units, which are required to do quantity lookups.
|
||||
|
||||
=cut
|
||||
|
||||
sub _calculateFromXML {
|
||||
my ($self, $xmlData, @shippableUnits) = @_;
|
||||
my $cost = 0;
|
||||
foreach my $package (@{ $xmlData->{Package} }) {
|
||||
my $id = $package->{ID};
|
||||
my $rate = $package->{Postage}->{Rate};
|
||||
##Error check for invalid index
|
||||
if ($id < 0 || $id > $#shippableUnits) {
|
||||
WebGUI::Error::RemoteShippingRate->throw(error => "Illegal package index returned by USPS: $id");
|
||||
}
|
||||
my $unit = $shippableUnits[$id];
|
||||
if ($unit->[0]->getSku->shipsSeparately) {
|
||||
##This is a single item due to ships separately. Since in reality there will be
|
||||
## N things being shipped, multiply the rate by the quantity.
|
||||
$cost += $rate * $unit->[0]->get('quantity');
|
||||
}
|
||||
else {
|
||||
##This is a loose bundle of items, all shipped together
|
||||
$cost += $rate;
|
||||
}
|
||||
}
|
||||
return $cost;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 definition ( $session )
|
||||
|
||||
This subroutine returns an arrayref of hashrefs, used to validate data put into
|
||||
the object by the user, and to automatically generate the edit form to show
|
||||
the user.
|
||||
|
||||
=cut
|
||||
|
||||
sub definition {
|
||||
my $class = shift;
|
||||
my $session = shift;
|
||||
WebGUI::Error::InvalidParam->throw(error => q{Must provide a session variable})
|
||||
unless ref $session eq 'WebGUI::Session';
|
||||
my $definition = shift || [];
|
||||
my $i18n = WebGUI::International->new($session, 'ShipDriver_USPS');
|
||||
tie my %shippingTypes, 'Tie::IxHash';
|
||||
##Note, these keys are required XML keywords in the USPS XML API.
|
||||
$shippingTypes{'PRIORITY'} = $i18n->get('priority');
|
||||
$shippingTypes{'EXPRESS' } = $i18n->get('express');
|
||||
$shippingTypes{'PARCEL' } = $i18n->get('parcel post');
|
||||
tie my %fields, 'Tie::IxHash';
|
||||
%fields = (
|
||||
instructions => {
|
||||
fieldType => 'readOnly',
|
||||
label => $i18n->get('instructions'),
|
||||
defaultValue => $i18n->get('usps instructions'),
|
||||
noFormProcess => 1,
|
||||
},
|
||||
userId => {
|
||||
fieldType => 'text',
|
||||
label => $i18n->get('userid'),
|
||||
hoverHelp => $i18n->get('userid help'),
|
||||
defaultValue => '',
|
||||
},
|
||||
password => {
|
||||
fieldType => 'password',
|
||||
label => $i18n->get('password'),
|
||||
hoverHelp => $i18n->get('password help'),
|
||||
defaultValue => '',
|
||||
},
|
||||
sourceZip => {
|
||||
fieldType => 'zipcode',
|
||||
label => $i18n->get('source zipcode'),
|
||||
hoverHelp => $i18n->get('source zipcode help'),
|
||||
defaultValue => '',
|
||||
},
|
||||
shipType => {
|
||||
fieldType => 'selectBox',
|
||||
label => $i18n->get('ship type'),
|
||||
hoverHelp => $i18n->get('ship type help'),
|
||||
options => \%shippingTypes,
|
||||
defaultValue => 'PARCEL',
|
||||
},
|
||||
##Note, if a flat fee is added to this driver, then according to the license
|
||||
##terms the website must display a note to the user (shop customer) that additional
|
||||
##fees have been added.
|
||||
# flatFee => {
|
||||
# fieldType => 'float',
|
||||
# label => $i18n->get('flatFee'),
|
||||
# hoverHelp => $i18n->get('flatFee help'),
|
||||
# defaultValue => 0,
|
||||
# },
|
||||
);
|
||||
my %properties = (
|
||||
name => 'U.S. Postal Service',
|
||||
properties => \%fields,
|
||||
);
|
||||
push @{ $definition }, \%properties;
|
||||
return $class->SUPER::definition($session, $definition);
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 _doXmlRequest ( $xml )
|
||||
|
||||
Contact the USPS website and submit the XML for a shipping rate lookup.
|
||||
Returns a LWP::UserAgent response object.
|
||||
|
||||
=head3 $xml
|
||||
|
||||
XML to send. It has some very high standards, including XML components in
|
||||
the right order and sets of allowed tags.
|
||||
|
||||
=cut
|
||||
|
||||
sub _doXmlRequest {
|
||||
my ($self, $xml) = @_;
|
||||
my $userAgent = LWP::UserAgent->new;
|
||||
$userAgent->env_proxy;
|
||||
$userAgent->agent('WebGUI');
|
||||
my $url = 'http://production.shippingapis.com/ShippingAPI.dll?API=RateV3&XML=';
|
||||
$url .= $xml;
|
||||
my $request = HTTP::Request->new(GET => $url);
|
||||
my $response = $userAgent->request($request);
|
||||
return $response;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
=head2 _getShippableUnits ( $cart )
|
||||
|
||||
This is a private method.
|
||||
|
||||
Sorts items into the cart by how they must be shipped, together, separate,
|
||||
etc. Returns an array of array references of cart items grouped by
|
||||
whether or not they ship separately, and then sorted by destination
|
||||
zip code.
|
||||
|
||||
If an item in the cart must be shipped separately, but has a quantity greater
|
||||
than 1, then for the purposes of looking up shipping costs it is returned
|
||||
as 1 bundle, since the total cost can now be calculated by multiplying the
|
||||
quantity together with the cost for a single unit.
|
||||
|
||||
For an empty cart (which shouldn't ever happen), it would return an empty array.
|
||||
|
||||
=head3 $cart
|
||||
|
||||
A WebGUI::Shop::Cart object. It provides access to the items in the cart
|
||||
that must be sorted.
|
||||
|
||||
=cut
|
||||
|
||||
sub _getShippableUnits {
|
||||
my ($self, $cart) = @_;
|
||||
my @shippableUnits = ();
|
||||
##Loose units are sorted by zip code.
|
||||
my %looseUnits = ();
|
||||
ITEM: foreach my $item (@{$cart->getItems}) {
|
||||
my $sku = $item->getSku;
|
||||
next ITEM unless $sku->isShippingRequired;
|
||||
if ($sku->shipsSeparately) {
|
||||
push @shippableUnits, [ $item ];
|
||||
}
|
||||
else {
|
||||
my $zip = $item->getShippingAddress->get('code');
|
||||
push @{ $looseUnits{$zip} }, $item;
|
||||
}
|
||||
}
|
||||
push @shippableUnits, values %looseUnits;
|
||||
return @shippableUnits;
|
||||
}
|
||||
|
||||
1;
|
||||
93
lib/WebGUI/i18n/English/ShipDriver_USPS.pm
Normal file
93
lib/WebGUI/i18n/English/ShipDriver_USPS.pm
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
package WebGUI::i18n::English::ShipDriver_USPS;
|
||||
|
||||
use strict;
|
||||
|
||||
our $I18N = {
|
||||
|
||||
'userid' => {
|
||||
message => q|USPS Web Tools Username|,
|
||||
lastUpdated => 1203569535,
|
||||
context => q|Label in the ShipDriver edit form.|,
|
||||
},
|
||||
|
||||
'userid help' => {
|
||||
message => q|You can get a Web Tools Username by first registering with the USPS.|,
|
||||
lastUpdated => 1203569511,
|
||||
},
|
||||
|
||||
'password' => {
|
||||
message => q|USPS Web Tools Password (optional)|,
|
||||
lastUpdated => 1203569535,
|
||||
context => q|Label in the ShipDriver edit form.|,
|
||||
},
|
||||
|
||||
'password help' => {
|
||||
message => q|You will recieve a password along with your username when you register.|,
|
||||
lastUpdated => 1203569511,
|
||||
},
|
||||
|
||||
'instructions' => {
|
||||
message => q|Registration Instructions|,
|
||||
lastUpdated => 1203569535,
|
||||
context => q|Label in the ShipDriver edit form.|,
|
||||
},
|
||||
|
||||
'usps instructions' => {
|
||||
lastUpdated => 1241028258,
|
||||
message => q|<p>In order to use the USPS Shipping Driver, you must first register with the United States Postal Service as a <a href="https://secure.shippingapis.com/registration/">USPS Web Tools User</a>. Fill out the form, submit it, and within a few days the USPS will send you a username and password to use this service. Enter your username and password in the form fields below.</p><p>This driver supports three kinds of shipping with one preset size for each kind. Package sizes, and shipping services outside of those choices, are currently not supported.</p><p>For the purpose of calculating weight, the weight property of a Product is considered to be in pounds.|,
|
||||
},
|
||||
|
||||
'ship type' => {
|
||||
message => q|Shipping type|,
|
||||
lastUpdated => 1203569535,
|
||||
context => q|Label in the ShipDriver edit form.|,
|
||||
},
|
||||
|
||||
'ship type help' => {
|
||||
message => q|Select one from the list of options. If you wish to provide multiple types of shipping, create one additional shipping driver instance for each option.|,
|
||||
lastUpdated => 1203569511,
|
||||
},
|
||||
|
||||
'source zipcode' => {
|
||||
message => q|Shipping Zipcode|,
|
||||
lastUpdated => 1203569535,
|
||||
context => q|Label in the ShipDriver edit form.|,
|
||||
},
|
||||
|
||||
'source zipcode help' => {
|
||||
message => q|The zipcode of the location you will be shipping from.|,
|
||||
lastUpdated => 1203569511,
|
||||
},
|
||||
|
||||
'flatFee' => {
|
||||
message => q|Flat Fee|,
|
||||
lastUpdated => 1241214572,
|
||||
context => q|A fixed amount of money added to a purchase for shipping.|,
|
||||
},
|
||||
|
||||
'flatFee help' => {
|
||||
message => q|A fixed amount of money added to a purchase for shipping, covering shipping materials and handling.|,
|
||||
lastUpdated => 1241214575,
|
||||
},
|
||||
|
||||
'priority' => {
|
||||
message => q|Priority, Flat Rate Box|,
|
||||
lastUpdated => 1203569511,
|
||||
context => q|Label for a type of shipping from the USPS.|,
|
||||
},
|
||||
|
||||
'express' => {
|
||||
message => q|Express, Regular size|,
|
||||
lastUpdated => 1203569511,
|
||||
context => q|Label for a type of shipping from the USPS.|,
|
||||
},
|
||||
|
||||
'parcel post' => {
|
||||
message => q|Parcel Post, Regular size|,
|
||||
lastUpdated => 1242166045,
|
||||
context => q|Label for a type of shipping from the USPS.|,
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
1;
|
||||
718
t/Shop/ShipDriver/USPS.t
Normal file
718
t/Shop/ShipDriver/USPS.t
Normal file
|
|
@ -0,0 +1,718 @@
|
|||
# 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 XML::Simple;
|
||||
use Data::Dumper;
|
||||
|
||||
use WebGUI::Test; # Must use this before any other WebGUI modules
|
||||
use WebGUI::Session;
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Init
|
||||
my $session = WebGUI::Test->session;
|
||||
my $user = WebGUI::User->create($session);
|
||||
WebGUI::Test->usersToDelete($user);
|
||||
$session->user({user => $user});
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Tests
|
||||
|
||||
my $tests = 41;
|
||||
plan tests => 1 + $tests;
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# put your tests here
|
||||
|
||||
my $loaded = use_ok('WebGUI::Shop::ShipDriver::USPS');
|
||||
|
||||
my $storage;
|
||||
my ($driver, $cart);
|
||||
my $versionTag = WebGUI::VersionTag->getWorking($session);
|
||||
|
||||
my $home = WebGUI::Asset->getDefault($session);
|
||||
|
||||
my $rockHammer = $home->addChild({
|
||||
className => 'WebGUI::Asset::Sku::Product',
|
||||
isShippingRequired => 1, title => 'Rock Hammers',
|
||||
shipsSeparately => 0,
|
||||
});
|
||||
|
||||
my $smallHammer = $rockHammer->setCollateral('variantsJSON', 'variantId', 'new',
|
||||
{
|
||||
shortdesc => 'Small rock hammer', price => 7.50,
|
||||
varSku => 'small-hammer', weight => 1.5,
|
||||
quantity => 9999,
|
||||
}
|
||||
);
|
||||
|
||||
my $bigHammer = $rockHammer->setCollateral('variantsJSON', 'variantId', 'new',
|
||||
{
|
||||
shortdesc => 'Big rock hammer', price => 19.99,
|
||||
varSku => 'big-hammer', weight => 12,
|
||||
quantity => 9999,
|
||||
}
|
||||
);
|
||||
|
||||
my $bible = $home->addChild({
|
||||
className => 'WebGUI::Asset::Sku::Product',
|
||||
isShippingRequired => 1, title => 'Bibles, individuall wrapped and shipped',
|
||||
shipsSeparately => 1,
|
||||
});
|
||||
|
||||
my $kjvBible = $bible->setCollateral('variantsJSON', 'variantId', 'new',
|
||||
{
|
||||
shortdesc => 'King James Bible', price => 17.50,
|
||||
varSku => 'kjv-bible', weight => 2.5,
|
||||
quantity => 99999,
|
||||
}
|
||||
);
|
||||
|
||||
my $nivBible = $bible->setCollateral('variantsJSON', 'variantId', 'new',
|
||||
{
|
||||
shortdesc => 'NIV Bible', price => 22.50,
|
||||
varSku => 'niv-bible', weight => 2.0,
|
||||
quantity => 999999,
|
||||
}
|
||||
);
|
||||
|
||||
$versionTag->commit;
|
||||
|
||||
SKIP: {
|
||||
|
||||
skip 'Unable to load module WebGUI::Shop::ShipDriver::USPS', $tests unless $loaded;
|
||||
|
||||
#######################################################################
|
||||
#
|
||||
# definition
|
||||
#
|
||||
#######################################################################
|
||||
|
||||
my $definition;
|
||||
my $e; ##Exception variable, used throughout the file
|
||||
|
||||
eval { $definition = WebGUI::Shop::ShipDriver::USPS->definition(); };
|
||||
$e = Exception::Class->caught();
|
||||
isa_ok($e, 'WebGUI::Error::InvalidParam', 'definition takes an exception to not giving it a session variable');
|
||||
cmp_deeply(
|
||||
$e,
|
||||
methods(
|
||||
error => 'Must provide a session variable',
|
||||
),
|
||||
'... checking error message',
|
||||
);
|
||||
|
||||
|
||||
isa_ok(
|
||||
$definition = WebGUI::Shop::ShipDriver::USPS->definition($session),
|
||||
'ARRAY'
|
||||
);
|
||||
|
||||
|
||||
#######################################################################
|
||||
#
|
||||
# create
|
||||
#
|
||||
#######################################################################
|
||||
|
||||
my $options = {
|
||||
label => 'USPS Driver',
|
||||
enabled => 1,
|
||||
};
|
||||
|
||||
$driver = WebGUI::Shop::ShipDriver::USPS->create($session, $options);
|
||||
|
||||
isa_ok($driver, 'WebGUI::Shop::ShipDriver::USPS');
|
||||
isa_ok($driver, 'WebGUI::Shop::ShipDriver');
|
||||
|
||||
#######################################################################
|
||||
#
|
||||
# getName
|
||||
#
|
||||
#######################################################################
|
||||
|
||||
is (WebGUI::Shop::ShipDriver::USPS->getName($session), 'U.S. Postal Service', 'getName returns the human readable name of this driver');
|
||||
|
||||
#######################################################################
|
||||
#
|
||||
# delete
|
||||
#
|
||||
#######################################################################
|
||||
|
||||
my $driverId = $driver->getId;
|
||||
$driver->delete;
|
||||
|
||||
my $count = $session->db->quickScalar('select count(*) from shipper where shipperId=?',[$driverId]);
|
||||
is($count, 0, 'delete deleted the object');
|
||||
|
||||
undef $driver;
|
||||
|
||||
#######################################################################
|
||||
#
|
||||
# calculate, and private methods.
|
||||
#
|
||||
#######################################################################
|
||||
|
||||
$driver = WebGUI::Shop::ShipDriver::USPS->create($session, {
|
||||
label => 'Shipping from Shawshank',
|
||||
enabled => 1,
|
||||
shipType => 'PARCEL',
|
||||
});
|
||||
|
||||
eval { $driver->calculate() };
|
||||
$e = Exception::Class->caught();
|
||||
isa_ok($e, 'WebGUI::Error::InvalidParam', 'calculate throws an exception when no zipcode has been set');
|
||||
cmp_deeply(
|
||||
$e,
|
||||
methods(
|
||||
error => 'Driver configured without a source zipcode.',
|
||||
),
|
||||
'... checking error message',
|
||||
);
|
||||
|
||||
my $properties = $driver->get();
|
||||
$properties->{sourceZip} = '97123';
|
||||
$driver->update($properties);
|
||||
|
||||
eval { $driver->calculate() };
|
||||
$e = Exception::Class->caught();
|
||||
isa_ok($e, 'WebGUI::Error::InvalidParam', 'calculate throws an exception when no userId');
|
||||
cmp_deeply(
|
||||
$e,
|
||||
methods(
|
||||
error => 'Driver configured without a USPS userId.',
|
||||
),
|
||||
'... checking error message',
|
||||
);
|
||||
|
||||
$cart = WebGUI::Shop::Cart->newBySession($session);
|
||||
my $addressBook = $cart->getAddressBook;
|
||||
my $workAddress = $addressBook->addAddress({
|
||||
label => 'work',
|
||||
organization => 'Plain Black Corporation',
|
||||
address1 => '1360 Regent St. #145',
|
||||
city => 'Madison', state => 'WI', code => '53715',
|
||||
country => 'USA',
|
||||
});
|
||||
my $wucAddress = $addressBook->addAddress({
|
||||
label => 'wuc',
|
||||
organization => 'Madison Concourse Hotel',
|
||||
address1 => '1 W Dayton St',
|
||||
city => 'Madison', state => 'WI', code => '53703',
|
||||
country => 'USA',
|
||||
});
|
||||
$cart->update({shippingAddressId => $workAddress->getId});
|
||||
|
||||
cmp_deeply(
|
||||
[$driver->_getShippableUnits($cart)],
|
||||
[(), ],
|
||||
'_getShippableUnits: empty cart'
|
||||
);
|
||||
|
||||
$rockHammer->addToCart($rockHammer->getCollateral('variantsJSON', 'variantId', $smallHammer));
|
||||
cmp_deeply(
|
||||
[$driver->_getShippableUnits($cart)],
|
||||
[[ ignore() ], ],
|
||||
'_getShippableUnits: one loose item in the cart'
|
||||
);
|
||||
|
||||
$rockHammer->addToCart($rockHammer->getCollateral('variantsJSON', 'variantId', $bigHammer));
|
||||
cmp_deeply(
|
||||
[$driver->_getShippableUnits($cart)],
|
||||
[[ ignore(), ignore() ], ],
|
||||
'_getShippableUnits: two loose items in the cart'
|
||||
);
|
||||
|
||||
$bible->addToCart($bible->getCollateral('variantsJSON', 'variantId', $kjvBible));
|
||||
cmp_bag(
|
||||
[$driver->_getShippableUnits($cart)],
|
||||
[[ ignore(), ignore() ], [ ignore(), ], ],
|
||||
'_getShippableUnits: two loose items, and 1 ships separately item in the cart'
|
||||
);
|
||||
|
||||
my $bibleItem = $bible->addToCart($bible->getCollateral('variantsJSON', 'variantId', $nivBible));
|
||||
$bibleItem->setQuantity(5);
|
||||
cmp_bag(
|
||||
[$driver->_getShippableUnits($cart)],
|
||||
[[ ignore(), ignore() ], [ ignore() ], [ ignore() ], ],
|
||||
'_getShippableUnits: two loose items, and 2 ships separately item in the cart, regarless of quantity for the new item'
|
||||
);
|
||||
|
||||
my $rockHammer2 = $bible->addToCart($rockHammer->getCollateral('variantsJSON', 'variantId', $smallHammer));
|
||||
$rockHammer2->update({shippingAddressId => $wucAddress->getId});
|
||||
cmp_bag(
|
||||
[$driver->_getShippableUnits($cart)],
|
||||
[[ ignore(), ignore() ], [ ignore() ], [ ignore() ], [ ignore() ], ],
|
||||
'_getShippableUnits: two loose items, and 2 ships separately item in the cart, and another loose item sorted by zipcode'
|
||||
);
|
||||
|
||||
$cart->empty;
|
||||
$bible->addToCart($bible->getCollateral('variantsJSON', 'variantId', $nivBible));
|
||||
cmp_deeply(
|
||||
[$driver->_getShippableUnits($cart)],
|
||||
[ [ ignore() ], ],
|
||||
'_getShippableUnits: only 1 ships separately item in the cart'
|
||||
);
|
||||
$cart->empty;
|
||||
|
||||
my $userId = $session->config->get('testing/USPS_userId');
|
||||
my $hasRealUserId = 1;
|
||||
##If there isn't a userId, set a fake one for XML testing.
|
||||
if (! $userId) {
|
||||
$hasRealUserId = 0;
|
||||
$userId = "blahBlahBlah";
|
||||
}
|
||||
$properties = $driver->get();
|
||||
$properties->{userId} = $userId;
|
||||
$properties->{sourceZip} = '97123';
|
||||
$driver->update($properties);
|
||||
|
||||
$rockHammer->addToCart($rockHammer->getCollateral('variantsJSON', 'variantId', $smallHammer));
|
||||
my @shippableUnits = $driver->_getShippableUnits($cart);
|
||||
|
||||
my $xml = $driver->buildXML($cart, @shippableUnits);
|
||||
like($xml, qr/<RateV3Request USERID="[^"]+"/, 'buildXML: checking userId is an attribute of the RateV3Request tag');
|
||||
like($xml, qr/<Package ID="0"/, 'buildXML: checking ID is an attribute of the Package tag');
|
||||
|
||||
my $xmlData = XMLin($xml,
|
||||
KeepRoot => 1,
|
||||
ForceArray => ['Package'],
|
||||
);
|
||||
cmp_deeply(
|
||||
$xmlData,
|
||||
{
|
||||
RateV3Request => {
|
||||
USERID => $userId,
|
||||
Package => [
|
||||
{
|
||||
ID => 0,
|
||||
ZipDestination => '53715', ZipOrigination => '97123',
|
||||
Pounds => '1', Ounces => '8',
|
||||
Size => 'REGULAR', Service => 'PARCEL',
|
||||
Machinable => 'true',
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
'buildXML: PARCEL service, 1 item in cart'
|
||||
);
|
||||
|
||||
like($xml, qr/RateV3Request USERID.+?Package ID=.+?Service.+?ZipOrigination.+?ZipDestination.+?Pounds.+?Ounces.+?Size.+?Machinable/, '... and tag order');
|
||||
|
||||
SKIP: {
|
||||
|
||||
skip 'No userId for testing', 2 unless $hasRealUserId;
|
||||
|
||||
my $response = $driver->_doXmlRequest($xml);
|
||||
ok($response->is_success, '_doXmlRequest to USPS successful');
|
||||
my $xmlData = XMLin($response->content, ForceArray => [qw/Package/],);
|
||||
cmp_deeply(
|
||||
$xmlData,
|
||||
{
|
||||
Package => [
|
||||
{
|
||||
ID => 0,
|
||||
ZipOrigination => ignore(), ZipDestination => ignore(),
|
||||
Machinable => ignore(), Ounces => ignore(),
|
||||
Pounds => ignore(), Size => ignore(),
|
||||
Zone => ignore(),
|
||||
Postage => {
|
||||
CLASSID => ignore(),
|
||||
MailService => ignore(),
|
||||
Rate => num(10,10), ##A number around 10...
|
||||
}
|
||||
},
|
||||
],
|
||||
},
|
||||
'... returned data from USPS in correct format. If this test fails, the driver may need to be updated'
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
my $cost = $driver->_calculateFromXML({
|
||||
Package => [
|
||||
{
|
||||
ID => 0,
|
||||
Postage => {
|
||||
Rate => 5.25,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
@shippableUnits
|
||||
);
|
||||
|
||||
is($cost, 5.25, '_calculateFromXML calculates shipping cost correctly for 1 item in the cart');
|
||||
|
||||
$bibleItem = $bible->addToCart($bible->getCollateral('variantsJSON', 'variantId', $nivBible));
|
||||
@shippableUnits = $driver->_getShippableUnits($cart);
|
||||
$xml = $driver->buildXML($cart, @shippableUnits);
|
||||
|
||||
$xmlData = XMLin( $xml,
|
||||
KeepRoot => 1,
|
||||
ForceArray => ['Package'],
|
||||
);
|
||||
|
||||
cmp_deeply(
|
||||
$xmlData,
|
||||
{
|
||||
RateV3Request => {
|
||||
USERID => $userId,
|
||||
Package => [
|
||||
{
|
||||
ID => 0,
|
||||
ZipDestination => '53715', ZipOrigination => '97123',
|
||||
Pounds => '2', Ounces => '0',
|
||||
Size => 'REGULAR', Service => 'PARCEL',
|
||||
Machinable => 'true',
|
||||
},
|
||||
{
|
||||
ID => 1,
|
||||
ZipDestination => '53715', ZipOrigination => '97123',
|
||||
Pounds => '1', Ounces => '8',
|
||||
Size => 'REGULAR', Service => 'PARCEL',
|
||||
Machinable => 'true',
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
'Validate XML structure and content for 2 items in the cart'
|
||||
);
|
||||
|
||||
SKIP: {
|
||||
|
||||
skip 'No userId for testing', 2 unless $hasRealUserId;
|
||||
|
||||
my $response = $driver->_doXmlRequest($xml);
|
||||
ok($response->is_success, '_doXmlRequest to USPS successful for 2 items in cart');
|
||||
my $xmlData = XMLin($response->content, ForceArray => [qw/Package/],);
|
||||
cmp_deeply(
|
||||
$xmlData,
|
||||
{
|
||||
Package => [
|
||||
{
|
||||
ID => 0,
|
||||
ZipOrigination => ignore(), ZipDestination => ignore(),
|
||||
Machinable => ignore(), Ounces => 0,
|
||||
Pounds => 2, Size => ignore(),
|
||||
Zone => ignore(),
|
||||
Postage => {
|
||||
CLASSID => ignore(),
|
||||
MailService => ignore(),
|
||||
Rate => num(10,10), ##A number around 10...
|
||||
}
|
||||
},
|
||||
{
|
||||
ID => 1,
|
||||
ZipOrigination => ignore(), ZipDestination => ignore(),
|
||||
Machinable => ignore(), Ounces => 8,
|
||||
Pounds => 1, Size => ignore(),
|
||||
Zone => ignore(),
|
||||
Postage => {
|
||||
CLASSID => ignore(),
|
||||
MailService => ignore(),
|
||||
Rate => num(10,10), ##A number around 10...
|
||||
}
|
||||
},
|
||||
],
|
||||
},
|
||||
'... returned data from USPS in correct format for 2 items in cart. If this test fails, the driver may need to be updated'
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
$cost = $driver->_calculateFromXML({
|
||||
Package => [
|
||||
{
|
||||
ID => 0,
|
||||
Postage => {
|
||||
Rate => 7.00,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID => 1,
|
||||
Postage => {
|
||||
Rate => 5.25,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
@shippableUnits
|
||||
);
|
||||
|
||||
is($cost, 12.25, '_calculateFromXML calculates shipping cost correctly for 2 items in the cart');
|
||||
|
||||
$bibleItem->setQuantity(2);
|
||||
@shippableUnits = $driver->_getShippableUnits($cart);
|
||||
|
||||
$cost = $driver->_calculateFromXML({
|
||||
Package => [
|
||||
{
|
||||
ID => 0,
|
||||
Postage => {
|
||||
Rate => 7.00,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID => 1,
|
||||
Postage => {
|
||||
Rate => 5.25,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
@shippableUnits
|
||||
);
|
||||
is($cost, 19.25, '_calculateFromXML calculates shipping cost correctly for 2 items in the cart, with quantity of 2');
|
||||
|
||||
$rockHammer2 = $rockHammer->addToCart($rockHammer->getCollateral('variantsJSON', 'variantId', $bigHammer));
|
||||
$rockHammer2->update({shippingAddressId => $wucAddress->getId});
|
||||
@shippableUnits = $driver->_getShippableUnits($cart);
|
||||
$xml = $driver->buildXML($cart, @shippableUnits);
|
||||
|
||||
$xmlData = XMLin( $xml,
|
||||
KeepRoot => 1,
|
||||
ForceArray => ['Package'],
|
||||
);
|
||||
|
||||
cmp_deeply(
|
||||
$xmlData,
|
||||
{
|
||||
RateV3Request => {
|
||||
USERID => $userId,
|
||||
Package => [
|
||||
{
|
||||
ID => 0,
|
||||
ZipDestination => '53715', ZipOrigination => '97123',
|
||||
Pounds => '2', Ounces => '0',
|
||||
Size => 'REGULAR', Service => 'PARCEL',
|
||||
Machinable => 'true',
|
||||
},
|
||||
{
|
||||
ID => 1,
|
||||
ZipDestination => '53715', ZipOrigination => '97123',
|
||||
Pounds => '1', Ounces => '8',
|
||||
Size => 'REGULAR', Service => 'PARCEL',
|
||||
Machinable => 'true',
|
||||
},
|
||||
{
|
||||
ID => 2,
|
||||
ZipDestination => '53703', ZipOrigination => '97123',
|
||||
Pounds => '12', Ounces => '0',
|
||||
Size => 'REGULAR', Service => 'PARCEL',
|
||||
Machinable => 'true',
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
'Validate XML structure and content for 3 items in the cart, 3 shippable items'
|
||||
);
|
||||
|
||||
SKIP: {
|
||||
|
||||
skip 'No userId for testing', 2 unless $hasRealUserId;
|
||||
|
||||
my $response = $driver->_doXmlRequest($xml);
|
||||
ok($response->is_success, '_doXmlRequest to USPS successful for 3 items in cart');
|
||||
my $xmlData = XMLin($response->content, ForceArray => [qw/Package/],);
|
||||
cmp_deeply(
|
||||
$xmlData,
|
||||
{
|
||||
Package => [
|
||||
{
|
||||
ID => 0,
|
||||
ZipOrigination => ignore(), ZipDestination => ignore(),
|
||||
Machinable => ignore(), Ounces => 0,
|
||||
Pounds => 2, Size => ignore(),
|
||||
Zone => ignore(),
|
||||
Postage => {
|
||||
CLASSID => ignore(),
|
||||
MailService => ignore(),
|
||||
Rate => num(10,10), ##A number around 10...
|
||||
}
|
||||
},
|
||||
{
|
||||
ID => 1,
|
||||
ZipOrigination => ignore(), ZipDestination => ignore(),
|
||||
Machinable => ignore(), Ounces => 8,
|
||||
Pounds => 1, Size => ignore(),
|
||||
Zone => ignore(),
|
||||
Postage => {
|
||||
CLASSID => ignore(),
|
||||
MailService => ignore(),
|
||||
Rate => num(10,10), ##A number around 10...
|
||||
}
|
||||
},
|
||||
{
|
||||
ID => 2,
|
||||
ZipOrigination => ignore(), ZipDestination => 53703,
|
||||
Machinable => ignore(), Ounces => 0,
|
||||
Pounds => 12, Size => ignore(),
|
||||
Zone => ignore(),
|
||||
Postage => {
|
||||
CLASSID => ignore(),
|
||||
MailService => ignore(),
|
||||
Rate => num(20,20), ##A number around 20...
|
||||
}
|
||||
},
|
||||
],
|
||||
},
|
||||
'... returned data from USPS in correct format for 3 items in cart. If this test fails, the driver may need to be updated'
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
$cart->empty;
|
||||
$properties = $driver->get();
|
||||
$properties->{shipType} = 'PRIORITY';
|
||||
$driver->update($properties);
|
||||
|
||||
$rockHammer->addToCart($rockHammer->getCollateral('variantsJSON', 'variantId', $smallHammer));
|
||||
@shippableUnits = $driver->_getShippableUnits($cart);
|
||||
$xml = $driver->buildXML($cart, @shippableUnits);
|
||||
my $xmlData = XMLin($xml,
|
||||
KeepRoot => 1,
|
||||
ForceArray => ['Package'],
|
||||
);
|
||||
cmp_deeply(
|
||||
$xmlData,
|
||||
{
|
||||
RateV3Request => {
|
||||
USERID => $userId,
|
||||
Package => [
|
||||
{
|
||||
ID => 0,
|
||||
ZipDestination => '53715', ZipOrigination => '97123',
|
||||
Pounds => '1', Ounces => '8',
|
||||
Size => 'REGULAR', Service => 'PRIORITY',
|
||||
Machinable => 'true', Container => 'FLAT RATE BOX',
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
'buildXML: PRIORITY service, 1 item in cart'
|
||||
);
|
||||
like($xml, qr/RateV3Request USERID.+?Package ID=.+?Service.+?ZipOrigination.+?ZipDestination.+?Pounds.+?Ounces.+?Container.+?Size.+?Machinable/, '... and tag order');
|
||||
|
||||
SKIP: {
|
||||
|
||||
skip 'No userId for testing', 2 unless $hasRealUserId;
|
||||
|
||||
my $response = $driver->_doXmlRequest($xml);
|
||||
ok($response->is_success, '_doXmlRequest to USPS successful');
|
||||
my $xmlData = XMLin($response->content, ForceArray => [qw/Package/],);
|
||||
cmp_deeply(
|
||||
$xmlData,
|
||||
{
|
||||
Package => [
|
||||
{
|
||||
ID => 0,
|
||||
ZipOrigination => ignore(), ZipDestination => ignore(),
|
||||
Container => ignore(), Ounces => ignore(), ##Machinable missing, added Container
|
||||
Pounds => ignore(), Size => ignore(),
|
||||
Zone => ignore(),
|
||||
Postage => {
|
||||
CLASSID => ignore(),
|
||||
MailService => ignore(),
|
||||
Rate => num(10,10), ##A number around 10...
|
||||
}
|
||||
},
|
||||
],
|
||||
},
|
||||
'... returned data from USPS in correct format. If this test fails, the driver may need to be updated'
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
$properties = $driver->get();
|
||||
$properties->{shipType} = 'EXPRESS';
|
||||
$driver->update($properties);
|
||||
|
||||
$xml = $driver->buildXML($cart, @shippableUnits);
|
||||
my $xmlData = XMLin($xml,
|
||||
KeepRoot => 1,
|
||||
ForceArray => ['Package'],
|
||||
);
|
||||
cmp_deeply(
|
||||
$xmlData,
|
||||
{
|
||||
RateV3Request => {
|
||||
USERID => $userId,
|
||||
Package => [
|
||||
{
|
||||
ID => 0,
|
||||
ZipDestination => '53715', ZipOrigination => '97123',
|
||||
Pounds => '1', Ounces => '8',
|
||||
Size => 'REGULAR', Service => 'EXPRESS',
|
||||
Machinable => 'true',
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
'buildXML: EXPRESS service, 1 item in cart'
|
||||
);
|
||||
like($xml, qr/RateV3Request USERID.+?Package ID=.+?Service.+?ZipOrigination.+?ZipDestination.+?Pounds.+?Ounces.+?Size.+?Machinable/, '... and tag order');
|
||||
|
||||
SKIP: {
|
||||
|
||||
skip 'No userId for testing', 2 unless $hasRealUserId;
|
||||
|
||||
my $response = $driver->_doXmlRequest($xml);
|
||||
ok($response->is_success, '... _doXmlRequest to USPS successful');
|
||||
my $xmlData = XMLin($response->content, ForceArray => [qw/Package/],);
|
||||
cmp_deeply(
|
||||
$xmlData,
|
||||
{
|
||||
Package => [
|
||||
{
|
||||
ID => 0,
|
||||
ZipOrigination => ignore(), ZipDestination => ignore(),
|
||||
Ounces => ignore(), Pounds => ignore(),
|
||||
Size => ignore(), Zone => ignore(),
|
||||
Postage => {
|
||||
CLASSID => ignore(),
|
||||
MailService => ignore(),
|
||||
Rate => num(30,30), ##A number around 10...
|
||||
}
|
||||
},
|
||||
],
|
||||
},
|
||||
'... returned data from USPS in correct format. If this test fails, the driver may need to be updated'
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Cleanup
|
||||
END {
|
||||
if (defined $driver && $driver->isa('WebGUI::Shop::ShipDriver')) {
|
||||
$driver->delete;
|
||||
}
|
||||
if (defined $cart && $cart->isa('WebGUI::Shop::Cart')) {
|
||||
my $addressBook = $cart->getAddressBook();
|
||||
$addressBook->delete if $addressBook;
|
||||
$cart->delete;
|
||||
}
|
||||
if (defined $versionTag) {
|
||||
$versionTag->rollback;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue