How shipping is calculated

### Index Up << >>

## How shipping is calculated

1. The base code is selected by reading the value of mv_shipmode in the user session. If it has not been explicitly set, either by means of the DefaultShipping directive or by setting the variable on a form (or in an order profile), it will be `default`.

   The mv_shipmode must be in the character class [A-Za-z0-9_]. If there are spaces, commas, or nulls in the value they will be read as multiple shipping modes.

2. The modes are selected from the d =item 1

   The criterion field is found -- if it is quantity, then it is the total quantity of items on the order form. If it is any other name, then the criterion is calculated by multiplying the return value from the product database field for each item in the shopping cart, multiplied by its quantity. (If the lookup fails due to the column or row not existing, a zero cost will be returned, and an error is sent to the catalog error log.) If a number is returned from a MiniVend tag, then that number is used directly.

3. Entries in the shipping database that begin with the same string as the shipping mode are examined. If none is found, a zero cost is returned and an error is sent to the catalog error log.

   NOTE: You may use the same mode name for all lines in the same group, but the first one will contain the main criteria.

4. The value of the accumulated criteria is examined, and if it falls with in the minimum and maximum, the cost is then applied.

5. If the cost is fixed, it is simply added.

6. If the cost field begins with an x, the cost is multiplied by the accumulated criterion -- price, weight, etc.

7. If the cost field begins with f, the formula following is applied. Use @@TOTAL@@ as the value of the accumulated criterion.

8. If the cost field begins with u or a single letter from A-Z, a UPS-style lookup is done.

9. If the cost field begins with `s`, a Perl subroutine call is made.

10. If the cost field begins with e, zero cost is returned and an error placed in the session ship_message field, available as `[data session ship_message]`.

Here is an example shipping file using all of the methods of determining shipping cost.

NOTE: The columns are lined up for your reading convenience, the actual entries should have ONE tab between fields.

     global Option   n/a                 0   0      g PriceDivide

     rpsg   RPS      quantity            0   0      R RPS products/rps.csv
     rpsg   RPS      quantity            0   5      7.00
     rpsg   RPS      quantity            6   10     10.00
     rpsg   RPS      quantity            11  150    x .95

     usps   US Post  price               0   0      0
     usps   US Post  price               0   50     f 7 + (1 * @@TOTAL@@ / 10)
     usps   US Post  price               50  100    f 12 + (.90 * @@TOTAL@@ / 10)
     usps   US Post  price               100 99999  f @@TOTAL@@ * .05

     upsg   UPS      weight [value state]  0   0      e Nothing to ship.
     upsg   UPS      AK HI               0   150    u upsg [default zip 980] 12.00 round
     upsg   UPS                          0   150    u Ground [default zip 980] 2.00 round
     upsg   UPS                          150 9999   e @@TOTAL@@ lb too heavy for UPS

     upsca  UPS/CA   weight              0   0      c C UPS_Canada products/can.csv
     upsca  UPS/CA   weight              -1   -1    o PriceDivide=0
     upsca  UPS/CA   weight              0   150    C upsca [default zip A7G] 5.00
     upsca  UPS/CA   weight              150 99999  e @@TOTAL@@ lb too heavy for UPS

     fedex  FedEx    quantity            1   9999   s fedex_cost ;[value country]

global
  This is a global option setting, called out by the `g` at the beginning. PriceDivide tells the shipping routines to multiply all shipping settings by the PriceDivide factor -- except those explicitly set differently with the o individual modifier. This allows currency conversion. (Currently the only option is PriceDivide.)

rpsg
  If the user selected RPS, (code rpsg), and the quantity on the order was 3, the cost of 7.00 from the second rpsg line would be applied. If the quantity were 7, the next entry from the third rpsg line would be selected, for a cost of 10.00. If the quantity were 15, the last rpsg would be selected, and the quantity of 15 multiplied by 0.95, for a total cost of 14.25.

usps
  The next mode, usps, is a more complicated formula -- using price as the criteria. If the total price of all items in the shopping cart (same as `[subtotal]` without quantity price breaks in place) is from 1 to 50, the cost will be 7.00 plus 10% of the order. If the total is from 50.01 to 100, the cost will be 12.00 plus 9% of the order total. If the cost is 100.01 or greater, then 5% of the order total will be used as the shipping cost.

