From cdb9341a4f258ad6fb6a7768f75348693c3e5d40 Mon Sep 17 00:00:00 2001 From: O K Date: Fri, 2 Jan 2026 09:32:44 +0200 Subject: [PATCH] improve address detection logic --- .../modules/zh_uspslabels/zh_uspslabels.php | 4 +- usps_api_bridge.php | 89 ++++++++++++------- 2 files changed, 58 insertions(+), 35 deletions(-) diff --git a/override/modules/zh_uspslabels/zh_uspslabels.php b/override/modules/zh_uspslabels/zh_uspslabels.php index f1d0596..374bfa3 100644 --- a/override/modules/zh_uspslabels/zh_uspslabels.php +++ b/override/modules/zh_uspslabels/zh_uspslabels.php @@ -10,7 +10,9 @@ class Zh_UspsLabelsOverride extends Zh_UspsLabels * Intercept the rate calculation call. */ public function getPackageShippingCost($params, $shipping_cost, $products) - { + + + { // 1. Check if Bridge Module exists and is active /** @var Usps_Api_Bridge $bridge */ $bridge = Module::getInstanceByName('usps_api_bridge'); diff --git a/usps_api_bridge.php b/usps_api_bridge.php index 6eeb175..a422ac6 100644 --- a/usps_api_bridge.php +++ b/usps_api_bridge.php @@ -153,7 +153,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'); @@ -161,38 +161,32 @@ class Usps_Api_Bridge extends Module $token = $this->getAccessToken(); if (!$token) return false; - - // 2. Identify Service (Use the Module's ID, not the Cart's ID) - // $originalModule->id_carrier is the carrier currently being calculated in the loop. + // 2. Identify Service (Module Loop context) $carrierId = (int)$originalModule->id_carrier; - - // Fallback for edge cases where module ID might be missing (rare) + // Fallback if (!$carrierId && isset($params->id_carrier)) { $carrierId = (int)$params->id_carrier; } // 3. Get Method Code $sql = 'SELECT code FROM `' . _DB_PREFIX_ . 'uspsl_method` WHERE id_carrier = ' . (int)$carrierId; - $methodCode = Db::getInstance()->getValue($sql); + $methodCode = \Db::getInstance()->getValue($sql); - // If this carrier ID isn't in the USPS table, it's not a USPS carrier (or map is broken) if (!$methodCode) return false; - // --- 4. CHECK LEGACY DB CACHE --- - // (Moved after method identification so we query cache for the CORRECT carrier) $zhCache = false; $canCache = class_exists('\UspsPsLabels\Cache') && class_exists('\UspsPsLabels\CacheRate'); if ($canCache) { $zhCache = \UspsPsLabels\Cache::cacheCart($params->id); - if (Validate::isLoadedObject($zhCache)) { + if (\Validate::isLoadedObject($zhCache)) { $sql = 'SELECT rate FROM `' . _DB_PREFIX_ . 'uspsl_cache_rate` WHERE id_cache = ' . (int)$zhCache->id . ' - AND id_carrier = ' . (int)$carrierId; // Use the correct ID here too! + AND id_carrier = ' . (int)$carrierId; - $cachedRate = Db::getInstance()->getValue($sql); + $cachedRate = \Db::getInstance()->getValue($sql); if ($cachedRate !== false && $cachedRate !== null) { return (float)$cachedRate + $shipping_cost; @@ -201,10 +195,42 @@ class Usps_Api_Bridge extends Module } // ------------------------------- - // 5. Determine International Status & Map Code - $destAddress = new Address($params->id_address_delivery); - $isInternational = ($destAddress->id_country != Country::getByIso('US')); + // 5. Determine International Status & Address Data (Cookie/Object Hybrid) + $destAddress = new \Address($params->id_address_delivery); + $destZip = ''; + $destCountryIso = 'US'; + if (\Validate::isLoadedObject($destAddress)) { + // Real Address exists + $destZip = $destAddress->postcode; + $destCountryIso = \Country::getIsoById($destAddress->id_country); + } else { + // Fallback for Estimator (Cookies) + $context = \Context::getContext(); + + if (isset($context->cookie->id_country) && $context->cookie->id_country) { + $destCountryIso = \Country::getIsoById($context->cookie->id_country); + } elseif (isset($params->id_country) && $params->id_country) { + $destCountryIso = \Country::getIsoById($params->id_country); + } + + if (isset($context->cookie->postcode) && $context->cookie->postcode) { + $destZip = $context->cookie->postcode; + } + + // If absolutely no data, we can't calculate + if (empty($destZip) && empty($destCountryIso)) { + return false; + } + } + + // Clean Data + $originZip = $this->getOriginZip($originalModule); + $originZip = substr(preg_replace('/[^0-9]/', '', $originZip), 0, 5); + $destZip = substr(preg_replace('/[^0-9]/', '', $destZip), 0, 5); + $isInternational = ($destCountryIso !== 'US'); + + // Map Code $newApiClass = $this->mapServiceCodeToApiClass($methodCode, $isInternational); if (!$newApiClass) return false; @@ -213,18 +239,13 @@ class Usps_Api_Bridge extends Module if (empty($packedBoxes)) return false; // 7. Setup Client - $client = new UspsV3Client($token, (bool)Configuration::get('USPS_BRIDGE_LIVE_MODE')); + $client = new UspsV3Client($token, (bool)\Configuration::get('USPS_BRIDGE_LIVE_MODE')); $totalPrice = 0; - $legacyPriceSetting = (int)Configuration::get('USPSL_COMMERCIAL'); + $legacyPriceSetting = (int)\Configuration::get('USPSL_COMMERCIAL'); $requestedPriceType = ($legacyPriceSetting > 0) ? 'COMMERCIAL' : 'RETAIL'; - // 8. Address Data - $originZip = $this->getOriginZip($originalModule); - $originZip = substr(preg_replace('/[^0-9]/', '', $originZip), 0, 5); - $destZip = substr(preg_replace('/[^0-9]/', '', $destAddress->postcode), 0, 5); - - // 9. Loop through boxes + // 8. Loop through boxes foreach ($packedBoxes as $packedBox) { $weightInLbs = $this->convertUnit($packedBox->getWeight(), 'g', 'lbs', 3); @@ -260,14 +281,16 @@ class Usps_Api_Bridge extends Module $payload['rateIndicator'] = $flatRateIndicator; } - $response = $this->sendApiRequest($client, $payload, $isInternational, $destAddress, $destZip); + // FIX: Pass destCountryIso directly, do not rely on Address object inside this helper + $response = $this->sendApiRequest($client, $payload, $isInternational, $destCountryIso, $destZip); if (isset($response['error']) && $payload['priceType'] === 'COMMERCIAL') { $payload['priceType'] = 'RETAIL'; - $response = $this->sendApiRequest($client, $payload, $isInternational, $destAddress, $destZip); + $response = $this->sendApiRequest($client, $payload, $isInternational, $destCountryIso, $destZip); } if (isset($response['error'])) { + // $this->log("API Fatal Error: " . $response['error']); return false; } @@ -280,11 +303,11 @@ class Usps_Api_Bridge extends Module } } - // --- 10. SAVE TO LEGACY DB CACHE --- - if ($canCache && Validate::isLoadedObject($zhCache)) { + // --- 9. SAVE TO LEGACY DB CACHE --- + if ($canCache && \Validate::isLoadedObject($zhCache)) { $newCacheRate = new \UspsPsLabels\CacheRate(); $newCacheRate->id_cache = $zhCache->id; - $newCacheRate->id_carrier = $carrierId; // Use Correct ID + $newCacheRate->id_carrier = $carrierId; $newCacheRate->code = $methodCode; $newCacheRate->rate = $totalPrice; $newCacheRate->save(); @@ -298,7 +321,7 @@ class Usps_Api_Bridge extends Module /** * Helper to send request with Runtime Caching & Domestic/Intl switching */ - private function sendApiRequest($client, $payload, $isInternational, $destAddress, $destZip) + private function sendApiRequest($client, $payload, $isInternational, $destCountryIso, $destZip) { // 1. Prepare the specific payload for the cache key @@ -306,7 +329,7 @@ class Usps_Api_Bridge extends Module $cachePayload = $payload; $cachePayload['destinationEntryFacilityType'] = 'NONE'; if ($isInternational) { - $cachePayload['destinationCountryCode'] = Country::getIsoById($destAddress->id_country); + $cachePayload['destinationCountryCode'] = $destCountryIso; // Use string directly $cachePayload['originZIPCode'] = $payload['originZIPCode']; // Ensure consistency // unset($cachePayload['destinationEntryFacilityType']); unset($cachePayload['destinationZIPCode']); @@ -323,12 +346,10 @@ class Usps_Api_Bridge extends Module // 3. Check Cache if (isset($this->apiRuntimeCache[$cacheKey])) { - // Uncomment for deep debugging if needed - // $this->log("Returning cached rate for key: " . $cacheKey); return $this->apiRuntimeCache[$cacheKey]; } - $this->externalLog(['sendApiRequest' => ['payload' => $payload, 'isInternational' => $isInternational, 'destAddress' => $destAddress, 'destZip' => $destZip]]); + $this->externalLog(['sendApiRequest' => ['payload' => $payload, 'isInternational' => $isInternational, 'destCountryIso' => $destCountryIso, 'destZip' => $destZip]]); // 4. Perform Request if ($isInternational) {