fix Machinable attribution

This commit is contained in:
O K
2025-12-08 21:32:11 +02:00
parent da38b3ccfd
commit 18ed87343c

View File

@@ -142,63 +142,39 @@ 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');
$this->externalLog(['calculateRate' => [$params, $shipping_cost, $products, $originalModule]]);
// --- 1. LEGACY CACHE CHECK ---
// We reuse the old module's cache table to save API calls
$zhCache = false;
$canCache = class_exists('\UspsPsLabels\Cache') && class_exists('\UspsPsLabels\CacheRate');
if ($canCache) { // 1. Get OAuth Token
// cacheCart() checks if products/address changed.
// If changed, it clears previous rates automatically.
$zhCache = \UspsPsLabels\Cache::cacheCart($params->id);
if (Validate::isLoadedObject($zhCache)) {
// Check if we already have a rate for this specific Carrier ID
$sql = 'SELECT rate FROM `' . _DB_PREFIX_ . 'uspsl_cache_rate`
WHERE id_cache = ' . (int)$zhCache->id . '
AND id_carrier = ' . (int)$params->id_carrier;
$cachedRate = Db::getInstance()->getValue($sql);
if ($cachedRate !== false && $cachedRate !== null) {
// $this->log("Returning DB Cached Rate: $cachedRate"); // Optional debug
// We must re-add the PrestaShop shipping cost (handling fees)
return (float)$cachedRate + $shipping_cost;
}
}
}
// -----------------------------
// 2. Get OAuth Token
$token = $this->getAccessToken(); $token = $this->getAccessToken();
if (!$token) return false; if (!$token) return false;
// 3. Identify Service // 2. Identify Service
$carrierId = $params->id_carrier; $carrierId = $params->id_carrier;
$sql = 'SELECT code FROM `' . _DB_PREFIX_ . 'uspsl_method` WHERE id_carrier = ' . (int)$carrierId; $sql = 'SELECT code FROM `' . _DB_PREFIX_ . 'uspsl_method` WHERE id_carrier = ' . (int)$carrierId;
$methodCode = Db::getInstance()->getValue($sql); $methodCode = Db::getInstance()->getValue($sql);
if (!$methodCode) return false; if (!$methodCode) return false;
// 4. 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) return false; if (!$newApiClass) return false;
// 5. Pack Products // 4. Pack Products
$packedBoxes = $originalModule->getHelper()->getCarrierHelper()->packProducts($products, $params->id); $packedBoxes = $originalModule->getHelper()->getCarrierHelper()->packProducts($products, $params->id);
if (empty($packedBoxes)) return false; if (empty($packedBoxes)) return false;
// 6. Initialize Client & Settings // 5. 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; $totalPrice = 0;
// Determine Price Type
$legacyPriceSetting = (int)Configuration::get('USPSL_COMMERCIAL'); $legacyPriceSetting = (int)Configuration::get('USPSL_COMMERCIAL');
$requestedPriceType = ($legacyPriceSetting > 0) ? 'COMMERCIAL' : 'RETAIL'; $requestedPriceType = ($legacyPriceSetting > 0) ? 'COMMERCIAL' : 'RETAIL';
// 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);
@@ -209,18 +185,28 @@ class Usps_Api_Bridge extends Module
// 7. Loop through boxes // 7. Loop through boxes
foreach ($packedBoxes as $packedBox) { foreach ($packedBoxes as $packedBox) {
// Weight (Lbs) - Min 0.1 to avoid errors
$weightInLbs = $this->convertUnit($packedBox->getWeight(), 'g', 'lbs', 3); $weightInLbs = $this->convertUnit($packedBox->getWeight(), 'g', 'lbs', 3);
if ($weightInLbs < 0.1) $weightInLbs = 0.1; if ($weightInLbs < 0.1) $weightInLbs = 0.1;
// Dimensions (Inches)
$box = $packedBox->getBox(); $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);
$category = 'MACHINABLE'; // --- PROCESSING CATEGORY LOGIC (FIXED) ---
if ($length > 22 || $width > 18 || $height > 15 || $weightInLbs > 25) { // "NONSTANDARD" is the V3 equivalent of a generic "Parcel" or "Package".
$category = 'NONSTANDARD'; // We only use "MACHINABLE" if it is strictly Ground Advantage AND fits dimensions.
// For Priority/Express, "NONSTANDARD" finds the correct Retail/Commercial SKU.
$category = 'NONSTANDARD';
if ($newApiClass === 'USPS_GROUND_ADVANTAGE') {
if ($length <= 22 && $width <= 18 && $height <= 15 && $weightInLbs >= 0.375 && $weightInLbs <= 25) {
$category = 'MACHINABLE';
}
} }
// -----------------------------------------
$payload = [ $payload = [
'originZIPCode' => $originZip, 'originZIPCode' => $originZip,
@@ -232,59 +218,53 @@ class Usps_Api_Bridge extends Module
'priceType' => $requestedPriceType, 'priceType' => $requestedPriceType,
'mailingDate' => date('Y-m-d', strtotime('+1 day')), 'mailingDate' => date('Y-m-d', strtotime('+1 day')),
'processingCategory' => $category, 'processingCategory' => $category,
'rateIndicator' => 'SP' 'rateIndicator' => 'SP' // SP = Single Piece (Variable dimensions)
]; ];
// Handle Flat Rates
$flatRateIndicator = $this->mapBoxToRateIndicator($box->getReference()); $flatRateIndicator = $this->mapBoxToRateIndicator($box->getReference());
if ($flatRateIndicator) { if ($flatRateIndicator) {
$payload['rateIndicator'] = $flatRateIndicator; $payload['rateIndicator'] = $flatRateIndicator;
// Flat rates technically ignore dims/category, but we keep valid enums
} }
$this->externalLog(['sendApiRequest' => [$client, $payload, $isInternational, $destAddress, $destZip]]);
// API REQUEST // --- SEND REQUEST ---
$response = $this->sendApiRequest($client, $payload, $isInternational, $destAddress, $destZip); $response = $this->sendApiRequest($client, $payload, $isInternational, $destAddress, $destZip);
$this->externalLog(['sendApiRequest' => ['response' => $response]]);
// Retry logic for Commercial rates // Retry Logic: If Commercial fails, try Retail
if (isset($response['error']) && $payload['priceType'] === 'COMMERCIAL') { if (isset($response['error']) && $payload['priceType'] === 'COMMERCIAL') {
$this->log("Commercial failed. Retrying RETAIL."); // $this->log("Commercial failed (" . $response['error'] . "). Retrying RETAIL.");
$payload['priceType'] = 'RETAIL'; $payload['priceType'] = 'RETAIL';
$response = $this->sendApiRequest($client, $payload, $isInternational, $destAddress, $destZip); $response = $this->sendApiRequest($client, $payload, $isInternational, $destAddress, $destZip);
} }
// Error Handling
if (isset($response['error'])) { if (isset($response['error'])) {
$this->log("API Fatal Error: " . $response['error']); // $this->log("API Fatal Error: " . $response['error']);
// $this->log("Payload: " . json_encode($payload));
return false; return false;
} }
// Parse Price
if (isset($response['totalBasePrice'])) { if (isset($response['totalBasePrice'])) {
$totalPrice += (float)$response['totalBasePrice']; $totalPrice += (float)$response['totalBasePrice'];
} 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.");
return false; return false;
} }
} }
// --- 8. SAVE TO LEGACY CACHE ---
if ($canCache && Validate::isLoadedObject($zhCache)) {
// We use the CacheRate class to save it properly
$newCacheRate = new \UspsPsLabels\CacheRate();
$newCacheRate->id_cache = $zhCache->id;
$newCacheRate->id_carrier = $params->id_carrier;
$newCacheRate->code = $methodCode;
$newCacheRate->rate = $totalPrice; // Store raw rate (without PS handling fees)
$newCacheRate->save();
}
// -------------------------------
return $totalPrice + $shipping_cost; return $totalPrice + $shipping_cost;
} }
/** /**
* Helper to send request with Runtime Caching & Domestic/Intl switching * Helper to send request with Runtime Caching & Domestic/Intl switching
*/ */
private function sendApiRequest($client, $payload, $isInternational, $destAddress, $destZip) private function sendApiRequest($client, $payload, $isInternational, $destAddress, $destZip)
{ {
$this->externalLog(['sendApiRequest' => [$client, $payload, $isInternational, $destAddress, $destZip]]);
// 1. Prepare the specific payload for the cache key // 1. Prepare the specific payload for the cache key
// We simulate the modifications we are about to do to ensure the key is accurate // We simulate the modifications we are about to do to ensure the key is accurate
$cachePayload = $payload; $cachePayload = $payload;
@@ -309,11 +289,9 @@ class Usps_Api_Bridge extends Module
if (isset($this->apiRuntimeCache[$cacheKey])) { if (isset($this->apiRuntimeCache[$cacheKey])) {
// Uncomment for deep debugging if needed // Uncomment for deep debugging if needed
// $this->log("Returning cached rate for key: " . $cacheKey); // $this->log("Returning cached rate for key: " . $cacheKey);
$this->externalLog(['sendApiRequest' => "Returning cached rate for key: " . $cacheKey]);
return $this->apiRuntimeCache[$cacheKey]; return $this->apiRuntimeCache[$cacheKey];
} }
$this->externalLog(['sendApiRequest' => ['cachePayload' => $cachePayload]]);
// 4. Perform Request // 4. Perform Request
if ($isInternational) { if ($isInternational) {
@@ -341,7 +319,6 @@ class Usps_Api_Bridge extends Module
if ($shouldCache) { if ($shouldCache) {
$this->apiRuntimeCache[$cacheKey] = $response; $this->apiRuntimeCache[$cacheKey] = $response;
} }
$this->externalLog(['sendApiRequest' => ['response' => $response]]);
return $response; return $response;
} }