added RETAIL handling

This commit is contained in:
O K
2025-12-08 13:17:25 +02:00
parent 3d8638eb07
commit 5c2798dedd

View File

@@ -139,7 +139,7 @@ class Usps_Api_Bridge extends Module
return $helper->generateForm([$fields_form]); return $helper->generateForm([$fields_form]);
} }
public function calculateRate($params, $shipping_cost, $products, $originalModule) public function calculateRate($params, $shipping_cost, $products, $originalModule)
{ {
require_once(dirname(__FILE__) . '/classes/UspsV3Client.php'); require_once(dirname(__FILE__) . '/classes/UspsV3Client.php');
@@ -155,59 +155,60 @@ class Usps_Api_Bridge extends Module
$methodCode = Db::getInstance()->getValue($sql); $methodCode = Db::getInstance()->getValue($sql);
if (!$methodCode) { if (!$methodCode) {
return false; return false;
} }
// 3. Map Old Code to New API Enum // 3. Map Old Code to New API Enum
$newApiClass = $this->mapServiceCodeToApiClass($methodCode); $newApiClass = $this->mapServiceCodeToApiClass($methodCode);
if (!$newApiClass) { if (!$newApiClass) {
$this->log("Mapping failed for legacy code: " . $methodCode);
return false; return false;
} }
// 4. Pack Products // 4. Pack Products
$packedBoxes = $originalModule->getHelper()->getCarrierHelper()->packProducts($products, $params->id); $packedBoxes = $originalModule->getHelper()->getCarrierHelper()->packProducts($products, $params->id);
if (empty($packedBoxes)) { if (empty($packedBoxes)) {
$this->log("Box packer returned empty."); $this->log("Box packer returned empty.");
return false; return false;
} }
// 5. Initialize API Client // 5. Initialize Client & Settings
$client = new UspsV3Client($token, (bool)Configuration::get('USPS_BRIDGE_LIVE_MODE')); $client = new UspsV3Client($token, (bool)Configuration::get('USPS_BRIDGE_LIVE_MODE'));
$totalPrice = 0; $totalPrice = 0;
// Determine Price Type from Old Module Settings
// 0 = Regular (Retail), 1 = Commercial, 2 = Commercial Plus
$legacyPriceSetting = (int)Configuration::get('USPSL_COMMERCIAL');
$requestedPriceType = ($legacyPriceSetting > 0) ? 'COMMERCIAL' : 'RETAIL';
// 6. Address Data // 6. Address Data
$originZip = $this->getOriginZip($originalModule); $originZip = $this->getOriginZip($originalModule);
$destAddress = new Address($params->id_address_delivery); $destAddress = new Address($params->id_address_delivery);
$originZip = substr(preg_replace('/[^0-9]/', '', $originZip), 0, 5); $originZip = substr(preg_replace('/[^0-9]/', '', $originZip), 0, 5);
$destZip = substr(preg_replace('/[^0-9]/', '', $destAddress->postcode), 0, 5); $destZip = substr(preg_replace('/[^0-9]/', '', $destAddress->postcode), 0, 5);
$isInternational = ($destAddress->id_country != Country::getByIso('US')); $isInternational = ($destAddress->id_country != Country::getByIso('US'));
// 7. Loop through boxes // 7. Loop through boxes
foreach ($packedBoxes as $packedBox) { foreach ($packedBoxes as $packedBox) {
// Weight Conversion (Grams -> Pounds) // Weight (Lbs) - Ensure minimum 0.1
$weightInLbs = $this->convertUnit($packedBox->getWeight(), 'g', 'lbs', 3); $weightInLbs = $this->convertUnit($packedBox->getWeight(), 'g', 'lbs', 3);
if ($weightInLbs < 0.1) $weightInLbs = 0.1;
// USPS requires minimum 0.001 lbs. 0 causes errors. // Dimensions (Inches)
if ($weightInLbs <= 0) $weightInLbs = 0.1; $box = $packedBox->getBox();
// Dimensions (mm -> Inches)
$box = $packedBox->getBox();
$length = $this->convertUnit($box->getOuterLength(), 'mm', 'in', 2); $length = $this->convertUnit($box->getOuterLength(), 'mm', 'in', 2);
$width = $this->convertUnit($box->getOuterWidth(), 'mm', 'in', 2); $width = $this->convertUnit($box->getOuterWidth(), 'mm', 'in', 2);
$height = $this->convertUnit($box->getOuterDepth(), 'mm', 'in', 2); $height = $this->convertUnit($box->getOuterDepth(), 'mm', 'in', 2);
// Determine Processing Category (Crucial for V3 API) // Processing Category Logic
// Machinable: Length <= 22", Width <= 18", Height <= 15", Weight >= 6oz (0.375lbs) and <= 25lbs
$category = 'MACHINABLE'; $category = 'MACHINABLE';
if ($length > 22 || $width > 18 || $height > 15 || $weightInLbs > 25 || $weightInLbs < 0.375) { if ($length > 22 || $width > 18 || $height > 15 || $weightInLbs > 25) {
$category = 'NONSTANDARD'; $category = 'NONSTANDARD';
} }
// Build Payload // Build Base Payload
$payload = [ $payload = [
'originZIPCode' => $originZip, 'originZIPCode' => $originZip,
'weight' => $weightInLbs, 'weight' => $weightInLbs,
@@ -215,39 +216,31 @@ class Usps_Api_Bridge extends Module
'width' => $width, 'width' => $width,
'height' => $height, 'height' => $height,
'mailClass' => $newApiClass, 'mailClass' => $newApiClass,
'priceType' => 'COMMERCIAL', 'priceType' => $requestedPriceType,
'mailingDate' => date('Y-m-d', strtotime('+1 day')), 'mailingDate' => date('Y-m-d', strtotime('+1 day')),
'processingCategory' => $category, 'processingCategory' => $category,
'rateIndicator' => 'SP' // Single Piece 'rateIndicator' => 'SP'
]; ];
// Flat Rate Override // Flat Rate Override
$flatRateIndicator = $this->mapBoxToRateIndicator($box->getReference()); $flatRateIndicator = $this->mapBoxToRateIndicator($box->getReference());
if ($flatRateIndicator) { if ($flatRateIndicator) {
$payload['rateIndicator'] = $flatRateIndicator; $payload['rateIndicator'] = $flatRateIndicator;
// Dimensions technically ignored for Flat Rate, but required by API schema
// Processing category usually irrelevant for Flat Rate but must be valid Enum
} }
if ($isInternational) { // --- API REQUEST LOGIC WITH RETRY ---
$payload['destinationCountryCode'] = Country::getIsoById($destAddress->id_country); $response = $this->sendApiRequest($client, $payload, $isInternational, $destAddress, $destZip);
$payload['originZIPCode'] = $originZip;
// Remove domestic specific fields
unset($payload['destinationEntryFacilityType']);
unset($payload['destinationZIPCode']);
$response = $client->getInternationalRate($payload); // If Failed AND we tried COMMERCIAL, try falling back to RETAIL
} else { if (isset($response['error']) && $payload['priceType'] === 'COMMERCIAL') {
$payload['destinationZIPCode'] = $destZip; $this->log("Commercial rate failed (" . $response['error'] . "). Retrying with RETAIL.");
$payload['destinationEntryFacilityType'] = 'NONE'; $payload['priceType'] = 'RETAIL';
$response = $this->sendApiRequest($client, $payload, $isInternational, $destAddress, $destZip);
$response = $client->getDomesticRate($payload);
} }
// Log Payload on Error for Debugging // Final Error Check
if (isset($response['error'])) { if (isset($response['error'])) {
$this->log("API Error: " . $response['error']); $this->log("API Fatal Error: " . $response['error']);
$this->log("Payload causing error: " . json_encode($payload));
return false; return false;
} }
@@ -257,7 +250,7 @@ class Usps_Api_Bridge extends Module
} elseif (isset($response['rateOptions'][0]['totalBasePrice'])) { } elseif (isset($response['rateOptions'][0]['totalBasePrice'])) {
$totalPrice += (float)$response['rateOptions'][0]['totalBasePrice']; $totalPrice += (float)$response['rateOptions'][0]['totalBasePrice'];
} else { } else {
$this->log("API Response missing price. Full response: " . json_encode($response)); $this->log("API Response missing price.");
return false; return false;
} }
} }
@@ -265,6 +258,27 @@ class Usps_Api_Bridge extends Module
return $totalPrice + $shipping_cost; return $totalPrice + $shipping_cost;
} }
/**
* Helper to send request and handle Domestic vs International switching
*/
private function sendApiRequest($client, $payload, $isInternational, $destAddress, $destZip)
{
if ($isInternational) {
$payload['destinationCountryCode'] = Country::getIsoById($destAddress->id_country);
// Cleanup domestic fields
unset($payload['destinationEntryFacilityType']);
unset($payload['destinationZIPCode']);
return $client->getInternationalRate($payload);
}
// Domestic
$payload['destinationZIPCode'] = $destZip;
$payload['destinationEntryFacilityType'] = 'NONE';
return $client->getDomesticRate($payload);
}
/** /**
* Simple Unit Converter to replace the dependency on the old module's class * Simple Unit Converter to replace the dependency on the old module's class
*/ */