From 091b4cf1b10eee76e6c8713615a5c50c8d191ccc Mon Sep 17 00:00:00 2001 From: Nick Zeng Date: Fri, 6 Feb 2026 10:58:21 +0800 Subject: [PATCH] update shopee entity parse --- .../Platform/Shopee/EntityParse/Product.php | 243 +++++++++--------- 1 file changed, 118 insertions(+), 125 deletions(-) diff --git a/backend/app/Platform/Shopee/EntityParse/Product.php b/backend/app/Platform/Shopee/EntityParse/Product.php index 414fb8e..0a5878f 100644 --- a/backend/app/Platform/Shopee/EntityParse/Product.php +++ b/backend/app/Platform/Shopee/EntityParse/Product.php @@ -4,46 +4,59 @@ declare(strict_types=1); namespace App\Platform\Shopee\EntityParse; +use App\Constants\ProductStatus; use App\Model\Company; -use App\Model\Model as Entity; use App\Model\Store; use App\Platform\AbstractProductParse; -use App\Platform\Shopee\Constants\OrderStatus; -use App\Constants\PaymentMethod; use Carbon\Carbon; use Hyperf\Collection\LazyCollection; -use Hyperf\Context\ApplicationContext; -use Psr\Log\LoggerInterface; use InvalidArgumentException; /** - * Shopee 订单解析器 + * Shopee 产品解析器 * - * 继承 AbstractOrderParse, 实现 Shopee 平台特定的 Order 解析逻辑 - * 实现 OrderContract 契约中定义的 parseOrderItems 方法 + * @TODO 待实现:参照 Tmall\EntityParse\Product 实现 Shopee 产品数据解析 * - * @attention 此类文件名为 Product.php,但实际处理订单数据,建议重命名为 Order.php + * Shopee 产品原始数据结构示例: + * { + * "item_id": 123456789, + * "item_name": "商品名称", + * "item_sku": "SKU001", + * "item_status": "NORMAL", + * "price_info": { "current_price": 99.00, "currency": "SGD" }, + * "stock_info": { "current_stock": 100 }, + * "image": { "image_url_list": ["https://..."] }, + * "model_list": [ + * { "model_id": 111, "model_sku": "SKU001-A", "current_price": 99.00, "stock_info": { "current_stock": 50 } } + * ], + * "create_time": 1640000000, + * "update_time": 1640100000 + * } + * + * 状态映射: + * - NORMAL -> ACTIVE + * - BANNED -> BANNED + * - UNLIST -> INACTIVE + * - REVIEWING -> REVIEWING + * - SELLER_DELETE -> SELLER_DELETE + * - SHOPEE_DELETE -> PLATFORM_DELETE */ class Product extends AbstractProductParse { /** * 公司作用域匹配 * - * 从 metadata 中提取 company_id,然后查询数据库获取公司对象 - * * @param array $metadata * @return Company * @throws InvalidArgumentException */ public function companyScopeMatch(array $metadata): Company { - // 验证必需字段 if (!isset($metadata['company_id'])) { throw new InvalidArgumentException('company_id is required in metadata'); } $company_id = $metadata['company_id']; - $company = Company::find($company_id); if (!$company) { @@ -56,29 +69,25 @@ class Product extends AbstractProductParse /** * 店铺作用域匹配 * - * 从 metadata 中提取 store_id,然后查询数据库获取店铺对象 - * * @param array $metadata * @return Store * @throws InvalidArgumentException */ public function storeScopeMatch(array $metadata): Store { - // 验证必需字段 if (!isset($metadata['platform_store_id'])) { throw new InvalidArgumentException('platform_store_id is required in metadata'); } $platform_store_id = $metadata['platform_store_id']; - $shopee_platform_id = 25; - $store = Store::where('platform_id','=', $shopee_platform_id) + $store = Store::where('platform_id', '=', $shopee_platform_id) ->where('platform_store_id', '=', $platform_store_id) ->first(); if (!$store) { - throw new InvalidArgumentException("Platform shopee store id {$shopee_platform_id} not found"); + throw new InvalidArgumentException("Shopee store with platform_store_id {$platform_store_id} not found"); } return $store; @@ -87,152 +96,136 @@ class Product extends AbstractProductParse /** * 实体数据映射 * - * 将原始数据映射为可供 Model 使用的数组集合 + * @TODO 待实现:解析 Shopee 产品原始数据 * - * @attention 当前返回格式为 ['order' => [...], 'items' => [...]] - * 但 ProductConsumer 第 153-157 行期望直接返回订单数据数组(参考 Tmall 实现) - * 需要调整返回格式以兼容 ProductConsumer 的 upsert 操作 - * - * @TODO 调整返回格式: - * - 方案1:改为直接返回订单数据数组(与 Tmall 一致) - * - 方案2:修改 ProductConsumer 以支持当前的嵌套结构 - * - * @param array $raw_data 原始数据数组,通常来自 $data['raw_data'] - * @return LazyCollection 返回 LazyCollection,每个元素为可供 Model::fill() 使用的数组 + * @param array $raw_data 原始数据数组 + * @return LazyCollection */ public function entityMap(array $raw_data): LazyCollection { - // 使用 LazyCollection 进行延迟处理,提高性能 + // TODO: 实现 Shopee 产品数据映射 + // 参考 Tmall\EntityParse\Product::entityMap() 实现 return LazyCollection::make(function () use ($raw_data) { - // 如果 raw_data 是单个记录,转换为数组 $records = isset($raw_data[0]) ? $raw_data : [$raw_data]; foreach ($records as $record) { - dump($record); + // TODO: 解析 model_list(规格列表) + // 无规格时返回单条记录,有规格时每个 model 返回一条记录 + yield $this->mapSingleProduct($record, null); } }); } + /** + * 映射单个产品记录 + * + * @TODO 待实现:根据 Shopee 实际数据结构完善字段映射 + * + * @param array $record 商品主记录 + * @param array|null $model 规格记录 + * @return array + */ + private function mapSingleProduct(array $record, ?array $model): array + { + $raw = \json_encode($record); + $platform_item_id = (string) ($record['item_id'] ?? ''); + $platform_model_id = $model ? (string) ($model['model_id'] ?? '') : null; + + return [ + 'company_id' => $this->getCompany()->id, + 'platform_id' => $this->getPlatform()->id, + 'store_id' => $this->getStore()->id, + 'status_id' => $this->getProductStatusId($record['item_status'] ?? 'NORMAL'), + 'type_id' => 1, + 'warehouse_id' => null, + 'sub_warehouse_id' => null, + 'platform_item_id' => $platform_item_id, + 'platform_model_id' => $platform_model_id, + 'origin_sku_id' => $model['model_sku'] ?? $record['item_sku'] ?? null, + 'mapped_sku_id' => null, + 'barcode' => null, + 'hscode' => null, + 'bundled' => null, + 'price' => $model['current_price'] ?? $record['price_info']['current_price'] ?? '0.00', + 'currency' => $record['price_info']['currency'] ?? 'USD', + 'num' => $model['stock_info']['current_stock'] ?? $record['stock_info']['current_stock'] ?? 0, + 'url' => null, + 'picture' => $record['image']['image_url_list'][0] ?? null, + 'name' => $record['item_name'] ?? null, + 'raw' => $raw, + 'ext' => null, + 'hash' => \md5($raw), + 'created_date' => isset($record['create_time']) + ? Carbon::createFromTimestamp($record['create_time']) + : null, + 'updated_date' => isset($record['update_time']) + ? Carbon::createFromTimestamp($record['update_time']) + : null, + 'created_at' => date('Y-m-d H:i:s'), + 'updated_at' => date('Y-m-d H:i:s'), + ]; + } /** - * 获取唯一键字段(对应数据库唯一索引) - * - * 对应数据库约束: - * UNIQUE INDEX orders_store_platform_order_unique (store_id, platform_order_id) + * 获取唯一键字段 * * @return array */ public function getUniqueBy(): array { - return ['store_id', 'platform_product_id']; + return ['store_id', 'platform_item_id', 'platform_model_id']; } /** * 获取可更新字段列表 * - * 排除:主键、唯一键、创建时间、关联 ID - * * @return array */ public function getUpdateFields(): array { - // 手动指定(推荐:明确且高效,无数据库查询开销) return [ - 'order_status_id', - 'payment_method_id', - 'buyer_user_id', - 'presale', - 'total_amount', - 'total_paid', - 'total_discount', - 'total_received', - 'freight_fee', - 'tax_fee', - 'discount_fee', - 'commission_fee', - 'coupon_amount', - 'voucher_amount', - 'order_type_id', - 'updated_date', - 'paid_date', - 'shipping_date', - 'zipcode', - 'city', - 'province', - 'country', + 'status_id', + 'type_id', + 'warehouse_id', + 'sub_warehouse_id', + 'origin_sku_id', + 'mapped_sku_id', + 'barcode', + 'hscode', + 'bundled', + 'price', + 'currency', + 'num', + 'url', + 'picture', + 'name', 'raw', 'ext', + 'hash', + 'updated_date', 'updated_at', ]; - - // 动态计算方案(如果表字段经常变化,可以使用): - // $entity = $this->entityMatch([ - // 'company_id' => $this->getCompany()->id, - // 'platform_id' => $this->getPlatform()->id, - // 'store_id' => $this->getStore()->id, - // ]); - // $excludeFields = array_merge( - // ['id', 'created_at', 'created_date', 'company_id', 'platform_id'], - // $this->getUniqueBy() - // ); - // return $this->getTableColumnsExcept($entity, $excludeFields); } /** - * 根据 Shopee 产品状态确定对应的本地订单状态 + * 获取产品状态 ID * - * @required ProductConsumer 要求实现此方法(第 130-132 行) - * @see \App\Constants\OrderStatus + * 将 Shopee 产品状态映射到本地 ProductStatus 枚举 * - * @param string $platform_order_status Shopee 平台订单状态 - * @return int 本地订单状态 ID + * @param string $platform_status Shopee 平台状态 + * @return int */ - public function getProductStatusId(string $platform_order_status): int + public function getProductStatusId(string $platform_status): int { - - } - - /** - * Shopee 产品状态到本地产品状态的映射表 - * - * @see \App\Platform\Shopee\Constants\ProductStatus Shopee 产品订单状态枚举 - * @see \App\Constants\OrderStatus 本地产品状态枚举 - * - * @return array - */ - private function ProducttatusMap(): array - { - return [ - // 未付款 -> 等待付款 - 'UNPAID' => \App\Constants\OrderStatus::PAYMENT_PENDING->value, - - // 可发货(已付款,等待卖家安排发货)-> 付款完成 - 'READY_TO_SHIP' => \App\Constants\OrderStatus::PAYMENT_COMPLETE->value, - - // 已处理(卖家已安排发货并获取物流单号)-> 等待发货 - 'PROCESSED' => \App\Constants\OrderStatus::AWAITING_SHIPMENT->value, - - // 重新发货(3PL 取件失败,需要重新安排发货)-> 等待发货 - 'RETRY_SHIP' => \App\Constants\OrderStatus::AWAITING_SHIPMENT->value, - - // 已发货(包裹已交给 3PL 或已被 3PL 取走)-> 已发货 - 'SHIPPED' => \App\Constants\OrderStatus::SHIPPED->value, - - // 待确认收货(买家已收到订单)-> 已发货 - 'TO_CONFIRM_RECEIVE' => \App\Constants\OrderStatus::SHIPPED->value, - - // 取消中(订单取消正在处理)-> 取消请求中 - 'IN_CANCEL' => \App\Constants\OrderStatus::CANCEL_REQUESTED->value, - - // 已取消 -> 取消确认 - 'CANCELLED' => \App\Constants\OrderStatus::CANCEL_CONFIRMED->value, - - // 退货中(买家请求退货,退货正在处理)-> 取消请求中 - 'TO_RETURN' => \App\Constants\OrderStatus::CANCEL_REQUESTED->value, - - // 已完成 -> 完成 - 'COMPLETED' => \App\Constants\OrderStatus::FINISHED->value, + $status_map = [ + 'NORMAL' => ProductStatus::ACTIVE->value, + 'BANNED' => ProductStatus::BANNED->value, + 'UNLIST' => ProductStatus::INACTIVE->value, + 'REVIEWING' => ProductStatus::REVIEWING->value, + 'SELLER_DELETE' => ProductStatus::SELLER_DELETE->value, + 'SHOPEE_DELETE' => ProductStatus::PLATFORM_DELETE->value, ]; - } + return $status_map[$platform_status] ?? ProductStatus::ACTIVE->value; + } }