[ic] Using FedEx instead of UPS

Mike Heins mikeh@minivend.com
Fri, 23 Feb 2001 13:39:28 -0500


Quoting Chet Pressler (chet@pressler.com):
> Is there a FedEx tables that are already to go for interchange that are 
> available somewhere? Or do we have to goto the fedex site and download the 
> tables and do this manually. I hate to reinvent the wheel here.
> 

No, no tables exist. However, Jean-Phillipe Bouchard and Francois Belanger
of sitepak.com did an excellent online query module for Fedex, which was
posted to this list (I think you can search for Business::Fedex). It
works on conjunction with this global UserTag to implement all FedEx
modes via online query.

This tag does Fedex ground without the Business::Fedex module.

At that point, you just make the criteria weight and the cost in 
shipping.asc be:  [fedex-query mode=THEMODE weight="@@TOTAL@@"] (assuming
UPS_ORIGIN is set ala the Interchange UI).

UserTag  fedex-query  Order  mode weight
UserTag  fedex-query  attrAlias origin_zip origin
UserTag  fedex-query  addAttr
UserTag  fedex-query  Routine <<EOR
my $can_do_ground;
my $can_do_express;
sub {
 	my( $mode, $weight, $opt) = @_;
	BEGIN {
		eval {
			require LWP::Simple;
			$can_do_ground = 1;
		};
	};
	BEGIN {
		eval {
			require Business::Fedex;
			$can_do_express = 1;
		};
	};
	my $die = sub {
		my ($msg, @args) = @_;
		$msg = ::errmsg($msg, @args);
		$Vend::Session->{ship_message} .= " $msg";
		return 0;
	};

	my $fed;

	$opt->{target_url} = 'http://grd.fedex.com/cgi-bin/rrr2010.exe'
		unless $opt->{target_url};
	$opt->{origin}	= $::Variable->{UPS_ORIGIN}
						if ! $opt->{origin};
	$opt->{country}	= $::Values->{$::Variable->{UPS_COUNTRY_FIELD}}
						if ! $opt->{country};
	$opt->{zip}		= $::Values->{$::Variable->{UPS_POSTCODE_FIELD}}
					if ! $opt->{zip};
	$opt->{country} = uc $opt->{country};

	$opt->{origin_country} = $::Variable->{COUNTRY} || 'US'
		if ! $opt->{origin_country};

	if($can_do_express and (! $opt->{cache} || ! $Vend::fedex_object) ) {
		eval {
			$Vend::fedex_object = new Business::Fedex (
				orig_country => $opt->{origin_country},
				orig_zip =>	$opt->{origin},
				weight => $opt->{weight},
				dest_country => $opt->{country},
				dest_zip => $opt->{zip},
				packaging => $opt->{packaging} || 'My Packaging',
			);
			$Vend::fedex_object->getrate;
		};
		return $die->($@) if $@;
	}
	$fed = $Vend::fedex_object if $can_do_express;

	my %is_express = (
		'FPO' => 1,
		'FSO' => 1,
		'F2D' => 1,
		'FES' => 1,
		'FIE' => 1,
		'FIP' => 1,
	);
	my %fe_map = (
    'FedEx Ground'                 => 'FEG',
    'FedEx Home Delivery'          => 'FEH',
    'FedEx Priority Overnight'     => 'FPO',
    'FedEx Standard Overnight'     => 'FSO',
    'FedEx 2-Day'                  => 'F2D',
    'FedEx Express Saver'          => 'FES',
    'FedEx International Priority' => 'FIP',
    'FedEx International Economy'  => 'FIE',
	);
	@fe_map{values %fe_map} = @fe_map{keys %fe_map};
Debug("fed=" . ::uneval($fed));
	my @services;
Debug("can_ground=$can_do_ground country=$opt->{country} orig_country=$opt->{origin_country}");
	if($opt->{services}) {
Debug("can_ground=$can_do_ground country=$opt->{country} orig_country=$opt->{origin_country}");
		if(
			$can_do_ground
			and ($opt->{country} eq 'US' or $opt->{country} eq 'CA')
			and $opt->{origin_country} eq 'US'
		  )
		{
			push @services, 'FEG';
			push @services, 'FEH';
		}
		if($fed) {
			for ( $fed->services() ) {
				push @services, $fe_map{$_->{service}};
			}
		}
		return join ( ($opt->{joiner} || ' '), @services);
	}
	
	if($fed and $is_express{$opt->{mode}}) {
		for ( $fed->services() ) {
			next unless $fe_map{$_->{service}} eq $opt->{mode};
			return $_->{total};
		}
		return 0;
	}
#::logGlobal("calling with: " . join("|", $mode, $origin, $zip, $weight, $country));

	if($opt->{mode} eq 'FEH') {
		$opt->{mode} = 'HomeD';
	}
	else {
		$opt->{mode} = 'Ground';
	}

	my @required = qw/
		function
		mode
		origin
		origin_country
		zip
		country
		weight
	/;
	my @opt = qw/
		length
		height
		width
		dimunit
		weightunit
		accessorial
	/;
	my %map = qw/
		function		func
		zip				DestZip
		country			DestCountryCode
		weight			Weight
		mode			Screen
		origin			OriginZip
		origin_country	OriginCountryCode
		length			Length
		height			Height
		width			Width
		dimunit			DimUnit
		weightunit		WeightUnit
		accessorial		AccessReturn
	/;

	$opt->{function} = 'Rate'
		unless length $opt->{function};

	my @parms;

	for(@required) {
		return $die->("Fedex mode %s: required parameter %s missing", $mode, $_)
			unless length $opt->{$_};
		push @parms, "$map{$_}=" . Vend::Util::hexify($opt->{$_});
	}
	for(@opt) {
		next unless length $opt->{$_};
		push @parms, "$map{$_}=" . Vend::Util::hexify($opt->{$_});
	}

	my $url = $opt->{target_url} . '?' . join('&', @parms);
	
	return $url if $opt->{test};
	my $return = LWP::Simple::get($url);

	return $die->('Unable to access Fedex calculator.')
		if ! length($return);
	
	my %result;
	while( $return =~ m{<!(\w+)>(.*)<!/\1>}gs ) {
		$result{$1} = $2;
	}

	return $Vend::Interpolate::Tmp->{$opt->{hashref}} = \%result
		if $opt->{hashref};

	if(! $result{TotalCharges}) {
		return $die->("Error on Fedex calculation: %s", $result{Error});
	}

	return $result{TransitTime} if $opt->{transit_time};
Debug("mode=$opt->{mode} total=$result{TotalCharges}");
	return $result{TotalCharges};
}
EOR

-- 
Red Hat, Inc., 131 Willow Lane, Floor 2, Oxford, OH  45056
phone +1.513.523.7621 fax 7501 <mheins@redhat.com>

Experience is what allows you to recognize a mistake the second
time you make it. -- unknown