--- a/app/Services/ShipmentProcessorService.php 2026-09-11 07:22:51.526092308 -0700 +++ b/app/Services/ShipmentProcessorService.php 2026-09-11 07:22:51.549092275 -0700 @@ -624,14 +624,20 @@ */ private function extractWhimsLocationInfo($partscan, $whimsDb) { - // Try uniq_key first (format: whims_{product_id}_{warehouse_id}_{location_id}) + // uniq_key is written by WhimsSyncInventory as whims_{part number}_{warehouse_id}_{location_id}. + // The first segment is WHIMS products.product_id (the part number string), not the numeric + // products.id, so resolve it by part number. A purely numeric part number (e.g. 625430) must + // never be read as the primary key; doing so silently skipped every numeric-part deduction. if (!empty($partscan->source) && $partscan->source === 'whims' && !empty($partscan->uniq_key)) { - if (preg_match('/^whims_(\d+)_(\d+)_(\d+|null)$/', $partscan->uniq_key, $matches)) { - return [ - 'product_id' => (int)$matches[1], - 'warehouse_id' => (int)$matches[2], - 'location_id' => ($matches[3] === 'null') ? null : (int)$matches[3], - ]; + if (preg_match('/^whims_(.+)_(\d+)_(\d+|null)$/', $partscan->uniq_key, $matches)) { + $product = $whimsDb->table('products')->where('product_id', $matches[1])->first(); + if ($product) { + return [ + 'product_id' => (int)$product->id, + 'warehouse_id' => (int)$matches[2], + 'location_id' => ($matches[3] === 'null' || (int)$matches[3] === 0) ? null : (int)$matches[3], + ]; + } } } @@ -639,17 +645,13 @@ if (!empty($partscan->params)) { $params = json_decode($partscan->params, true); if (is_array($params) && isset($params['whims_product_id'], $params['whims_warehouse_id'])) { - $whimsProductId = $params['whims_product_id']; - - // If not numeric, look up the numeric id from WHIMS products table - if (!is_numeric($whimsProductId)) { - $product = $whimsDb->table('products')->where('product_id', $whimsProductId)->first(); - if ($product) { - $whimsProductId = $product->id; - } else { - return null; - } + // whims_product_id also holds the part number, even when it is all digits. + // Cast to string so MySQL compares as text rather than coercing the column to a number. + $product = $whimsDb->table('products')->where('product_id', (string)$params['whims_product_id'])->first(); + if (!$product) { + return null; } + $whimsProductId = $product->id; return [ 'product_id' => (int)$whimsProductId,