5198938; #--------------------------------------------------------------- my $pMessageList = [ 'The shipping price is formatted incorrectly. It should be formatted like %s.', 'The shipping price is too large. The price must be less than %s.', 'The shipping price is too small. The price must be greater than or equal to %s.', 'The class/location combination you selected were invalid. Please check and re-enter your selection.', 'The catalog shipping database does not have any shipping options defined for this location. Please contact us directly with your order.', 'Free Shipping', 'Standard Shipping', 'Your order has exceeded the shipping tables defined by the supplier, therefore it is not possible to calculate the shipping cost. Please contact the supplier with this information as they will be happy to process your order and will then be able to correct the shipping tables.
Thank you.',
'Please enter a shipping cost.',
'Please select a state or province.',
];
my %ZoneTable = (
"UK" => {
"UndefinedRegion" => [13],
},
"US" => {
"UndefinedRegion" => [10],
},
"CA" => {
"UndefinedRegion" => [10],
},
"AU" => {
"UndefinedRegion" => [10],
},
"AT" => {
"UndefinedRegion" => [11],
},
"BE" => {
"UndefinedRegion" => [11],
},
"BG" => {
"UndefinedRegion" => [11],
},
"CY" => {
"UndefinedRegion" => [11],
},
"CZ" => {
"UndefinedRegion" => [11],
},
"DK" => {
"UndefinedRegion" => [11],
},
"EE" => {
"UndefinedRegion" => [11],
},
"FI" => {
"UndefinedRegion" => [11],
},
"FR" => {
"UndefinedRegion" => [11],
},
"DE" => {
"UndefinedRegion" => [11],
},
"GR" => {
"UndefinedRegion" => [11],
},
"HU" => {
"UndefinedRegion" => [11],
},
"IE" => {
"UndefinedRegion" => [11],
},
"IT" => {
"UndefinedRegion" => [11],
},
"LV" => {
"UndefinedRegion" => [11],
},
"LT" => {
"UndefinedRegion" => [11],
},
"LU" => {
"UndefinedRegion" => [11],
},
"MT" => {
"UndefinedRegion" => [11],
},
"NL" => {
"UndefinedRegion" => [11],
},
"NZ" => {
"UndefinedRegion" => [10],
},
"PL" => {
"UndefinedRegion" => [11],
},
"PT" => {
"UndefinedRegion" => [11],
},
"RO" => {
"UndefinedRegion" => [11],
},
"SK" => {
"UndefinedRegion" => [11],
},
"SI" => {
"UndefinedRegion" => [11],
},
"ES" => {
"UndefinedRegion" => [11],
},
"SE" => {
"UndefinedRegion" => [11],
},
);
my %ClassTable = (
6 => ['Overseas', 0, ''],
7 => ['Royal Mail Airsure', 0, ''],
38 => ['Recorded Delivery', 1, ''],
40 => ['Click & Collect', 0, ''],
6 => ['Overseas', 0, ''],
6 => ['Overseas', 0, '']
);
my $phashDefinedCategories =
{
'Normal' => 1, 'Collection' => 1, 'Badges' => 1, 'Tickets' => 1, 'Door Mat' => 1, 'Programmes' => 1, 'Calendar' => 1, 'Large Letter' => 1,
};
my $sDefaultCategory = 'Normal';
my %ShippingTable = (
6 =>
{
10 => [ {'CalculationBasis' => 1, 'WeightFactor' => 1.000000, 'AltWeightFactor' => 1.000000, 'TaxAppliesToShipping' => 0, 'ShippingCostsIncludeTax' => 1, 'ExcessAction' => 'Highest'}, { "wt" => 20, "cost" => 1500}, ],
14 => [ {'CalculationBasis' => 0, 'WeightFactor' => 1.000000, 'AltWeightFactor' => 1.000000, 'TaxAppliesToShipping' => 1, 'ShippingCostsIncludeTax' => 1, 'ExcessAction' => 'Error'}, ],
15 => [ {'CalculationBasis' => 1, 'WeightFactor' => 1.000000, 'AltWeightFactor' => 1.000000, 'TaxAppliesToShipping' => 1, 'ShippingCostsIncludeTax' => 1, 'ExcessAction' => 'Error'}, ],
},
7 =>
{
11 => [ {'CalculationBasis' => 1, 'WeightFactor' => 1.000000, 'AltWeightFactor' => 1.000000, 'TaxAppliesToShipping' => 0, 'ShippingCostsIncludeTax' => 1, 'ExcessAction' => 'Highest'}, { "wt" => 20, "cost" => 1000}, ],
},
38 =>
{
13 => [ {'CalculationBasis' => 6, 'WeightFactor' => 1.000000, 'AltWeightFactor' => 1.000000, 'TaxAppliesToShipping' => 0, 'ShippingCostsIncludeTax' => 1, 'ExcessAction' => 'Error'}, {'Normal' => {'Fixed' => 475, 'PerItem' => 0}, 'Collection' => {'Fixed' => 0, 'PerItem' => 0}, 'Badges' => {'Fixed' => 200, 'PerItem' => 0}, 'Tickets' => {'Fixed' => 200, 'PerItem' => 0}, 'Door Mat' => {'Fixed' => 600, 'PerItem' => 0}, 'Programmes' => {'Fixed' => 200, 'PerItem' => 0}, 'Calendar' => {'Fixed' => 500, 'PerItem' => 0}, 'Large Letter' => {'Fixed' => 300, 'PerItem' => 0}, }, ],
},
40 =>
{
13 => [ {'CalculationBasis' => 6, 'WeightFactor' => 1.000000, 'AltWeightFactor' => 1.000000, 'TaxAppliesToShipping' => 0, 'ShippingCostsIncludeTax' => 1, 'ExcessAction' => 'Error'}, {'Normal' => {'Fixed' => 0, 'PerItem' => 0}, 'Collection' => {'Fixed' => 0, 'PerItem' => 0}, 'Badges' => {'Fixed' => 0, 'PerItem' => 0}, 'Tickets' => {'Fixed' => 0, 'PerItem' => 0}, 'Door Mat' => {'Fixed' => 0, 'PerItem' => 0}, 'Programmes' => {'Fixed' => 0, 'PerItem' => 0}, 'Calendar' => {'Fixed' => 0, 'PerItem' => 0}, 'Large Letter' => {'Fixed' => 0, 'PerItem' => 0}, }, ],
},
);
my $phashWeightConfiguration =
{
0 => {'UseWeightIfUndefined' => 0, 'DefaultWeight' => '0.25' ,'OptimalWeight' => '' ,},
4 => {'UseWeightIfUndefined' => 0, 'DefaultWeight' => '0.25' ,'OptimalWeight' => '' ,},
5 => {'UseWeightIfUndefined' => 0, 'DefaultWeight' => '' ,'OptimalWeight' => '' ,},
};
my ($ShippingBasis, $SimpleCost, $UnknownRegion, $UnknownRegionCost, $WaiveCharges, $WaiveThreshold);
$ShippingBasis = 'ByZoneClass';
$UnknownRegion = 'Default';
$UnknownRegionCost = 1000;
$WaiveCharges = 'No';
$WaiveThreshold = 100000.000000;
my $bPricesIncludesTax = 1;
my $dTaxInclusiveMultiplier = 1.200000;
my $nHandlingCharge = 0;
my $nHandlingProportion = 0;
my %ParentZoneTable = (
"US" => [10, ],
"CA" => [10, ],
);
use strict;
my $UNDEFINED = 'UndefinedRegion';
my $sOnlineError = '';
$::UPS_XPCI_VERSION = '1.0001';
$::UPS_SUCCESSFUL = '1';
$::UPS_FAILED = '0';
$::XML_HEADER = "";
$::UPS_XML_RESPONSE = 'Response';
$::UPS_XML_RESPONSE_STATUS_CODE = 'ResponseStatusCode';
$::UPS_XML_RESPONSE_STATUS_DESCRIPTION = 'ResponseStatusDescription';
$::UPS_XML_ERROR = 'Error';
$::UPS_XML_ERROR_DESCRIPTION = 'ErrorDescription';
$::UPS_XML_ERROR_SEVERITY = 'ErrorSeverity';
$::UPS_XML_ADDRESS_VALIDATION_RESULT = 'AddressValidationResult';
$::UPS_XML_RATED_SHIPMENT = 'RatedShipment';
$::UPS_XML_SERVICE = 'Service';
$::UPS_XML_SERVICE_CODE = 'Code';
$::UPS_XML_TOTAL_CHARGES = 'TotalCharges';
$::UPS_XML_CURRENCY_CODE = 'CurrencyCode';
$::UPS_XML_MONETARY_VALUE = 'MonetaryValue';
$::UPS_XML_RANK = 'Rank';
$::UPS_XML_QUALITY = 'Quality';
$::UPS_XML_ADDRESS = 'Address';
$::UPS_XML_STATE_PROVINCE_CODE = 'StateProvinceCode';
$::UPS_XML_CITY = 'City';
$::UPS_XML_POSTAL_CODE_LOW_END = 'PostalCodeLowEnd';
$::UPS_XML_POSTAL_CODE_HIGH_END = 'PostalCodeHighEnd';
$::UPS_ERROR_SEVERITY_TRANSIENT_ERROR = 'Transient';
$::UPS_ERROR_SEVERITY_HARD_ERROR = 'Hard';
$::UPS_ERROR_SEVERITY_WARNING = 'Warning';
my $ssl_socket;
%::s_Ship_nShippingStatus = ();
%::s_Ship_sShippingError = ();
%::s_Ship_PreliminaryInfoVariables = ();
%::s_Ship_ShippingVariables = ();
$::s_Ship_bPrelimIsHidden = $::FALSE;
$::s_Ship_bShipPhaseIsHidden = $::FALSE;
$::s_Ship_sShippingDescription = '';
$::s_Ship_sHandlingDescription = ''; # not used in this plug-in
$::s_Ship_sShippingCountryName = '';
$::s_Ship_nShipCharges = 0;
$::s_Ship_nShipOptions = 0;
$::s_Ship_nShippingStatus{GetHandlingDescription} = $::SUCCESS;
$::s_Ship_sShippingError{GetHandlingDescription} = '';
$::s_Ship_bDisplayExtraCartInformation = $::FALSE;
%::s_Ship_hShippingClassProviderIDs = ();
%::s_Ship_hBasePlusPerProviderIDs = ();
$::s_Ship_nSSPProviderID = -1;
$::s_Ship_bTaxAppliesToShipping = $::FALSE;
$::s_Ship_sGFSCarrierAndService = '';
$::s_Ship_bInternationalShippingZone = $::FALSE;
$::UPS_CLASSES_NOT_USED = 0;
$::UPS_CLASSES_USED = 1;
$::UPS_BASEPLUSPER_CLASSES_USED = 2;
my %hSSPUsed;
my $bUPS_Available = $::TRUE;
my $sCONFIRM_BY_EMAIL = 'Actinic:ConfirmByEmail';
@::s_arrSortedShippingHashes;
$::SimpleCost = $SimpleCost;
$::ShippingBasis = $ShippingBasis;
$::UnknownRegion = $UnknownRegion;
$::UnknownRegionCost = $UnknownRegionCost;
$::UnknownRegionLabel = $$pMessageList[6];
$::FreeShippingLabel = $$pMessageList[5];
local %::s_hashShipData;
local %::s_hashClassToWeightCost;
my $c_nWeight = 0;
my $c_nQuantity = 1;
my $c_nPrice = 2;
my $c_nSimple = 3;
my $c_nAlternateWeight = 4;
my $c_nMaximumWeight = 5;
my $c_nPerItemShipping = 6;
$::dShippingSupplements = 0;
$::dHandlingSupplements = 0;
$::s_Ship_nAdjustedTotalQuantity = undef;
my @arrFuncns =
(
[\&ValidatePreliminaryInput, 'ValidatePreliminaryInput'],
[\&ValidateFinalInput, 'ValidateFinalInput'],
[\&RestoreFinalUI, 'RestoreFinalUI'],
[\&CalculateShipping, 'CalculateShipping'],
[\&IsFinalPhaseHidden, 'IsFinalPhaseHidden'],
[\&GetShippingDescription, 'GetShippingDescription'],
[\&CalculateHandling, 'CalculateHandling'],
);
OpaqueToHash();
my ($parrFunction, $nReturnCode, $sError);
$nReturnCode = $::SUCCESS;
foreach $parrFunction (@arrFuncns)
{
my $pFunction = $$parrFunction[0];
($nReturnCode, $sError) = &$pFunction();
$::s_Ship_nShippingStatus{$$parrFunction[1]} = $nReturnCode;
$::s_Ship_sShippingError{$$parrFunction[1]} = $sError;
}
if(defined $::s_hashShipData{InternationalShipping})
{
$::s_Ship_bInternationalShippingZone = $::s_hashShipData{InternationalShipping};
}
else
{
$::s_Ship_bInternationalShippingZone = $::FALSE;
}
SaveSelectionToOpaqueData();
my $nClassID;
foreach $nClassID (keys(%ClassTable))
{
push (@::s_ShipClassList, $ClassTable{$nClassID}[0]);
}
return($::SUCCESS);
sub ValidatePreliminaryInput
{
if ($ShippingBasis eq 'Simple')
{
return($::SUCCESS, undef);
}
if ($WaiveCharges eq 'Value' &&
CalculatePrice() > $WaiveThreshold)
{
return(SetFreeShipping());
}
if($::s_sDeliveryCountryCode eq '')
{
return(SetUndefinedShipping());
}
if($::s_sDeliveryCountryCode eq $ActinicOrder::REGION_NOT_SUPPLIED)
{
return(SetDefaultCharge());
}
if ($::s_sDeliveryRegionCode eq "" ||
$::s_sDeliveryRegionCode eq $UNDEFINED)
{
if (defined $ParentZoneTable{$::s_sDeliveryCountryCode} &&
$#{$ParentZoneTable{$::s_sDeliveryCountryCode}} == -1)
{
return ($::FAILURE, $$pMessageList[9]);
}
}
my $pProviderList = GetSSPProviderList($::s_sDeliveryCountryCode);
if (keys %ZoneTable == 0 &&
@$pProviderList == 0 )
{
return(SetDefaultCharge());
}
if($::g_pSSPSetupBlob &&
$$::g_pSSPSetupBlob{1}{'AVSEnabled'} &&
(exists $::g_InputHash{'LocationDeliveryCountry'} || exists $::g_InputHash{DELIVERADDRESSSELECT}))
{
my $sCity = $::g_ShipContact{'ADDRESS3'};
my ($Result, $sSSPError) = DoUPSAddressValidation(ActinicLocations::GetISODeliveryCountryCode(),
ActinicLocations::GetISODeliveryRegionCode(), $sCity, $::g_LocationInfo{DELIVERPOSTALCODE});
if($Result == $::BADDATA)
{
if($sCity eq '')
{
SetUndefinedShipping();
}
return($::FAILURE, $sSSPError);
}
}
return($::SUCCESS, undef);
}
sub ValidateFinalInput
{
if ($ShippingBasis eq 'Simple')
{
return(SimpleValidateFinalInput());
}
if(@::s_arrSortedShippingHashes > 0)
{
return($::SUCCESS, undef);
}
my ($nReturnCode, $sError);
if(@::s_arrSortedShippingHashes == 0)
{
($nReturnCode, $sError) = CalculateMultiPackageShipping();
if($nReturnCode != $::SUCCESS)
{
return($nReturnCode, $sError);
}
}
SaveSelectionToOpaqueData();
return($::SUCCESS, undef);
}
sub RestoreFinalUI
{
if ($ShippingBasis eq 'Simple')
{
return(SimpleRestoreFinalUI());
}
my ($phashShipping, $sClassLabel, $sClassID, $sSelectHTML);
my $sPriceLabelFormat = ' (%s)';
$::s_Ship_nShipOptions = @::s_arrSortedShippingHashes;
if (@::s_arrSortedShippingHashes == 1)
{
$phashShipping = $::s_arrSortedShippingHashes[0];
$sClassLabel = $$phashShipping{ShippingLabel};
if ($::s_Ship_bDisplayPrices)
{
my (@PriceResponse) =
ActinicOrder::FormatPrice($$phashShipping{Cost},
$::TRUE,
\%::s_Ship_PriceFormatBlob);
$sClassLabel .= sprintf($sPriceLabelFormat, $PriceResponse[2]);
}
$sSelectHTML =
sprintf("%s\n",
$sClassLabel,
$$phashShipping{ShippingClass});
}
elsif (@::s_arrSortedShippingHashes > 1)
{
$sSelectHTML = "\n";
}
if($hSSPUsed{$::UPS_CLASSES_USED} == $::TRUE)
{
$::s_Ship_hShippingClassProviderIDs{1} = $::TRUE;
}
elsif ($hSSPUsed{$::UPS_BASEPLUSPER_CLASSES_USED} == $::TRUE)
{
$::s_Ship_hBasePlusPerProviderIDs{1} = $::TRUE;
}
$::s_Ship_ShippingVariables{$::VARPREFIX . 'SHIPPINGSELECT'} = $sSelectHTML;
return($::SUCCESS, undef);
}
sub CalculateShipping
{
if ($ShippingBasis eq 'Simple')
{
return(SimpleCalculateShipping());
}
if(@::s_arrSortedShippingHashes == 0)
{
return($::SUCCESS, undef);
}
if($::s_hashShipData{'ShippingClass'} =~ /^(\d+)_(.+)/)
{
$::s_Ship_nSSPProviderID = $1;
my $bSSPError = $2 eq $sCONFIRM_BY_EMAIL;
my $pSSPProvider = GetUPSSetup();
$::s_Ship_sSSPOpaqueShipData =
sprintf("SSPID=%d;SSPClassRef=%s;OrigZip=%s;OrigCntry=%s;OrigCntryDesc=%s;Pack=%s;Rate=%s;Weight=%.03f;DestCntry=%s;DestPost=%s;Residential=%s;",
$::s_Ship_nSSPProviderID,
$2,
$$pSSPProvider{ShipperPostalCode},
$$pSSPProvider{ShipperCountry},
ACTINIC::GetCountryName($$pSSPProvider{ShipperCountry}),
$$pSSPProvider{'PackagingType'},
$$pSSPProvider{'RateChart'},
$::s_hashShipData{BasisTotal},
$::s_sDeliveryCountryCode,
$::g_ShipContact{'POSTALCODE'},
$::g_ShipContact{'RESIDENTIAL'} ne '' ? 1 : 0
);
if($::s_Ship_nSSPProviderID == 1)
{
if(!$bSSPError)
{
$::s_Ship_bDisplayExtraCartInformation = $::TRUE;
}
}
}
return($::SUCCESS, undef);
}
sub IsFinalPhaseHidden
{
if ($ShippingBasis eq 'Simple')
{
return($::SUCCESS, undef);
}
if ((@::s_arrSortedShippingHashes < 1) ||
(scalar @::s_Ship_sShipProducts == 0))
{
$::s_Ship_bShipPhaseIsHidden = $::TRUE;
}
return($::SUCCESS, undef);
}
sub GetShippingDescription
{
if(defined $::s_hashShipData{ShippingLabel})
{
$::s_Ship_sShippingDescription =
$::s_hashShipData{ShippingLabel};
}
else
{
$::s_Ship_sShippingDescription = '';
}
if(defined $::s_hashShipData{GFSCarrierAndService})
{
$::s_Ship_sGFSCarrierAndService = $::s_hashShipData{GFSCarrierAndService};
}
else
{
$::s_Ship_sGFSCarrierAndService = '';
}
return($::SUCCESS, undef);
}
sub CalculateHandling
{
$::s_Ship_nHandlingCharges = $nHandlingCharge + int (GetTaxExclusiveShipping() * $nHandlingProportion / $ActinicOrder::PERCENTOFFSET);
$::s_Ship_nHandlingCharges += $::dHandlingSupplements;
$::s_Ship_sOpaqueHandleData = sprintf("Handling;%d;", $::s_Ship_nHandlingCharges);
return ($::SUCCESS, undef);
}
sub GetTaxExclusiveShipping
{
my ($phashShipping, $phashSelected);
$phashSelected = undef;
foreach $phashShipping (@::s_arrSortedShippingHashes)
{
if($$phashShipping{ShippingClass} eq $::s_hashShipData{ShippingClass})
{
$phashSelected = $phashShipping;
last;
}
}
if(!defined $phashSelected &&
@::s_arrSortedShippingHashes > 0)
{
$phashSelected = $::s_arrSortedShippingHashes[0];
}
if (defined $phashSelected)
{
%::s_hashShipData = %$phashSelected;
$::s_Ship_nShipCharges = $$phashSelected{Cost};
}
return ($::s_Ship_nShipCharges);
}
sub SimpleValidateFinalInput
{
my (@Response);
if(!defined $::g_InputHash{SHIPPING})
{
return($::SUCCESS, undef);
}
if ($::g_InputHash{SHIPPING})
{
$::g_InputHash{SHIPPING} =~ s/^\s*(.*?)\s*$/$1/gs;
}
if (defined $::g_InputHash{SHIPPING})
{
my $sText = (0 == length $::g_InputHash{SHIPPING}) ? ' ' : $::g_InputHash{SHIPPING};
$::s_Ship_sOpaqueShipData = sprintf("Simple;Error-%s;", $sText);
}
if (!defined $::g_InputHash{'SHIPPING'} ||# if the shipping is undefined, error out
length $::g_InputHash{'SHIPPING'} == 0)
{
return($::FAILURE, $$pMessageList[8]);
}
@Response = ActinicOrder::ReadPrice($::g_InputHash{SHIPPING}, \%::s_Ship_PriceFormatBlob);
if ($Response[0] != $::SUCCESS ||
$Response[2] != int $Response[2])
{
@Response = ActinicOrder::FormatSinglePrice(10000, $::FALSE, \%::s_Ship_PriceFormatBlob);
if ($Response[0] != $::SUCCESS)
{
return($Response[0], $Response[1]);
}
return($::FAILURE, sprintf($$pMessageList[0], $Response[2]));
}
my ($nMaxShipping) = 99999999;
if ($Response[2] >= $nMaxShipping)
{
@Response = ActinicOrder::FormatPrice($nMaxShipping, $::TRUE, \%::s_Ship_PriceFormatBlob);
if ($Response[0] != $::SUCCESS)
{
return($Response[0], $Response[1]);
}
return($::FAILURE, sprintf($$pMessageList[1], $Response[2]));
}
my ($nMinShipping) = 0;
if ($Response[2] < $nMinShipping)
{
@Response = ActinicOrder::FormatPrice($nMinShipping, $::TRUE, \%::s_Ship_PriceFormatBlob);
if ($Response[0] != $::SUCCESS)
{
return($Response[0], $Response[1]);
}
return($::FAILURE, sprintf($$pMessageList[2], $Response[2]));
}
if (defined $::g_InputHash{SHIPPING})
{
$::s_Ship_sOpaqueShipData = sprintf("Simple;%s;", $Response[2]);
if ($bPricesIncludesTax)
{
$::s_Ship_sOpaqueShipData .= sprintf('TaxApplies;%d;', $::s_sShip_bLocationTaxable);
}
OpaqueToHash();
}
return($::SUCCESS, undef);
}
sub SimpleRestoreFinalUI
{
my (@Response);
$::s_Ship_nShipOptions = -1;
my $ePosOrder = $::s_Ship_PriceFormatBlob{"ICURRENCY"};
if ($ePosOrder == 0)
{
$::s_Ship_ShippingVariables{"NETQUOTEVAR:CURRENCYSYMBOL1"} = $::s_Ship_PriceFormatBlob{"SCURRENCY"};
$::s_Ship_ShippingVariables{"NETQUOTEVAR:CURRENCYSYMBOL2"} = '';
}
elsif ($ePosOrder == 1)
{
$::s_Ship_ShippingVariables{"NETQUOTEVAR:CURRENCYSYMBOL1"} = '';
$::s_Ship_ShippingVariables{"NETQUOTEVAR:CURRENCYSYMBOL2"} = $::s_Ship_PriceFormatBlob{"SCURRENCY"};
}
elsif ($ePosOrder == 2)
{
$::s_Ship_ShippingVariables{"NETQUOTEVAR:CURRENCYSYMBOL1"} = $::s_Ship_PriceFormatBlob{"SCURRENCY"} . ' ';
$::s_Ship_ShippingVariables{"NETQUOTEVAR:CURRENCYSYMBOL2"} = '';
}
elsif ($ePosOrder == 3)
{
$::s_Ship_ShippingVariables{"NETQUOTEVAR:CURRENCYSYMBOL1"} = '';
$::s_Ship_ShippingVariables{"NETQUOTEVAR:CURRENCYSYMBOL2"} = $::s_Ship_PriceFormatBlob{"SCURRENCY"} . ' ';
}
if (!defined $::s_hashShipData{'Simple'})
{
@Response = ActinicOrder::FormatSinglePrice($SimpleCost, $::FALSE, \%::s_Ship_PriceFormatBlob);
if ($Response[0] != $::SUCCESS)
{
return($Response[0], $Response[1]);
}
$::s_Ship_ShippingVariables{"NETQUOTEVAR:SHIPPINGVALUE"} = $Response[2];
$::s_hashShipData{'Simple'} = $SimpleCost;
$::s_Ship_sOpaqueShipData = sprintf("Simple;%s;", $SimpleCost);
if ($bPricesIncludesTax)
{
$::s_Ship_sOpaqueShipData .= sprintf('TaxApplies;%d;', $::s_sShip_bLocationTaxable);
}
}
elsif($::s_hashShipData{'Simple'} =~ /Error-/)
{
$::s_hashShipData{'Simple'} =~ s/^Error-\s*(.*?)\s*$/$1/g;
$::s_Ship_ShippingVariables{"NETQUOTEVAR:SHIPPINGVALUE"} = $::s_hashShipData{'Simple'};
}
else
{
$::s_hashShipData{'Simple'} =~ s/^\s*(.*?)\s*$/$1/g;
@Response = ActinicOrder::FormatSinglePrice($::s_hashShipData{'Simple'}, $::FALSE, \%::s_Ship_PriceFormatBlob);
if ($Response[0] != $::SUCCESS)
{
return($Response[0], $Response[1]);
}
$::s_Ship_ShippingVariables{"NETQUOTEVAR:SHIPPINGVALUE"} = $Response[2];
}
if ($bPricesIncludesTax)
{
$::s_Ship_bTaxAppliesToShipping = ActinicOrder::IsTaxApplicableForLocation('TAX_1');
}
else
{
$::s_Ship_bTaxAppliesToShipping = $::TRUE;
}
return($::SUCCESS, undef);
}
sub SimpleCalculateShipping
{
if (!defined $::s_hashShipData{'Simple'} ||
$::s_hashShipData{'Simple'} =~ /Error-/)
{
$::s_Ship_nShipCharges = 0;
}
else
{
$::s_Ship_nShipCharges = $::s_hashShipData{'Simple'};
}
return($::SUCCESS, undef);
}
sub CalculateQuantity
{
return($::s_Ship_nTotalQuantity);
}
sub CalculateAdjustedQuantity
{
if (defined $::s_Ship_nAdjustedTotalQuantity)
{
return ($::s_Ship_nAdjustedTotalQuantity);
}
$::s_Ship_nAdjustedTotalQuantity = 0;
$::s_Ship_nNonExcludedCount = 0;
my $i;
for $i (0 .. $#::s_Ship_sShipProducts)
{
if($::s_Ship_sShipProducts[$i] =~ /_/)
{
next;
}
if ($::s_Ship_nExcludeFromShipping[$i] == 1 &&
$::s_Ship_sGFSCarrierAndService eq "")
{
next;
}
if ($::s_Ship_bProduct == 0 &&
$::s_Ship_bUseAssociatedShip[$i] == 0)
{
next;
}
$::s_Ship_nNonExcludedCount++;
$::s_Ship_nAdjustedTotalQuantity +=
($::s_Ship_nShipShipQuantities[$i] *
$::s_Ship_nShipQuantities[$i]);
}
return($::s_Ship_nAdjustedTotalQuantity);
}
sub CalculatePrice
{
my $j;
if (defined $::s_Ship_nTotalPrice)
{
return ($::s_Ship_nTotalPrice);
}
if (defined $::s_Ship_nSubTotal)
{
return ($::s_Ship_nSubTotal);
}
$::s_Ship_nTotalPrice = 0;
for $j (0 .. $#::s_Ship_sShipProducts)
{
$::s_Ship_nTotalPrice += ($::s_Ship_nShipPrices[$j] * $::s_Ship_nShipQuantities[$j]);
}
return($::s_Ship_nTotalPrice);
}
sub GetBands
{
if ($::s_sDeliveryRegionCode eq "" ||
$::s_sDeliveryRegionCode eq $UNDEFINED)
{
if ($#{$ParentZoneTable{$::s_sDeliveryCountryCode}} != -1)
{
return (@{$ParentZoneTable{$::s_sDeliveryCountryCode}}); # return this list (has invalid entries stripped)
}
}
if(defined $ZoneTable{$::s_sDeliveryCountryCode})
{
if(defined $ZoneTable{$::s_sDeliveryCountryCode}{$::s_sDeliveryRegionCode})
{
return(@{ $ZoneTable{$::s_sDeliveryCountryCode}{$::s_sDeliveryRegionCode} });
}
my $sParentState = ActinicLocations::GetDeliveryParentRegionCode();
if($sParentState ne '' &&
$sParentState ne $::s_sDeliveryRegionCode &&
defined $ZoneTable{$::s_sDeliveryCountryCode}{$sParentState})
{
return(@{ $ZoneTable{$::s_sDeliveryCountryCode}{$sParentState} });
}
if(defined $ZoneTable{$::s_sDeliveryCountryCode}{$UNDEFINED})
{
return(@{ $ZoneTable{$::s_sDeliveryCountryCode}{$UNDEFINED} });
}
}
my @listEmpty = ();
return(@listEmpty);
}
sub GetSSPProviderList
{
my ($sCountryCode) = @_;
my @arrReturn;
if(defined $$::g_pSSPSetupBlob{SupportedRegions} &&
defined $$::g_pSSPSetupBlob{SupportedRegions}{$sCountryCode})
{
my $nProviderID;
foreach $nProviderID ($$::g_pSSPSetupBlob{SupportedRegions}{$sCountryCode})
{
push(@arrReturn, $nProviderID);
}
}
return (\@arrReturn);
}
sub GetUS5DigitZipCode
{
my ($sZipCode) = @_;
if($sZipCode !~ /^\d{5}$/ &&
$sZipCode !~ /^\d{5}-\d{4}$/ &&
$sZipCode !~ /^\d{9}$/)
{
return($::FAILURE, ACTINIC::GetPhrase(-1, 2150));
}
$sZipCode = substr($sZipCode, 0, 5);
return($::SUCCESS, '', $sZipCode);
}
sub CalculatePackageShipping
{
my ($nZoneID, $nClassID, $objBasis, $nCalculationBasis) = @_;
if ($nCalculationBasis == $c_nPerItemShipping)
{
return (CalculatePerItemShipping($nZoneID, $nClassID, $objBasis));
}
my $nCost = 0;
my $bWeightOK = $::TRUE;
my $dMaxWeight = 0.0;
my $nHighestCost = 0;
my $sCostKey = 'cost';
my $parrBandEntries = $ShippingTable{$nClassID}{$nZoneID};
my $nEntryCount = @$parrBandEntries;
my $phashBandEntry;
if($nEntryCount > 1)
{
$phashBandEntry = $$parrBandEntries[$nEntryCount - 1];
$dMaxWeight = $$phashBandEntry{wt};
if (defined $phashBandEntry->{'costIncTax'})
{
$sCostKey = 'costIncTax';
}
$nHighestCost = $$phashBandEntry{$sCostKey};
}
if($objBasis > $dMaxWeight)
{
my $phashExcessAction = $$parrBandEntries[0];
if($$phashExcessAction{ExcessAction} eq 'Highest')
{
$nCost = $nHighestCost;
}
elsif($$phashExcessAction{ExcessAction} eq 'AddFurther')
{
my $dExtraWeight = $objBasis - $dMaxWeight;
my $sCostSuffix = defined $phashExcessAction->{'IncrementalChargeIncTax'} ?
'IncTax' : '';
my ($dWeightIncrement, $nChargeIncrement) =
($$phashExcessAction{'IncrementalWeight'},
$$phashExcessAction{'IncrementalCharge' . $sCostSuffix});
my $nExtraUnits = int ($dExtraWeight / $dWeightIncrement + 0.999);
$nCost = $nHighestCost +
($nExtraUnits * $nChargeIncrement);
}
elsif($$phashExcessAction{ExcessAction} eq 'Error')
{
$bWeightOK = $::FALSE;
}
}
else
{
my $i;
for($i = 1; $i < $nEntryCount; $i++)
{
$phashBandEntry = $$parrBandEntries[$i];
if($$phashBandEntry{wt} >= $objBasis)
{
$nCost = $$phashBandEntry{$sCostKey};
last;
}
}
}
return($bWeightOK, $nCost);
}
sub GetPerItemQuantities
{
my ($phashCategoryQuantities) = @_;
my $i;
for $i (0 .. $#::s_Ship_sShipProducts)
{
if($::s_Ship_sShipProducts[$i] =~ /_/)
{
next;
}
if ($::s_Ship_nExcludeFromShipping[$i] == 1 &&
$::s_Ship_sGFSCarrierAndService eq "")
{
next;
}
if ($::s_Ship_bUseAssociatedShip[$i] == 0)
{
next;
}
my $sCategory = $::s_Ship_sShipCategories[$i];
if (!defined $phashDefinedCategories->{$sCategory})
{
$sCategory = $sDefaultCategory;
}
my $nTotalQuantity =
$::s_Ship_nShipQuantities[$i] * $::s_Ship_nShipShipQuantities[$i];
if (defined $phashCategoryQuantities->{$sCategory})
{
$phashCategoryQuantities->{$sCategory} += $nTotalQuantity;
}
else
{
$phashCategoryQuantities->{$sCategory} = $nTotalQuantity;
}
}
}
sub CalculateSupplements
{
my %hashShippingSupplementApplied;
my %hashHandlingSupplementApplied;
my $i;
for $i (0 .. $#::s_Ship_sShipProducts)
{
if ($::s_Ship_sShipProducts[$i] =~ /_/)
{
next;
}
if ($::s_Ship_bProduct[$i] ||
($::s_Ship_bUseAssociatedShip[$i] == 1))
{
my $nQuantity = $::s_Ship_nShipQuantities[$i];
if ($::s_Ship_dShipSupplementOnce[$i] == 1)
{
if (defined $hashShippingSupplementApplied{$::s_Ship_sShipProducts[$i]})
{
$nQuantity = 0;
}
else
{
$hashShippingSupplementApplied{$::s_Ship_sShipProducts[$i]} = 1;
$nQuantity = 1;
}
}
$::dShippingSupplements += $nQuantity * $::s_Ship_dShipSupplements[$i];
$nQuantity = $::s_Ship_nShipQuantities[$i];
if ($::s_Ship_dHandSupplementOnce[$i] == 1)
{
if (defined $hashHandlingSupplementApplied{$::s_Ship_sShipProducts[$i]})
{
$nQuantity = 0;
}
else
{
$hashHandlingSupplementApplied{$::s_Ship_sShipProducts[$i]} = 1;
$nQuantity = 1;
}
}
$::dHandlingSupplements += $nQuantity * $::s_Ship_dHandSupplements[$i];
}
}
}
sub CalculatePerItemShipping
{
my ($nZoneID, $nClassID, $phashCategoryQuantities) = @_;
my $nMaxFixedCost = 0;
my $dPerItemCharges = 0;
my $parrBandEntries = $ShippingTable{$nClassID}{$nZoneID};
my $phashZoneClassPerItemCharges = $parrBandEntries->[1];
my $sKeySuffix = '';
if ($bPricesIncludesTax &&
$parrBandEntries->[0]->{'TaxAppliesToShipping'} &&
!$parrBandEntries->[0]->{'ShippingCostsIncludeTax'})
{
$sKeySuffix = 'IncTax';
}
my $sCategory;
foreach $sCategory (keys %$phashCategoryQuantities)
{
my $phashCategory = $phashZoneClassPerItemCharges->{$sCategory};
if ($phashCategory->{'Fixed' . $sKeySuffix} > $nMaxFixedCost)
{
$nMaxFixedCost = $phashCategory->{'Fixed' . $sKeySuffix};
}
my $nQuantity = $phashCategoryQuantities->{$sCategory};
$dPerItemCharges += $phashCategory->{'PerItem' . $sKeySuffix} * $nQuantity;
}
return ($::TRUE, $nMaxFixedCost + $dPerItemCharges);
}
sub CalculateMultiPackageShipping
{
my $dWeightRemainder = 0.0;
my $bNonSeparateShipFound = $::FALSE;
my ($i);
my $dWeight;
my @arrShippingHashes;
my $parrZonesClasses = GetZoneClassCombinations();
my $pProviderList = GetSSPProviderList($::s_sDeliveryCountryCode);
if(@$parrZonesClasses == 0 &&
@$pProviderList == 0)
{
return(SetDefaultCharge());
}
CalculateAdjustedQuantity();
CalculateSupplements();
my %hashCalculationBases = {};
GetZoneClassesByBasis(\%hashCalculationBases, $parrZonesClasses, \@arrShippingHashes);
my $nCalculationBasis;
foreach $nCalculationBasis (keys %hashCalculationBases)
{
my $parrBasisZoneClasses =
$hashCalculationBases{$nCalculationBasis};
my $parrZoneClass;
foreach $parrZoneClass (@$parrBasisZoneClasses)
{
CalculateZoneClassShipping($nCalculationBasis,
$parrZoneClass, \@arrShippingHashes);
}
}
if (@$pProviderList > 0)
{
my ($phashWeightToQuantity, $parrSortedWeightKeys, $sWeightList,
$parrShipSeparatePackages, $parrMixedPackages, $sOptimalWeight)
= DivideIntoPackages($c_nWeight, undef);
my $dSumOfWeights = 0.0;
foreach $dWeight (@$parrSortedWeightKeys)
{
$dSumOfWeights += $$phashWeightToQuantity{$dWeight} * $dWeight;
}
my $nProviderID;
foreach $nProviderID (@$pProviderList)
{
my $bWeightThresholdExceeded = IsWeightThresholdExceeded($nProviderID, $dSumOfWeights);
if($::g_pSSPSetupBlob &&
$$::g_pSSPSetupBlob{$nProviderID}{'RSSEnabled'} &&
$bWeightThresholdExceeded == $::FALSE)
{
my ($nReturnCode, $sSSPError, $parrShippingHashes, $nRateType) = GetUPSRates();
$hSSPUsed{$nRateType} = $::TRUE;
if($nReturnCode != $::SUCCESS)
{
return($nReturnCode, $sSSPError);
}
else
{
push @arrShippingHashes, @$parrShippingHashes;
}
}
}
}
if(@$parrZonesClasses == 0 &&
@arrShippingHashes == 0)
{
return(SetDefaultCharge());
}
if (@arrShippingHashes == 0 &&
scalar @::s_Ship_sShipProducts != 0)
{
return ($::FAILURE, $$pMessageList[7]);
}
@arrShippingHashes = sort{$$a{Cost} <=> $$b{Cost}} @arrShippingHashes;
my @arrLastClasses;
my $phashClass;
foreach $phashClass (@arrShippingHashes)
{
my $bLastClass = 0;
my $nClassID = $phashClass->{'ShippingClass'};
if (defined $ClassTable{$nClassID})
{
$bLastClass = $ClassTable{$nClassID}->[1];
}
if ($bLastClass)
{
push @arrLastClasses, $phashClass;
}
else
{
push @::s_arrSortedShippingHashes, $phashClass;
}
}
push @::s_arrSortedShippingHashes, @arrLastClasses;
return($::SUCCESS, '');
}
sub CalculateZoneClassShipping
{
my ($nCalculationBasis, $parrZoneClass, $parrShippingHashes) = @_;
my ($phashWeightToQuantity, $parrSortedWeightKeys, $sWeightList,
$parrShipSeparatePackages, $parrMixedPackages, $sOptimalWeight)
= DivideIntoPackages($nCalculationBasis, $parrZoneClass);
my $nTotalCost = 0;
my ($nZoneID, $nClassID) = @$parrZoneClass;
my ($bBasisOK, $nPackageCost);
$bBasisOK = $::TRUE;
my $dBasisTotal = 0;
my $dBasis;
foreach $dBasis (@$parrSortedWeightKeys)
{
($bBasisOK, $nPackageCost) =
CalculatePackageShipping($nZoneID, $nClassID,
$dBasis, $nCalculationBasis);
if ($bBasisOK)
{
$nTotalCost +=
$$phashWeightToQuantity{$dBasis} * $nPackageCost;
my $sKey = sprintf('%0.03f', $dBasis);
$::s_hashClassToWeightCost{$nClassID}{$sKey} = $nPackageCost;
$dBasisTotal += $dBasis;
}
else
{
last;
}
}
if ($bBasisOK)
{
if ($::s_Ship_nNonExcludedCount == 0 &&
$dBasisTotal == 0)
{
$nTotalCost = 0.0;
}
my $nCost = ActinicOrder::RoundScientific($nTotalCost + $::dShippingSupplements);
my $phashBandDefinition = GetBandDefinition(@$parrZoneClass);
if (defined $phashBandDefinition->{'FreeOver'} &&
CalculatePrice() > $phashBandDefinition->{'FreeOver'})
{
$nCost = 0;
}
my $bInternational = $::FALSE;
if (defined $phashBandDefinition->{'InternationalZone'})
{
$bInternational = $phashBandDefinition->{'InternationalZone'};
}
push @$parrShippingHashes, {
'ShippingLabel' => $ClassTable{$nClassID}[0],
'ShippingClass' => $nClassID,
'ShippingZone' => $nZoneID,
'Cost' => $nCost,
'BasisTotal' => $dBasis,
'ShipSeparatePackages' => $parrShipSeparatePackages,
'MixedPackages' => $parrMixedPackages,
'OptimalWeight' => $sOptimalWeight,
'TaxAppliesToShipping' => $phashBandDefinition->{'TaxAppliesToShipping'},
'ShippingCostsIncludeTax' => $phashBandDefinition->{'ShippingCostsIncludeTax'},
'GFSCarrierAndService' => $ClassTable{$nClassID}[2],
'InternationalShipping' => $bInternational
};
}
}
sub GetZoneClassesByBasis
{
my ($phashCalculationBases, $parrZonesClasses, $parrShippingHashes) = @_;
my $parrZoneClass;
foreach $parrZoneClass (@$parrZonesClasses)
{
my ($nZoneID, $nClassID) = @$parrZoneClass;
my $phashBandDefinition = GetBandDefinition(@$parrZoneClass);
if (defined $phashBandDefinition->{'FreeClass'})
{
my $bInternational = $::FALSE;
if (defined $phashBandDefinition->{'InternationalZone'})
{
$bInternational = $phashBandDefinition->{'InternationalZone'};
}
push @$parrShippingHashes, {
'ShippingLabel' => $ClassTable{$nClassID}[0],
'ShippingClass' => $nClassID,
'ShippingZone' => $nZoneID,
'Cost' => 0,
'BasisTotal' => 0,
'GFSCarrierAndService' => $ClassTable{$nClassID}[2],
'InternationalShipping' => $bInternational
};
}
else
{
my $nCalculationBasis = $phashBandDefinition->{'CalculationBasis'};
if (!defined $phashCalculationBases->{$nCalculationBasis})
{
$phashCalculationBases->{$nCalculationBasis} = [];
}
my $parrBasisZoneClasses = $phashCalculationBases->{$nCalculationBasis};
push @$parrBasisZoneClasses, $parrZoneClass;
}
}
return (scalar(keys %$phashCalculationBases) > 0);
}
sub GetBandDefinition
{
my ($nZoneID, $nClassID) = @_;
my $parrBandEntries = $ShippingTable{$nClassID}{$nZoneID};
my $phashBandDefinition = $$parrBandEntries[0];
return ($phashBandDefinition);
}
sub IsWeightThresholdExceeded
{
my $nProviderID = shift;
my $dSumOfWeights = shift;
my $bWeightThresholdExceeded = $::FALSE;
if($::g_pSSPSetupBlob &&
$$::g_pSSPSetupBlob{$nProviderID}{'WEIGHTTHRESHOLD'})
{
my $dWeightThreshold = $$::g_pSSPSetupBlob{$nProviderID}{'WEIGHTTHRESHOLD'};
if (($dWeightThreshold ne '') &&
($dWeightThreshold =~ /^[+]?[\d]*(\.[\d]+)?$/))
{
if ($dWeightThreshold < $dSumOfWeights)
{
$bWeightThresholdExceeded = $::TRUE;
}
}
}
return $bWeightThresholdExceeded;
}
sub DivideIntoPackages
{
my ($nCalculationBasis, $parrZoneClass, $bUseIntegralWeights) = @_;
my $dWeightRemainder = 0.0;
my $nNonSeparateShipCount = 0;
my $dExcludeFromShippingWeight = 0.0;
my (%hashWeightToQuantity, @arrSortedWeightKeys);
my ($i);
my (@arrShipSeparatePackages, @arrMixedPackages, $parrPackage);
if (($::s_Ship_sGFSCarrierAndService eq "" ||
!defined $::s_Ship_sGFSCarrierAndService) &&
defined $parrZoneClass)
{
my ($nZoneID, $nClassID) = @$parrZoneClass;
$::s_Ship_sGFSCarrierAndService = $ClassTable{$nClassID}[2];
}
my $nBasisTotal = -1;
if ($nCalculationBasis == $c_nQuantity)
{
$nBasisTotal = CalculateAdjustedQuantity();
}
elsif ($nCalculationBasis == $c_nPrice)
{
$nBasisTotal = CalculatePrice();
}
elsif ($nCalculationBasis == $c_nPerItemShipping)
{
$nBasisTotal = {};
GetPerItemQuantities($nBasisTotal);
}
if (ref($nBasisTotal) ne '' || $nBasisTotal != -1)
{
$hashWeightToQuantity{$nBasisTotal} = 1;
@arrSortedWeightKeys = ($nBasisTotal);
return(\%hashWeightToQuantity, \@arrSortedWeightKeys, $nBasisTotal);
}
my $dWeightDivisor = 1;
my $dAltWeightDivisor = 1;
my $sOptimalWeight = '';
if (defined $parrZoneClass)
{
my ($nZoneID, $nClassID) = @$parrZoneClass;
my $parrBandEntries = $ShippingTable{$nClassID}{$nZoneID};
my $phashBandDefinition = $$parrBandEntries[0];
$dWeightDivisor = $phashBandDefinition->{'WeightFactor'};
$dAltWeightDivisor = $phashBandDefinition->{'AltWeightFactor'};
$sOptimalWeight =
$phashWeightConfiguration->{$nCalculationBasis}->{'OptimalWeight'};
}
else
{
$sOptimalWeight =
$phashWeightConfiguration->{$c_nWeight}->{'OptimalWeight'};
}
my $dUnitWeight;
for $i (0 .. $#::s_Ship_sShipProducts)
{
my $sProdRef = $::s_Ship_sShipProducts[$i];
if($::s_Ship_sShipProducts[$i] =~ /_/)
{
next;
}
if ($::s_Ship_nExcludeFromShipping[$i] == 1 &&
$::s_Ship_sGFSCarrierAndService eq "")
{
next;
}
if ($nCalculationBasis == $c_nWeight)
{
$dUnitWeight =
GetWeight($i, $phashWeightConfiguration, $dWeightDivisor);
}
elsif ($nCalculationBasis == $c_nAlternateWeight)
{
$dUnitWeight =
GetAltWeight($i, $phashWeightConfiguration,
$dWeightDivisor, $dAltWeightDivisor);
}
elsif ($nCalculationBasis == $c_nMaximumWeight)
{
$dUnitWeight =
GetMaxWeight($i, $phashWeightConfiguration,
$dWeightDivisor, $dAltWeightDivisor);
}
if($::s_Ship_nShipSeparately[$i] == 1 ||
($sOptimalWeight > 0 &&
$dUnitWeight >= $sOptimalWeight))
{
if($bUseIntegralWeights)
{
$dUnitWeight = int($dUnitWeight + 0.9999);
}
if ($::s_Ship_nExcludeFromShipping[$i] == 0)
{
$hashWeightToQuantity{$dUnitWeight} += $::s_Ship_nShipQuantities[$i];
}
my @arrTemp = ($::s_Ship_sShipProducts[$i], $::s_Ship_nShipQuantities[$i], $dUnitWeight);
push @arrShipSeparatePackages, \@arrTemp;
}
else
{
$nNonSeparateShipCount += $::s_Ship_nShipQuantities[$i];
$dWeightRemainder +=
$dUnitWeight * $::s_Ship_nShipQuantities[$i];
if ($::s_Ship_nExcludeFromShipping[$i] == 1)
{
$dExcludeFromShippingWeight += $dUnitWeight * $::s_Ship_nShipQuantities[$i];
}
my @arrTemp = ($::s_Ship_sShipProducts[$i], $::s_Ship_nShipQuantities[$i], $dUnitWeight);
push @arrMixedPackages, \@arrTemp;
}
}
my $dBasis = 0.0;
if($nNonSeparateShipCount > 0)
{
my $nQuantity = 1;
if($sOptimalWeight ne '' &&
$dWeightRemainder > $sOptimalWeight)
{
my $nCalculatedPackages = int(($dWeightRemainder / $sOptimalWeight) + 0.9999);
if($nCalculatedPackages == $nNonSeparateShipCount)
{
foreach $parrPackage (@arrMixedPackages)
{
$dUnitWeight = $$parrPackage[2];
if($bUseIntegralWeights)
{
$dUnitWeight = int($dUnitWeight + 0.9999);
}
$dBasis = $dUnitWeight;
if ($dExcludeFromShippingWeight > 0)
{
$dBasis -= $dExcludeFromShippingWeight;
}
$hashWeightToQuantity{$dBasis} += $$parrPackage[1];
push @arrShipSeparatePackages, $parrPackage;
}
@arrMixedPackages = ();
}
else
{
$nQuantity =
($nCalculatedPackages < $nNonSeparateShipCount) ?
$nCalculatedPackages :
$nNonSeparateShipCount;
$dWeightRemainder = $dWeightRemainder / $nQuantity;
$dExcludeFromShippingWeight = $dExcludeFromShippingWeight / $nQuantity;
if($bUseIntegralWeights)
{
$dWeightRemainder = int($dWeightRemainder + 0.9999);
if ($dExcludeFromShippingWeight > 0)
{
$dExcludeFromShippingWeight = int($dExcludeFromShippingWeight + 0.9999);
}
}
$dBasis = $dWeightRemainder;
if ($dExcludeFromShippingWeight > 0)
{
$dBasis -= $dExcludeFromShippingWeight;
}
if ($dBasis != 0.0 ||
$dBasis == $dWeightRemainder)
{
$hashWeightToQuantity{$dBasis} += $nQuantity;
}
my @arrTemp = ('', $nQuantity, $dWeightRemainder);
push @arrMixedPackages, \@arrTemp;
}
}
else
{
if($bUseIntegralWeights)
{
$dWeightRemainder = int($dWeightRemainder + 0.9999);
if ($dExcludeFromShippingWeight > 0)
{
$dExcludeFromShippingWeight = int($dExcludeFromShippingWeight + 0.9999);
}
}
$dBasis = $dWeightRemainder;
if ($dExcludeFromShippingWeight > 0)
{
$dBasis -= $dExcludeFromShippingWeight;
}
if ($dBasis != 0.0 ||
$dBasis == $dWeightRemainder)
{
$hashWeightToQuantity{$dBasis} += $nQuantity;
}
my @arrTemp = ('', $nQuantity, $dWeightRemainder);
push @arrMixedPackages, \@arrTemp;
}
}
@arrSortedWeightKeys = sort {$b <=> $a} keys %hashWeightToQuantity;
my ($dWeight, $sWeightList);
foreach $dWeight (@arrSortedWeightKeys)
{
$sWeightList .= sprintf("%d@%.03f,", $hashWeightToQuantity{$dWeight}, $dWeight);
}
$sWeightList =~ s/,$//;
return(\%hashWeightToQuantity, \@arrSortedWeightKeys, $sWeightList,
\@arrShipSeparatePackages, \@arrMixedPackages, $sOptimalWeight);
}
sub GetWeight
{
my ($nIndex, $phashWeightConfiguration, $dWeightDivisor) = @_;
my $dUnitWeight = $::s_Ship_OpaqueDataTables{$::s_Ship_sShipProducts[$nIndex]};
if ($dUnitWeight eq "")
{
$dUnitWeight = $phashWeightConfiguration->{$c_nWeight}->{'DefaultWeight'};
}
if ($dWeightDivisor != 0)
{
$dUnitWeight /= $dWeightDivisor;
}
return ($dUnitWeight);
}
sub GetAltWeight
{
my ($nIndex, $phashWeightConfiguration, $dWeightDivisor, $dAltWeightDivisor) = @_;
my $dUnitWeight = $::s_Ship_dShipAltWeights[$nIndex];
if ($::s_Ship_dShipAltWeights[$nIndex] eq "")
{
my $phashWeightDetails = $phashWeightConfiguration->{$c_nAlternateWeight};
if ($phashWeightDetails->{'UseWeightIfUndefined'})
{
return (GetWeight($nIndex, $phashWeightConfiguration, $dWeightDivisor));
}
$dUnitWeight =
$phashWeightConfiguration->{$c_nAlternateWeight}->{'DefaultWeight'};
}
if ($dAltWeightDivisor != 0)
{
$dUnitWeight /= $dAltWeightDivisor;
}
return ($dUnitWeight);
}
sub GetMaxWeight
{
my ($nIndex, $phashWeightConfiguration, $dWeightDivisor, $dAltWeightDivisor) = @_;
my $dUnitWeight = GetWeight($nIndex, $phashWeightConfiguration, $dWeightDivisor);
my $dAltWeight = GetAltWeight($nIndex, $phashWeightConfiguration, $dWeightDivisor, $dAltWeightDivisor);
if ($dAltWeight > $dUnitWeight)
{
$dUnitWeight = $dAltWeight;
}
return ($dUnitWeight);
}
sub GetZoneClassCombinations
{
my @arrZones = GetBands();
my (%hashZones, $nZoneID, $nClassID, @arrZonesClasses);
foreach $nZoneID (@arrZones)
{
$hashZones{$nZoneID} = 1;
}
foreach $nClassID (keys %ShippingTable)
{
my $phashClass = $ShippingTable{$nClassID};
foreach $nZoneID (keys %$phashClass)
{
if(defined $hashZones{$nZoneID})
{
my @arrClassZone = ($nZoneID, $nClassID);
push @arrZonesClasses, \@arrClassZone;
}
}
}
return(\@arrZonesClasses);
}
sub AddShippingHash
{
my ($phashShipping) = @_;
push @::s_arrSortedShippingHashes, $phashShipping;
}
sub SetDefaultCharge
{
if ($UnknownRegion eq 'Default')
{
AddShippingHash({
'ShippingLabel' => $$pMessageList[6],
'ShippingClass' => 'Default',
'ShippingZone' => -1,
'Cost' => $UnknownRegionCost,
'TaxAppliesToShipping' => $::s_sShip_bLocationTaxable,
});
return($::SUCCESS, '');
}
return($::FAILURE, $$pMessageList[4]);
}
sub SetFreeShipping
{
AddShippingHash(GetFreeShippingHash());
return($::SUCCESS, '');
}
sub GetFreeShippingHash
{
return({
'ShippingLabel' => $$pMessageList[5],
'ShippingClass' => '-1',
'ShippingZone' => -1,
'Cost' => 0,
'BasisTotal' => 0
});
}
sub SetUndefinedShipping
{
AddShippingHash({
'ShippingLabel' => '',
'ShippingClass' => -1,
'ShippingZone' => -1,
'Cost' => 0,
});
return($::SUCCESS, '');
}
sub OpaqueToHash
{
if(defined $::g_InputHash{ShippingClass})
{
$::s_hashShipData{ShippingClass} = $::g_InputHash{ShippingClass};
}
else
{
%::s_hashShipData =
split (';', $::s_Ship_sOpaqueShipData);
}
}
sub SaveSelectionToOpaqueData
{
if($ShippingBasis eq 'Simple')
{
return;
}
my ($phashShipping, $phashSelected);
$phashSelected = undef;
foreach $phashShipping (@::s_arrSortedShippingHashes)
{
HashToOpaque($phashShipping);
$$phashShipping{'OpaqueData'} = $::s_Ship_sOpaqueShipData;
if($$phashShipping{ShippingClass} eq $::s_hashShipData{ShippingClass})
{
$phashSelected = $phashShipping;
}
}
if(!defined $phashSelected &&
@::s_arrSortedShippingHashes > 0)
{
$phashSelected = $::s_arrSortedShippingHashes[0];
}
if (defined $phashSelected)
{
%::s_hashShipData = %$phashSelected;
}
HashToOpaque($phashSelected);
if (!$phashSelected ||
$$phashSelected{ShippingClass} !~ /^\d+_/)
{
$::s_Ship_sSSPOpaqueShipData = '';
}
}
sub HashToOpaque
{
my $phashSelected = shift;
if (defined $phashSelected)
{
$::s_Ship_sOpaqueShipData =
sprintf("ShippingClass;%s;ShippingZone;%d;BasisTotal;%s;Cost;%d;",
$$phashSelected{ShippingClass},
$$phashSelected{ShippingZone},
$$phashSelected{BasisTotal},
$$phashSelected{Cost});
if ($bPricesIncludesTax)
{
$::s_Ship_sOpaqueShipData .=
sprintf("TaxApplies;%s;TaxIncluded;%d;TaxMultiplier;%0.06f;",
$$phashSelected{'TaxAppliesToShipping'},
$$phashSelected{'ShippingCostsIncludeTax'},
$dTaxInclusiveMultiplier);
}
if(defined $$phashSelected{OnlineError} &&
$$phashSelected{OnlineError} ne '')
{
$::s_Ship_sOpaqueShipData .=
sprintf('OnlineError;%s;', $$phashSelected{OnlineError});
}
my $sOptimalWeight = $phashSelected->{'OptimalWeight'};
if($sOptimalWeight ne '' &&
$sOptimalWeight > 0)
{
$::s_Ship_sOpaqueShipData .=
sprintf('OptimalWeight;%s;', $sOptimalWeight);
}
$::s_Ship_nShipCharges = $$phashSelected{Cost};
if ($bPricesIncludesTax)
{
$::s_Ship_bTaxAppliesToShipping = $$phashSelected{TaxAppliesToShipping};
}
else
{
$::s_Ship_bTaxAppliesToShipping = $::TRUE;
}
my $sClassID = $$phashSelected{ShippingClass};
my $parrShipSeparatePackages = $phashSelected->{'ShipSeparatePackages'};
my $parrMixedPackages = $phashSelected->{'MixedPackages'};
if(defined $parrShipSeparatePackages &&
defined $parrMixedPackages)
{
my $phashWeightToCost =
(defined $::s_hashClassToWeightCost{$sClassID}) ?
$::s_hashClassToWeightCost{$sClassID} :
undef;
$::s_Ship_sSeparatePackageDetails = '';
$::s_Ship_sMixedPackageDetails = '';
my $parrPackage;
foreach $parrPackage (@$parrShipSeparatePackages)
{
my $sUnitWeight = ($sClassID =~ /^1_/) ?
sprintf('%0.03f', int($$parrPackage[2] + 0.9999)) :
sprintf('%0.03f', $$parrPackage[2]);
my $nUnitCost =
(defined $phashWeightToCost) ?
$$phashWeightToCost{$sUnitWeight} :
0;
$::s_Ship_sSeparatePackageDetails .=
sprintf("%s\t%d\t%0.03f\t%d\n",
$$parrPackage[0], $$parrPackage[1], $$parrPackage[2], $nUnitCost);
}
my $parrSummary =
(@$parrMixedPackages > 0) ?
$$parrMixedPackages[-1] :
undef;
foreach $parrPackage (@$parrMixedPackages)
{
my $sUnitWeight = ($sClassID =~ /^1_/) ?
sprintf('%0.03f', int($$parrPackage[2] + 0.9999)) :
sprintf('%0.03f', $$parrPackage[2]);
my $nUnitCost =
(defined $phashWeightToCost && $parrSummary == $parrPackage) ?
$$phashWeightToCost{$sUnitWeight} :
0;
$::s_Ship_sMixedPackageDetails .=
sprintf("%s\t%d\t%0.03f\t%d\n",
$$parrPackage[0], $$parrPackage[1], $$parrPackage[2], $nUnitCost);
}
}
}
else
{
$::s_Ship_sOpaqueShipData = '';
$::s_Ship_nShipCharges = 0;
$::s_Ship_sSSPOpaqueShipData = '';
}
}
sub ClearUnusedSSPShippingEntries
{
if (CalculateQuantity() == 0)
{
my $sShipKey;
foreach $sShipKey (keys %::g_ShipInfo)
{
if($sShipKey =~ /^\d+_/)
{
delete $::g_ShipInfo{$sShipKey};
}
}
return;
}
}
sub GetUPSRates
{
my @arrShippingHashes;
my (%hashValidClasses, %hashClassToTotal, $sClassID);
my $sShipKey;
foreach $sShipKey (keys %::g_ShipInfo)
{
if($sShipKey =~ /^1_/)
{
delete $::g_ShipInfo{$sShipKey};
}
}
my $pSSPProvider = GetUPSSetup();
my ($nReturnCode, $sError, $sServiceLevelCode, $sRateChart,
$sShipperPostalCode, $sShipperCountry, $sConsigneePostalCode, $sConsigneeCountry,
$nResidential, $sPackagingType) =
GetShipmentDetails();
if($nReturnCode != $::SUCCESS)
{
return($nReturnCode, $sError);
}
my $sRSSRequestDataFormat;
$sRSSRequestDataFormat = $::XML_HEADER;
$sRSSRequestDataFormat .= GetUPSAccessRequestNode($pSSPProvider);
$sRSSRequestDataFormat .= $::XML_HEADER;
$sRSSRequestDataFormat .= "$sRateChart
";
$sRSSRequestDataFormat .= "$sServiceLevelCode
";
$sRSSRequestDataFormat .= " $sPackagingType
";
$sRSSRequestDataFormat .= "