From f24e6dd52cbba24d06bebdfdae6fbc1be3c71623 Mon Sep 17 00:00:00 2001 From: Nick Zeng Date: Thu, 5 Feb 2026 10:38:36 +0800 Subject: [PATCH] update tmall order parse --- .../app/Platform/Tmall/EntityParse/Order.php | 112 +++++++++++++++--- 1 file changed, 98 insertions(+), 14 deletions(-) diff --git a/backend/app/Platform/Tmall/EntityParse/Order.php b/backend/app/Platform/Tmall/EntityParse/Order.php index 23a6709..99f26a8 100644 --- a/backend/app/Platform/Tmall/EntityParse/Order.php +++ b/backend/app/Platform/Tmall/EntityParse/Order.php @@ -7,10 +7,12 @@ namespace App\Platform\Tmall\EntityParse; use App\Constants\OrderStatus; use App\Model\Company; use App\Model\Model as Entity; +use App\Model\Product; use App\Model\Store; use App\Entity\Parse\EntityParse; use App\Constants\PaymentMethod; use App\Constants\OrderType; +use Carbon\Carbon; use Hyperf\Collection\LazyCollection; use InvalidArgumentException; @@ -263,44 +265,126 @@ class Order extends EntityParse /** - * + * * orderItems 的输出结果为 \App\Model\OrderItem::fill() 可以直接使用的数据格式 - * - * @param array $raw_data - * @param array $platform_orders_id_to_local_db_order_id_map - * - * - * @param array $order_items_to_product_id_map = [ - * num_iid => local_db_product_id - * ] - * @return array + * + * @param array $raw_data + * @param array $platform_orders_id_to_local_db_order_id_map + + * @return array */ - public function formatOrderItemsFromRaw(array $raw_data, array $platform_orders_id_to_local_db_order_id_map, array $order_items_to_product_id_map = []): array + public function formatOrderItemsFromRaw(array $raw_data, array $platform_orders_id_to_local_db_order_id_map): array { // 由于 $raw_data 是批量数据,包含多条订单结果,因此订单子项需要从集合中提取 // Tmall 平台响应体的数据格式为: collection->payload->orders // $platform_orders_id_to_local_db_order_id_map 内部元素数据格式为 [platform_order_id => local db order id] $items = []; + $product_keys = []; // 索引 => 查询键 foreach ($raw_data as $raw_orders) { + $parent_order_created_date = Carbon::parse($raw_orders['created']); + foreach ($raw_orders['orders']['order'] as $raw_order_item) { // 数据库中父订单 id $db_order_id = $platform_orders_id_to_local_db_order_id_map[$raw_orders['tid']]; $platform_order_id = strval($raw_orders['tid']); - $local_product_id = empty($order_items_to_product_id_map) || !isset($order_items_to_product_id_map[$raw_order_item['num_iid']]) ? 0 : $order_items_to_product_id_map[$raw_order_item['num_iid']]; - $items[] = $this->tmallOrderItemMap($raw_order_item, $platform_order_id, $db_order_id, $raw_orders['created'], $local_product_id); + + // 记录当前索引 + $index = count($items); + + // 先添加 item,product_id 初始为 0 + $items[] = $this->tmallOrderItemMap($raw_order_item, $platform_order_id, $db_order_id, $parent_order_created_date, 0); + + // 记录该索引对应的产品查询键 (Tmall 使用 num_iid 作为 item_id,sku_id 作为 model_id) + $model_id = !empty($raw_order_item['sku_id']) ? (string)$raw_order_item['sku_id'] : null; + $product_keys[$index] = $this->buildProductMapKey((string)$raw_order_item['num_iid'], $model_id); + } + } + + // 批量查询产品 ID 并更新 items + if (!empty($product_keys)) { + $products_id_map = $this->batchQueryProducts($product_keys); + foreach ($product_keys as $index => $key) { + if (isset($products_id_map[$key])) { + $items[$index]['product_id'] = $products_id_map[$key]; + } } } return $items; } + /** + * 构建产品映射键 + * + * @param string $item_id 平台商品 ID + * @param string|null $model_id 平台 SKU ID + * @return string + */ + private function buildProductMapKey(string $item_id, ?string $model_id): string + { + return $item_id . ':' . ($model_id ?? 'null'); + } + + /** + * 批量查询产品 ID + * + * 使用 PostgreSQL VALUES + JOIN 语法优化,避免生成冗长的 OR 条件链 + * + * @param array $product_keys 索引 => 查询键 的映射 + * @return array 查询键 => 产品 ID 的映射 + */ + private function batchQueryProducts(array $product_keys): array + { + $store_id = $this->getStore()->id; + $unique_keys = array_unique(array_values($product_keys)); + + if (empty($unique_keys)) { + return []; + } + + // 构建 VALUES 子句和绑定参数 + $values = []; + $bindings = []; + + foreach ($unique_keys as $key) { + [$item_id, $model_id] = explode(':', $key, 2); + $values[] = '(?::text, ?::text)'; + $bindings[] = $item_id; + $bindings[] = $model_id === 'null' ? null : $model_id; + } + + $valuesClause = implode(', ', $values); + $bindings[] = $store_id; + + // PostgreSQL 原生 SQL:VALUES 作为驱动表(小表在左侧) + // store_id 条件移入 JOIN ON 子句,让索引过滤更早介入 + $sql = " + SELECT p.id, p.platform_item_id, p.platform_model_id + FROM (VALUES {$valuesClause}) AS v(item_id, model_id) + INNER JOIN products p + ON p.store_id = ? + AND p.platform_item_id = v.item_id + AND (p.platform_model_id = v.model_id OR (v.model_id IS NULL AND p.platform_model_id IS NULL)) + "; + + $products = \Hyperf\DbConnection\Db::select($sql, $bindings); + + $map = []; + foreach ($products as $product) { + $key = $this->buildProductMapKey($product->platform_item_id, $product->platform_model_id); + $map[$key] = $product->id; + } + + return $map; + } + /** * Tmall 订单子项映射转换 * @return void */ - private function tmallOrderItemMap(array $item, string $platform_order_id, int $parent_order_id, string $parent_order_created_date, int $local_product_id = 0): array + private function tmallOrderItemMap(array $item, string $platform_order_id, int $parent_order_id, Carbon $parent_order_created_date, int $local_product_id = 0): array { // $item = [