upsg
  The next, upsg, is a special case. It specifies a UPS lookup based on your UPS zone and two required values (and two optional arguments):

          1. Weight (careful, always use weight for this one!)
          2. The zip/postal code of the recipient, of which only
             the first three digits are used.
          3. A fixed amount to add to the cost found in the UPS
             tables (use 0 as a placeholder if specifying roundup)
          4. If set to 'round', will round the cost up to the next
             integer monetary unit.

  If the cost returned is zero, the reason will be placed as an error message in the session variable ship_message (available as `[data session ship_message]`).

  UPS weights are always rounded up if any fraction is present.

  The routines use standard UPS lookup tables. First, the UPS Zone file must be present. That is a standard UPS document, specific to your area, that you must obtain from UPS and enter into and make available to MiniVend in TAB-delimited format. (As of March 1997, you can use the standard .csv file distributed by UPS on their web site at www.ups.com.) You specify it with the UpsZoneFile directive -- it is usually named something like `NNN.csv`, where NNN is the first three digits of the originating zip code. If you place it in your products directory, then the directive would look like:

          UPSZoneFile  products/450.csv

  Second, you must obtain the cost tables from UPS (again, you can get them from www.ups.com) and place them into a MiniVend database. That database, its identifier specified with the first argument (Ground in the example) of the cost specification, is consulted to determine the UPS cost for that weight and rate schedule.

  In the example below, you would want a database specification like:

          Database  Ground  Ground.csv  CSV

  You can append a simple shipping cost qualification to a UPS lookup. If any additional parameters are present after the five usual ones used for UPS lookup, they will be interpreted as a Perl subroutine call. The syntax is the same as if it was encased in the tag `[perl sub] [/perl]`, but the following substitutions are made prior to the call:

          @@COST@@  is replaced with whatever the UPS lookup returned
          @@GEO@@   is replaced with the zip (or other geo code)
          @@ADDER@@ is replaced with the defined adder
          @@TYPE@@  is replaced with the UPS shipping type
          @@TOTAL@@ is replaced with the total weight

  The example above also illustrates geographic qualification. If the value of the form variable state on the checkout form is AK or HI, the U.S. states Alaska and Hawaii, a $10.00 additional charge (over and above the normal 2.00 handling charge) is made. This can also be used to select on country, product type, or any other qualification that can be encoded in the file.

upsca
  The next entry is just like the UPS definition except it defines a different lookup zone file (`products/can.csv`) and uses a different database, upsca. It also disables the global PriceDivide option for itself only, not allowing currency conversion. Otherwise, the process is the same.

  You can define up to 27 different lookup zones in the same fashion. If one of the cost lines (the last field) in the `shipping.asc` file begins with a ``c'', it configures another lookup zone, which must be lettered from A to `Z`. It takes the format:

          c X name file* length* multiplier*

  where X is the letter from `A-Z`. The name is used internally as an identifier and must be present. The optional file is relative to the catalog root (like UpsZoneFile is) -- if it is not present the file equal to name in the products directory (ProductDir) will be used as the zone file. If the optional digit `length` is present, that determines the number of signficant digits in the passed postal/geo code. When the optional `multiplier` is present, the weight is multiplied by it before doing the table lookup. This allows shipping weights in pounds or kilograms to be adapted to a table using the opposite as the key. Remember, the match on weight must be exact, and MiniVend rounds the weight up to the next even unit.

  To define the exact equivalent of the UPS lookup zone, you would do:

          c U UPS products/450.csv 3 1

  The only difference is that the beginning code to call the lookup is upper-case `U` instead of lower-case u.

fedex
  The last entry, fedex, uses a named subroutine. The example is designed to work with this subroutine defined in catalog.cfg:

          Sub <<EOF
          sub fedex_cost {
              my($country) = @_;
              my $cost;
              if($country =~ /^usa?$/i) {
                  $cost = 20;
              }
              else {
                  $cost = 50;
              }
              return $cost;
          }
          EOF

  NOTE: The text above appears indented, but in the catalog.cfg file it must begin at the beginning of the line. Also, make sure you upload in ASCII mode -- carriage returns are not tolerated.

  It will simply return a cost of 20 if the country the user has entered is US or USA -- and return 50 otherwise. Obviously much more complicated routines can be defined. Read the following only if you know Perl well and/or are not of faint heart.

  You can call named subroutines with any of the methods, defined with `[set name] your_perl_code_here [/set]`, Sub, or GlobalSub.

  If parameters are specified, separated by commas, they will be taken as either fixed values or as database fields to be sent to the subroutine in an anonymous hash keyed on the item code (for each item in the *current* shopping cart).

  If a database other than the products database is to be used, the database name should be prepended with a colon (`:`) separator. If a key other than the item code is to be used, it should be appended with a semi-colon separator.

  To send fixed value to the subroutine (appended to the call reference as an array of fixed scalar parameters), begin the parameter with a semicolon. They will be appended globally after the hash reference.

  Examples

        # Sends the weight of each item from the products database

        weight

        # Sends the value of the handling field from the
        # special database for each item

        special:handling

        # Sends the value of the 'adder' field from the special
        # database, for the value the user has entered for 'country'
        # The spaces around the separators are OK

        special : adder ; [value country]

        # Sends a fixed parameter of 20 to the subroutine

        ;20

  The parameters are interpreted for MiniVend tags before being parsed. Here is a complete example:

         s item_cost weight,modes:[value mv_shipmode];[value country], ;20, ;25

        items in the shopping cart:  00-0011 19=202

        ------- product database  ----

        code    weight   description      price
        00-0011   8      The Mona Lisa    1000
        19-202    12     American Gothic  800

        ------- modes database  ----

        code    upsg  upsb  upsr  postal_air postal_surface
        UK        0    0     0       1            1

  will call the subroutine `item_cost`, and will send the weight of each item, along with the value of the modes database column corresponding to the shipping mode the user has selected, keyed with the value of country on their order form. If the user has selected mode postal_air, and is in the country coded as `UK`, the subroutine will be called as if it was:

            item_cost( {
                          '00-0011' => {postal_air => '1', weight => '8'},
                          '19-202' => {postal_air => '1', weight => '12'},
                       }, 20, 25 )

  If the undefined value is returned by the routine, the next shipping mode will be tried. If a non-numeric string value is returned, its value will be placed as an error message in the session variable ship_message (available as `[data session ship_message]`) and a zero cost will be returned. If any number or the empty string is returned, it will be used as the shipping cost (even 0).

### Index Up << >>