1 # Vend::Ship::QueryUPS - Interchange shipping code
3 # $Id: QueryUPS.pm,v 1.8 2008-05-14 16:21:02 mheins Exp $
5 # Copyright (C) 2002-2007 Interchange Development Group
6 # Copyright (C) 1996-2002 Red Hat, Inc.
8 # This program was originally based on Vend 0.2 and 0.3
9 # Copyright 1995 by Andrew M. Wilcox <amw@wilcoxsolutions.com>
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 2 of the License, or
14 # (at your option) any later version.
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
21 # You should have received a copy of the GNU General Public
22 # License along with this program; if not, write to the Free
23 # Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
26 package Vend::Ship::QueryUPS;
29 use Vend::Interpolate;
34 my $Have_Business_UPS;
36 require Business::UPS;
38 $Have_Business_UPS = 1;
42 my ($mode, $weight, $row, $opt, $tagopt, $extra) = @_;
44 unless($Have_Business_UPS) {
45 do_error("Ship mode %s: Requires installation of Business::UPS", $mode);
48 $opt->{service} ||= $opt->{table};
49 if(! $opt->{service} and $extra =~ /^\w+$/) {
50 $opt->{service} = $extra;
52 $opt->{service} ||= $opt->{table} || $mode;
54 $opt->{origin} ||= $::Variable->{UPS_ORIGIN};
55 $opt->{country_field} ||= $::Variable->{UPS_COUNTRY_FIELD} || 'country';
56 $opt->{geo} ||= $::Variable->{UPS_POSTCODE_FIELD} || 'zip';
58 my $origin = $opt->{origin};
59 my $country = $opt->{country} || $::Values->{$opt->{country_field}};
61 $country ||= $opt->{default_country} || 'US';
63 my $zip = $opt->{zip} || $::Values->{$opt->{geo}};
64 $zip ||= $opt->{default_geo};
66 my $modulo = $opt->{aggregate};
68 if($modulo and $modulo <= 1) {
69 $modulo = $::Variable->{UPS_QUERY_MODULO} || 150;
75 $country = uc $country;
77 my %exception = ( UK => 'GB');
79 if(! $::Variable->{UPS_COUNTRY_REMAP} ) {
82 elsif ($::Variable->{UPS_COUNTRY_REMAP} =~ /=/) {
83 my $new = Vend::Util::get_option_hash($::Variable->{UPS_COUNTRY_REMAP});
84 Vend::Util::get_option_hash(\%exception, $new);
87 Vend::Util::hash_string($::Variable->{UPS_COUNTRY_REMAP}, \%exception);
90 $country = $exception{$country} if $exception{$country};
92 # In the U.S., UPS only wants the 5-digit base ZIP code, not ZIP+4
93 $country eq 'US' and $zip =~ /^(\d{5})/ and $zip = $1;
95 #::logDebug("calling QueryUPS with: " . join("|", $opt->{service}, $origin, $zip, $weight, $country,$modulo));
107 my $ctable = $opt->{cache_table} || 'ups_cache';
110 if($Vend::Database{$ctable}) {
111 $Vend::WriteDatabase{$ctable} = 1;
115 my $tname = $db->name();
117 $weight = ceil($weight);
123 shipmode => $opt->{service},
127 # reverse sort makes zip first
128 for(reverse sort keys %cline) {
129 push @items, "$_ = " . $db->quote($cline{$_}, $_);
132 my $string = join " AND ", @items;
133 my $q = qq{SELECT code,cost,updated from $tname WHERE $string};
134 my $ary = $db->query($q);
135 #::logDebug("query cache: " . ::uneval($ary));
136 if($ary and $ary->[0] and $cache_code = $ary->[0][0]) {
137 $shipping = $ary->[0][1];
138 $updated = $ary->[0][2];
140 if($now - $updated > $Variable->{UPS_CACHE_EXPIRE} || 86000) {
144 elsif($shipping <= 0) {
150 #::logDebug("shipping is: " . (defined $shipping ? $shipping : 'undef'));
158 unless(defined $shipping) {
160 while($w > $modulo) {
163 $shipping += $maxcost;
167 ($maxcost, $zone, $error)
168 = getUPS( $opt->{service}, $origin, $zip, $modulo, $country);
170 do_error( "Ship mode %s: Error calling UPS service %s",
175 $shipping += $maxcost;
179 #::logDebug("calling getUPS( $opt->{service}, $origin, $zip, $w, $country)");
180 ($tmpcost, $zone, $error)
181 = getUPS( $opt->{service}, $origin, $zip, $w, $country);
183 $shipping += $tmpcost;
185 $cline{updated} = $now || time();
186 $cline{cost} = $shipping || $error;
187 $db->set_slice($cache_code, \%cline);
192 do_error( "Ship mode %s: Error calling UPS service %s",
202 Vend::Ship::QueryUPS -- calculate UPS costs via www
208 Shipping QueryUPS default_geo 45056
211 ground: UPS Ground Commercial
217 cost e Nothing to ship!
225 cost e Too heavy for UPS.
229 Calculates UPS costs via the WWW using Business::UPS.
231 To activate, configure any parameter in catalog.cfg. A good choice
232 is the default origin zip.
240 Weight in pounds. Required -- normally passed via CRIT parameter.
244 Any valid Business::UPS mode (required). Example: 1DA,2DA,GNDCOM. Defaults
249 Location of field containing zip code. Default is 'zip'.
253 Location of field containing country code. Default is 'country'.
257 The ZIP code to use if none supplied -- for defaulting shipping to some
258 value in absence of ZIP. No default -- will return 0 and error if
261 =item default_country
263 The country code to use if none supplied -- for defaulting shipping to some
264 value in absence of country. Default US.
268 If 1, aggregates by a call to weight=150 (or $Variable->{UPS_QUERY_MODULO}).
269 Multiplies that times number necessary, then runs a call for the
270 remainder. In other words:
272 [ups-query weight=400 mode=GNDCOM aggregate=1]
277 [ups-query weight=150 mode=GNDCOM] +
278 [ups-query weight=150 mode=GNDCOM] +
279 [ups-query weight=100 mode=GNDCOM];
282 If set to a number above 1, will be the modulo to do repeated calls by. So:
284 [ups-query weight=400 mode=GNDCOM aggregate=100]
289 [ups-query weight=100 mode=GNDCOM] +
290 [ups-query weight=100 mode=GNDCOM] +
291 [ups-query weight=100 mode=GNDCOM] +
292 [ups-query weight=100 mode=GNDCOM];
295 To aggregate by 1, use .999999.
299 Set to the name of a table (default ups_cache) which can cache the
300 calls so repeated calls for the same values will not require repeated
303 Table needs to be set up with:
305 Database ups_cache ship/ups_cache.txt __SQLDSN__
306 Database ups_cache AUTO_SEQUENCE ups_cache_seq
307 Database ups_cache DEFAULT_TYPE varchar(12)
308 Database ups_cache INDEX weight origin zip shipmode country
312 code weight origin zip country shipmode cost updated
314 Typical cached data will be like:
316 code weight origin zip country shipmode cost updated
317 14 11 45056 99501 US 2DA 35.14 1052704130
318 15 11 45056 99501 US 1DA 57.78 1052704130
319 16 11 45056 99501 US 2DA 35.14 1052704132
320 17 11 45056 99501 US 1DA 57.78 1052704133
322 Cache expires in one day.