Shipping
The shipping is mainly handled by the ShopShippingLib, with some help
from ShopOrderLib in preparing data. If you want to set up a shipping
method that is not listed here, or is listed but you want to customize
it, please contact us for a quote.
ShopSetup
Here you define your shipping options, using the following keys as in
the example below:
-SHOP_CALCULATE_SHIPPING_BY_QUANTITY => 0,
-SHOP_SHIPPING_FROM_ZIP => '96067',
-SHOP_SHIPPING_FROM_STATE => 'CA',
-SHOP_SHIPPING_FROM_COUNTRY => 'US',
-SHOP_SHIPPING_METHODS => ['usps','ups', 'free', 'custom'],
-SHOP_SHIPPING_METHOD_DEFAULT => 'custom|byzone-1',
-SHOP_ALLOWS_FREE_SHIPPING => 1,
We will explain how these relate in the description of the shop shipping
module (ShopShippingLib). As a general idea, here are some basic rules:
You need to provide the origin for the shipping, using the 3 keys listed
above. Some methods use it, some don't, but we decided to require them
by default.
List the main methods in the array of shipping methods. If you have defined
more than one custom method, but you want to display only some of them,
use the format:
-SHOP_SHIPPING_METHODS => ['free', 'custom|1', 'custom|2'],
If you want a certain method to appear as default in your shipping method
selector, you can define it using the following key:
-SHOP_SHIPPING_METHOD_DEFAULT => 'custom|byzone-1',
Some methods require specific settings, please read the text below for
explanations.
ShopFormatting (for each language)
These modules hold an array of shipping options and the corresponding
description. We use an array and not a hash in order to preserve the display
order.
ShopShippingLib
It takes the following function call (extract from ShopOrderLib):
RequireFile($S->{-SHOP_PATH}, 'ShopShippingLib.pm');
($ShippingCost,
$SError,
$SWarning) = ShopShippingLib::display($S, [
$ToZip,
$ToState,
$ToCountry,
$FromZip,
$FromState,
$FromCountry,
$STotals,
$Weight,
$SPreferredMethod]);
It is meant to be simple, and not have to handle split-shipping or distributed
shipping. You have to process that outside this routine, take example
from the ShopOrderLib.
As expected, you have to provide values for all the address fields, and
of course, you have to provide values for the totals, weight and shipping
method (I guess it could be said: all parameters are required... oh well,
you get what I mean).
Methods supported by this module:
Free
This returns 0 for the shipping costs. The required input parameter is
"free".
Of course, you will have to enable the following key in the ShopSetup,
for the free shipping to be allowed:
-SHOP_ALLOWS_FREE_SHIPPING => 1,
Custom Methods
As in the name, it is not said by the method ID what it will do. We display
a few examples in the ShopShippingLib, but if you need something special,
feel free to build your own calculations, or call us for a quote (...we
love that :))
Here are the methods currently implemented, we will list the method ID
needed:
custom|1
This is meant as a straight multiplier using the number of items. We
even thought of implementing alternatively the calculations by weight,
and that would be simple to do, just assign $NumberOfItems = $Weight before
the calculation takes place.
The following flag needs to be set in the ShopSetup, in order for the
calculations to be successful:
-SHOP_CALCULATE_SHIPPING_BY_QUANTITY => 1,
custom|2
This method uses a straight table of countries and prices by pound or
kg. You will have to record your prices per unit in both the states.db
and countries.db, using the manager interface, or edit the files and re-upload
them. The table field name in question is "PriceByWeight", and
should be a numeric, positive value.
As expected, if the source address country is different from the target
country, the countries.db will be used, otherwise the states.db. Note
that the states.db contains only valid values for US and CA, so if you
want to customize this for another country, you need to add the states/regions
in that country to the states.db. Since the display of the states data
can be sorted alphabetically, you can use a numeric first character for
the new states: 0A, 0B, 0C,... if you want them at the top.
One hint here, the module is using named data sources, as defined in
the ShopSetup, i.e. $S->{-DATA_SOURCE}{'DisplayStates'}. It might appear
odd, but this is the way to keep the data in memory and avoid multiple
database queries for the same data. The shop implements caching in this
case, given the small table size, and the likelyhood that the data will
be needed a few times during a single click.
custom|3
This method is using local defined tables, for shipping by country ONLY.
As in the custom|1, this method uses in older modules, the the following
flag to be set in the ShopSetup, in order for the calculations to be successful:
-SHOP_CALCULATE_SHIPPING_BY_QUANTITY => 1,
If you download the last released version of the shop (evt. prerelease),
we modified the module to support here either number of items or weight,
depending of whether the above flag is set or not. For the impatient,
set the following in the module (it was set before on 0):
my $NumberOfItems = $Weight;
Look at the top of the module and you will see the following global variables:
%CountryZones = (
'US' => 0,
'CA' => 1,
'DE' => 2,
);
%ZonesDetails = (
0 => [qw(US CA)],
1 => [qw(RU GR)],
2 => [qw(DE FR IT AT)],
);
%ShippingData = (
0 => 3,
1 => 4.5,
2 => 6,
);
$DefaultShipping = 10;
It looks complex, it is not. The way it functions:
- You have a country defined in the %CountryZones, with a number assigned
to it. This number is an index to the hash %ShippingData, which contains
the prices per unit of measurement (weight or number of items, see above).
The shipping cost will be calculated by multiplying the unit of measurement
with the price, no preservatives added :).
- The country is defined in one of the lists contained in the values
of %ZonesDetails. The corresponding key of that hash is the actual index
that you will use to calculate the shipping price, as in the above example.
- If nothing is defined for the country of destination, the value in
the $DefaultShipping will be used.
That is all there is to it. Yes, I can hear the questions, "what
about the states, what about the handling fees,..." - this is a custom
method meant as an example. If you want to customize it further (sic.,*giggle*),
you can either write your own code around a method you like most, or call
us for a quote (you already heard it, we love that :)).
custom|byzone-*
Look at the top of the module and you will see the following global variables:
@CustomShippingThresholds = qw(2 5 10); # these are weight limits
%ZonePricesByType = (
1 => { # urgent
0 => [qw(5.15 5.8 7.3)],
1 => [qw(5.9 7.3 9.8)],
2 => [qw(6.3 7.95 11.25)],
},
2 => { # express
0 => [qw(6.5 7.6 8.4)],
1 => [qw(7.9 9.3 11.8)],
2 => [qw(9 10.75 16)],
},
3 => { # preferred
0 => [qw(8.45 8.9 15.15)],
1 => [qw(11.25 13.5 23.35)],
2 => [qw(12.25 15.2 26.5)],
},
4 => { # overnight
0 => [qw(8.45 8.9 15.15)],
1 => [qw(11.25 13.5 23.35)],
},
);
As expected, the "*" is a variable parameter that you should
define in each of the ShopFormatting modules:
'custom|byzone-1' => 'Urgent',
'custom|byzone-2' => 'Expres',
'custom|byzone-3' => 'Preferred',
'custom|byzone-4' => 'Overnight',
The parameter value is numeric, but you can define it otherwise, if you
understand the principle. Here it is, explained:
every parameter associates with a valid key in the hash %ZonePricesByType.
Let's say you chose "Urgent", this will give you the following
hash to work with:
{ # urgent
0 => [qw(5.15 5.8 7.3)],
1 => [qw(5.9 7.3 9.8)],
2 => [qw(6.3 7.95 11.25)],
}
The module checks for the weight, if it fits in one of the thresholds
defined in the @CustomShippingThresholds. That means, if the order
is between 0 and 1.9x lbs, it will return 0, if it is between 2 and 4.9x
lbs it will return 1, between 5 and 9.9x lbs it will return 2, and will
return 3 if above 10 lbs.
This number will be used as a key to extract the mapping array from the
hash above. Given a package weighing 3 lbs, where the index returned is
1, the following array is what we have to work with:
[qw(5.9 7.3 9.8)]
Now the magic is in the states.db or countries.db.
As expected, if the source address country is different from the target
country, the countries.db will be used, otherwise the states.db. Note
that the states.db contains only valid values for US and CA, so if you
want to customize this for another country, you need to add the states/regions
in that country to the states.db. Since the display of the states data
can be sorted alphabetically, you can use a numeric first character for
the new states: 0A, 0B, 0C,... if you want them at the top.
The change that you will need to make in the module then, will be for
example:
if ($FromCountry eq 'US' && $ToCountry eq 'US' ||
$FromCountry eq 'CA' && $ToCountry eq 'CA' ||
$FromCountry eq 'DE' && $ToCountry eq 'DE') {
...
The table field that will be the index to that array, is "ShippingZone".
The shipping cost will be the element in the array above, indexed by the
value in the "ShippingZone", which of course, has to
be numeric and positive.
UPS
This method is using the ShippingUPS module. It makes use of the US based
UPS online gateway, and of course, it works ONLY for shippments originating
US or CA.
As soon I get the time and the documentation to other UPS gateways worldwide,
I will expand the ShippingUPS, with no changes to the ShopShippingLib.
In order to use it, you have to define the submethods in the ShopFormatting
for every language, and add it in the array of supported shipping methods,
in the ShopSetup (see module related explanation above)
The gateway will calculate the shipping costs between the source address
and the destination address.
The submethod to be used, needs to be given as a part of the shipping
method, in the format:
'ups|1DM' => 'UPS Next Day Early',
'ups|1DA' => 'UPS Next Day Air',
'ups|GND' => 'UPS Ground',
...
See the complete list in the Views/eng/ShopFormatting.pm.
|