update tmall product entity
This commit is contained in:
@@ -0,0 +1,211 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Platform\Tmall\EntityParse;
|
||||||
|
|
||||||
|
use App\Constants\ProductStatus;
|
||||||
|
use App\Model\Company;
|
||||||
|
use App\Model\Store;
|
||||||
|
use App\Entity\Parse\EntityParse;
|
||||||
|
use App\Platform\Tmall\Constants\ItemStatus;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Hyperf\Collection\LazyCollection;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 天猫产品解析器
|
||||||
|
*
|
||||||
|
* 将 Tmall 产品原始数据解析为本地 Product 模型格式
|
||||||
|
*/
|
||||||
|
class Product extends EntityParse
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 公司作用域匹配
|
||||||
|
*
|
||||||
|
* @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) {
|
||||||
|
throw new InvalidArgumentException("Company with ID {$company_id} not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $company;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 店铺作用域匹配
|
||||||
|
*
|
||||||
|
* @param array $metadata
|
||||||
|
* @return Store
|
||||||
|
* @throws InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function storeScopeMatch(array $metadata): Store
|
||||||
|
{
|
||||||
|
if (!isset($metadata['store_id'])) {
|
||||||
|
throw new InvalidArgumentException('store_id is required in metadata');
|
||||||
|
}
|
||||||
|
|
||||||
|
$store_id = $metadata['store_id'];
|
||||||
|
$store = Store::find($store_id);
|
||||||
|
|
||||||
|
if (!$store) {
|
||||||
|
throw new InvalidArgumentException("Store with ID {$store_id} not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $store;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实体数据映射
|
||||||
|
*
|
||||||
|
* 将原始产品数据映射为可供 Product Model 使用的数组集合
|
||||||
|
*
|
||||||
|
* 每个 SKU 规格生成一条独立记录。
|
||||||
|
*
|
||||||
|
* Tmall 平台两种场景,数据结构有区别,分别为
|
||||||
|
* 1. 单个商品为一个独立 SKU
|
||||||
|
* 2. 单个商品为套装或组合商品,内部包含多个 SKU
|
||||||
|
*
|
||||||
|
* @param array $raw_data 原始数据数组
|
||||||
|
* @return LazyCollection
|
||||||
|
*/
|
||||||
|
public function entityMap(array $raw_data): LazyCollection
|
||||||
|
{
|
||||||
|
return LazyCollection::make(function () use ($raw_data) {
|
||||||
|
$records = isset($raw_data[0]) ? $raw_data : [$raw_data];
|
||||||
|
|
||||||
|
foreach ($records as $record) {
|
||||||
|
$skus = $record['skus']['sku'] ?? [];
|
||||||
|
|
||||||
|
if (empty($skus)) {
|
||||||
|
// 无 SKU 规格商品,单条记录
|
||||||
|
yield $this->mapSingleProduct($record, null);
|
||||||
|
} else {
|
||||||
|
// 有 SKU 规格商品,每个 SKU 一条记录
|
||||||
|
foreach ($skus as $sku) {
|
||||||
|
yield $this->mapSingleProduct($record, $sku);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 映射单个产品记录
|
||||||
|
*
|
||||||
|
* @param array $record 商品主记录
|
||||||
|
* @param array|null $sku SKU 规格记录
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function mapSingleProduct(array $record, ?array $sku): array
|
||||||
|
{
|
||||||
|
$raw = \json_encode($record);
|
||||||
|
$platform_item_id = (string) $record['num_iid'];
|
||||||
|
$platform_model_id = $sku ? (string) $sku['sku_id'] : null;
|
||||||
|
|
||||||
|
return [
|
||||||
|
'company_id' => $this->getCompany()->id,
|
||||||
|
'platform_id' => $this->getPlatform()->id,
|
||||||
|
'store_id' => $this->getStore()->id,
|
||||||
|
'status_id' => $this->getProductStatusId($record['approve_status'] ?? ItemStatus::ONSALE->value),
|
||||||
|
'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' => $sku['outer_id'] ?? $record['outer_id'] ?? null,
|
||||||
|
'mapped_sku_id' => null,
|
||||||
|
'barcode' => $sku['barcode'] ?? $sku['outer_id'] ?? $record['outer_id'] ?? null,
|
||||||
|
'hscode' => null,
|
||||||
|
'bundled' => null,
|
||||||
|
'price' => $sku['price'] ?? $record['price'] ?? '0.00',
|
||||||
|
'currency' => 'CNY',
|
||||||
|
'num' => $sku['quantity'] ?? $record['num'] ?? 0,
|
||||||
|
'url' => $record['detail_url'] ?? null,
|
||||||
|
'picture' => $record['pic_url'] ?? null,
|
||||||
|
'name' => $record['title'] ?? null,
|
||||||
|
'raw' => $raw,
|
||||||
|
'ext' => null,
|
||||||
|
'hash' => \md5($raw),
|
||||||
|
'created_date' => isset($record['created']) ? Carbon::parse($record['created'], $this->getStore()->getTimezoneString())->format('Y-m-d H:i:sP') : null,
|
||||||
|
'updated_date' => isset($record['modified']) ? Carbon::parse($record['modified'], $this->getStore()->getTimezoneString())->format('Y-m-d H:i:sP') : null,
|
||||||
|
'created_at' => Carbon::now()->format('Y-m-d H:i:sP'),
|
||||||
|
'updated_at' => Carbon::now()->format('Y-m-d H:i:sP'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取唯一键字段
|
||||||
|
*
|
||||||
|
* 对应数据库约束:products_store_item_model_unique
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getUniqueBy(): array
|
||||||
|
{
|
||||||
|
return ['store_id', 'platform_item_id', 'platform_model_id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取可更新字段列表
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getUpdateFields(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'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',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取产品状态 ID
|
||||||
|
*
|
||||||
|
* 将 Tmall 产品状态映射到本地 ProductStatus 枚举
|
||||||
|
*
|
||||||
|
* @see ItemStatus Tmall 平台商品状态枚举
|
||||||
|
* @see ProductStatus 本地产品状态枚举
|
||||||
|
*
|
||||||
|
* @param string $platform_status Tmall 平台状态
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getProductStatusId(string $platform_status): int
|
||||||
|
{
|
||||||
|
$status_map = [
|
||||||
|
ItemStatus::ONSALE->value => ProductStatus::ACTIVE->value,
|
||||||
|
ItemStatus::INSTOCK->value => ProductStatus::INACTIVE->value,
|
||||||
|
];
|
||||||
|
|
||||||
|
return $status_map[$platform_status] ?? ProductStatus::INACTIVE->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user