From 5c2798deddfe9be7bdd5c61c2a7e4740fc1bec61 Mon Sep 17 00:00:00 2001 From: O K Date: Mon, 8 Dec 2025 13:17:25 +0200 Subject: [PATCH] added RETAIL handling --- usps_api_bridge.php | 88 ++++++++++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 37 deletions(-) diff --git a/usps_api_bridge.php b/usps_api_bridge.php index 46c4d6c..b19ab74 100644 --- a/usps_api_bridge.php +++ b/usps_api_bridge.php @@ -139,7 +139,7 @@ class Usps_Api_Bridge extends Module 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'); @@ -155,59 +155,60 @@ class Usps_Api_Bridge extends Module $methodCode = Db::getInstance()->getValue($sql); if (!$methodCode) { - return false; + return false; } // 3. Map Old Code to New API Enum $newApiClass = $this->mapServiceCodeToApiClass($methodCode); if (!$newApiClass) { - $this->log("Mapping failed for legacy code: " . $methodCode); return false; } // 4. Pack Products $packedBoxes = $originalModule->getHelper()->getCarrierHelper()->packProducts($products, $params->id); - + if (empty($packedBoxes)) { $this->log("Box packer returned empty."); return false; } - // 5. Initialize API Client + // 5. Initialize Client & Settings $client = new UspsV3Client($token, (bool)Configuration::get('USPS_BRIDGE_LIVE_MODE')); $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 $originZip = $this->getOriginZip($originalModule); $destAddress = new Address($params->id_address_delivery); - + $originZip = substr(preg_replace('/[^0-9]/', '', $originZip), 0, 5); $destZip = substr(preg_replace('/[^0-9]/', '', $destAddress->postcode), 0, 5); $isInternational = ($destAddress->id_country != Country::getByIso('US')); // 7. Loop through boxes foreach ($packedBoxes as $packedBox) { - - // Weight Conversion (Grams -> Pounds) + + // Weight (Lbs) - Ensure minimum 0.1 $weightInLbs = $this->convertUnit($packedBox->getWeight(), 'g', 'lbs', 3); + if ($weightInLbs < 0.1) $weightInLbs = 0.1; - // USPS requires minimum 0.001 lbs. 0 causes errors. - if ($weightInLbs <= 0) $weightInLbs = 0.1; - - // Dimensions (mm -> Inches) - $box = $packedBox->getBox(); + // Dimensions (Inches) + $box = $packedBox->getBox(); $length = $this->convertUnit($box->getOuterLength(), 'mm', 'in', 2); $width = $this->convertUnit($box->getOuterWidth(), 'mm', 'in', 2); $height = $this->convertUnit($box->getOuterDepth(), 'mm', 'in', 2); - // Determine Processing Category (Crucial for V3 API) - // Machinable: Length <= 22", Width <= 18", Height <= 15", Weight >= 6oz (0.375lbs) and <= 25lbs + // Processing Category Logic $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'; } - // Build Payload + // Build Base Payload $payload = [ 'originZIPCode' => $originZip, 'weight' => $weightInLbs, @@ -215,39 +216,31 @@ class Usps_Api_Bridge extends Module 'width' => $width, 'height' => $height, 'mailClass' => $newApiClass, - 'priceType' => 'COMMERCIAL', + 'priceType' => $requestedPriceType, 'mailingDate' => date('Y-m-d', strtotime('+1 day')), 'processingCategory' => $category, - 'rateIndicator' => 'SP' // Single Piece + 'rateIndicator' => 'SP' ]; // Flat Rate Override $flatRateIndicator = $this->mapBoxToRateIndicator($box->getReference()); if ($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) { - $payload['destinationCountryCode'] = Country::getIsoById($destAddress->id_country); - $payload['originZIPCode'] = $originZip; - // Remove domestic specific fields - unset($payload['destinationEntryFacilityType']); - unset($payload['destinationZIPCode']); + // --- API REQUEST LOGIC WITH RETRY --- + $response = $this->sendApiRequest($client, $payload, $isInternational, $destAddress, $destZip); - $response = $client->getInternationalRate($payload); - } else { - $payload['destinationZIPCode'] = $destZip; - $payload['destinationEntryFacilityType'] = 'NONE'; - - $response = $client->getDomesticRate($payload); + // If Failed AND we tried COMMERCIAL, try falling back to RETAIL + if (isset($response['error']) && $payload['priceType'] === 'COMMERCIAL') { + $this->log("Commercial rate failed (" . $response['error'] . "). Retrying with RETAIL."); + $payload['priceType'] = 'RETAIL'; + $response = $this->sendApiRequest($client, $payload, $isInternational, $destAddress, $destZip); } - // Log Payload on Error for Debugging + // Final Error Check if (isset($response['error'])) { - $this->log("API Error: " . $response['error']); - $this->log("Payload causing error: " . json_encode($payload)); + $this->log("API Fatal Error: " . $response['error']); return false; } @@ -257,7 +250,7 @@ class Usps_Api_Bridge extends Module } elseif (isset($response['rateOptions'][0]['totalBasePrice'])) { $totalPrice += (float)$response['rateOptions'][0]['totalBasePrice']; } else { - $this->log("API Response missing price. Full response: " . json_encode($response)); + $this->log("API Response missing price."); return false; } } @@ -265,6 +258,27 @@ class Usps_Api_Bridge extends Module 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 */