add contract for product and refund parse

This commit is contained in:
2026-03-05 10:07:51 +08:00
parent d93fdee203
commit 4c49c2b71c
9 changed files with 122 additions and 38 deletions
@@ -5,7 +5,6 @@ declare(strict_types=1);
namespace App\Platform; namespace App\Platform;
use App\Entity\Parse\EntityParse; use App\Entity\Parse\EntityParse;
use InvalidArgumentException;
/** /**
* 产品解析器抽象基类 * 产品解析器抽象基类
@@ -15,5 +14,8 @@ use InvalidArgumentException;
*/ */
abstract class AbstractProductParse extends EntityParse implements ProductContract abstract class AbstractProductParse extends EntityParse implements ProductContract
{ {
/**
* 获取产品状态 ID(抽象方法,由子类实现)
*/
abstract public function getProductStatusId(string $platform_status): int;
} }
@@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace App\Platform;
use App\Entity\Parse\EntityParse;
/**
* 退款解析器抽象基类
*
* 继承 EntityParse 的通用能力,并实现 RefundContract 契约
* 提供退款解析的通用方法和辅助函数
*/
abstract class AbstractRefundParse extends EntityParse implements RefundContract
{
/**
* 获取退款状态 ID(抽象方法,由子类实现)
*/
abstract public function getRefundStatusId(string $platform_status): int;
/**
* 获取退款类型 ID(抽象方法,由子类实现)
*/
abstract public function getRefundTypeId(array $record): int;
/**
* 是否有父退款(抽象方法,由子类实现)
*/
abstract public function hasParentRefund(): bool;
/**
* 从原始数据格式化退款子项(抽象方法,由子类实现)
*/
abstract public function formatRefundItemsFromRaw(array $raw_data, ?array $platform_refund_id_to_local_refund_id_map): array;
/**
* 通用辅助方法:格式化货币金额
*
* @param float|int|string|null $amount 金额
* @param int $decimals 小数位数,默认 2 位
* @return float 格式化后的金额
*/
protected function formatAmount(float|int|string|null $amount, int $decimals = 2): float
{
return round((float)($amount ?? 0), $decimals);
}
}
-5
View File
@@ -98,11 +98,6 @@ class ProductConsumer extends ConsumerMessage
dump("Processing " . count($data_to_upsert) . " product(s) with batch upsert"); dump("Processing " . count($data_to_upsert) . " product(s) with batch upsert");
// 检测产品解析器是否实现了 getProductStatusId 方法
if (!method_exists($parse, 'getProductStatusId')) {
throw new \Exception('getProductStatusId method must be implemented in ' . $parse::class);
}
Db::beginTransaction(); Db::beginTransaction();
// 使用 upsert 批量处理产品插入和更新 // 使用 upsert 批量处理产品插入和更新
+9 -1
View File
@@ -12,5 +12,13 @@ namespace App\Platform;
*/ */
interface ProductContract interface ProductContract
{ {
/**
* 获取产品状态 ID
*
* 将平台产品状态映射到本地 ProductStatus 枚举
*
* @param string $platform_status 平台状态字符串
* @return int 本地产品状态 ID
*/
public function getProductStatusId(string $platform_status): int;
} }
-22
View File
@@ -5,7 +5,6 @@ declare(strict_types=1);
namespace App\Platform; namespace App\Platform;
use App\Entity\Parse\EntityParseFactory; use App\Entity\Parse\EntityParseFactory;
use App\Entity\Parse\EntityParseInterface;
use App\Utils\Log; use App\Utils\Log;
use Hyperf\Amqp\Annotation\Consumer; use Hyperf\Amqp\Annotation\Consumer;
use Hyperf\Amqp\Builder\QueueBuilder; use Hyperf\Amqp\Builder\QueueBuilder;
@@ -15,7 +14,6 @@ use Hyperf\Amqp\Producer;
use PhpAmqpLib\Message\AMQPMessage; use PhpAmqpLib\Message\AMQPMessage;
use Hyperf\DbConnection\Db; use Hyperf\DbConnection\Db;
use App\Model\RefundItem; use App\Model\RefundItem;
use Exception;
use Hyperf\Context\ApplicationContext; use Hyperf\Context\ApplicationContext;
use Throwable; use Throwable;
@@ -71,8 +69,6 @@ class RefundConsumer extends ConsumerMessage
try { try {
$parse = EntityParseFactory::createFromMessage($message); $parse = EntityParseFactory::createFromMessage($message);
$this->parseValidate($parse);
$meta = $data['meta'] ?? []; $meta = $data['meta'] ?? [];
$metadata = [ $metadata = [
'company_id' => $meta['company_id'] ?? null, 'company_id' => $meta['company_id'] ?? null,
@@ -299,22 +295,4 @@ class RefundConsumer extends ConsumerMessage
dump("Refund items processing completed"); dump("Refund items processing completed");
} }
protected function parseValidate(EntityParseInterface $parse): void
{
if (!method_exists($parse, 'hasParentRefund')) {
throw new Exception('hasParentRefund method must be implemented in ' . $parse::class);
}
if (!method_exists($parse, 'formatRefundItemsFromRaw')) {
throw new Exception('formatRefundItemsFromRaw method must be implemented in ' . $parse::class);
}
if (!method_exists($parse, 'getRefundStatusId')) {
throw new Exception('getRefundStatusId method must be implemented in ' . $parse::class);
}
if (!method_exists($parse, 'getRefundTypeId')) {
throw new Exception('getRefundTypeId method must be implemented in ' . $parse::class);
}
}
} }
+53
View File
@@ -0,0 +1,53 @@
<?php
declare(strict_types=1);
namespace App\Platform;
/**
* 退款解析器契约接口
*
* 定义所有电商平台退款解析器必须实现的方法
* 适用于:Shopee、Tmall、JD 等所有电商平台
*/
interface RefundContract
{
/**
* 获取退款状态 ID
*
* 将平台退款状态映射到本地 RefundStatus 枚举
*
* @param string $platform_status 平台退款状态字符串
* @return int 本地退款状态 ID
*/
public function getRefundStatusId(string $platform_status): int;
/**
* 获取退款类型 ID
*
* 根据退款记录判断退款类型(退货退款、仅退款等)
*
* @param array $record 单条退款原始数据
* @return int 本地退款类型 ID
*/
public function getRefundTypeId(array $record): int;
/**
* 是否有父退款
*
* 判断平台是否具有父子退款结构
* Shopee 有父退款(return 包含多个 item),Tmall 没有
*
* @return bool
*/
public function hasParentRefund(): bool;
/**
* 从原始数据格式化退款子项
*
* @param array $raw_data 原始数据数组
* @param array|null $platform_refund_id_to_local_refund_id_map 平台退款 ID => 本地数据库退款 ID 映射
* @return array 解析后的退款子项数据数组
*/
public function formatRefundItemsFromRaw(array $raw_data, ?array $platform_refund_id_to_local_refund_id_map): array;
}
@@ -10,7 +10,7 @@ use App\Platform\Shopee\Constants\ReturnStatus as ShopeeReturnStatus;
use App\Model\Company; use App\Model\Company;
use App\Model\Order; use App\Model\Order;
use App\Model\Store; use App\Model\Store;
use App\Entity\Parse\EntityParse; use App\Platform\AbstractRefundParse;
use Carbon\Carbon; use Carbon\Carbon;
use Hyperf\Collection\LazyCollection; use Hyperf\Collection\LazyCollection;
use InvalidArgumentException; use InvalidArgumentException;
@@ -21,7 +21,7 @@ use InvalidArgumentException;
* Shopee 具有完整的父子退款结构:一个 return 包含多个 item。 * Shopee 具有完整的父子退款结构:一个 return 包含多个 item。
* 每个 return 同时写入 refunds(主记录)和 refund_items(明细)两张表。 * 每个 return 同时写入 refunds(主记录)和 refund_items(明细)两张表。
*/ */
class Refund extends EntityParse class Refund extends AbstractRefundParse
{ {
/** /**
* 缓存 entityMap 中查询到的订单日期映射,供 formatRefundItemsFromRaw 复用 * 缓存 entityMap 中查询到的订单日期映射,供 formatRefundItemsFromRaw 复用
@@ -178,7 +178,7 @@ class Refund extends EntityParse
* @param array $platform_refund_id_to_local_refund_id_map [platform_refund_id => local db refund id] * @param array $platform_refund_id_to_local_refund_id_map [platform_refund_id => local db refund id]
* @return array * @return array
*/ */
public function formatRefundItemsFromRaw(array $raw_data, array $platform_refund_id_to_local_refund_id_map): array public function formatRefundItemsFromRaw(array $raw_data, ?array $platform_refund_id_to_local_refund_id_map): array
{ {
$records = isset($raw_data[0]) ? $raw_data : [$raw_data]; $records = isset($raw_data[0]) ? $raw_data : [$raw_data];
$items = []; $items = [];
@@ -7,7 +7,7 @@ namespace App\Platform\Tmall\EntityParse;
use App\Constants\ProductStatus; use App\Constants\ProductStatus;
use App\Model\Company; use App\Model\Company;
use App\Model\Store; use App\Model\Store;
use App\Entity\Parse\EntityParse; use App\Platform\AbstractProductParse;
use App\Platform\Tmall\Constants\ItemStatus; use App\Platform\Tmall\Constants\ItemStatus;
use Carbon\Carbon; use Carbon\Carbon;
use Hyperf\Collection\LazyCollection; use Hyperf\Collection\LazyCollection;
@@ -18,7 +18,7 @@ use InvalidArgumentException;
* *
* 将 Tmall 产品原始数据解析为本地 Product 模型格式 * 将 Tmall 产品原始数据解析为本地 Product 模型格式
*/ */
class Product extends EntityParse class Product extends AbstractProductParse
{ {
/** /**
* 公司作用域匹配 * 公司作用域匹配
@@ -15,7 +15,7 @@ use App\Model\Order;
use App\Model\OrderItem; use App\Model\OrderItem;
use App\Model\RefundItem; use App\Model\RefundItem;
use App\Model\Store; use App\Model\Store;
use App\Entity\Parse\EntityParse; use App\Platform\AbstractRefundParse;
use Carbon\Carbon; use Carbon\Carbon;
use Hyperf\Collection\LazyCollection; use Hyperf\Collection\LazyCollection;
use Hyperf\DbConnection\Db; use Hyperf\DbConnection\Db;
@@ -27,7 +27,7 @@ use InvalidArgumentException;
* Tmall 没有主退款和子退款的概念,每个售后单对应一个订单子项。 * Tmall 没有主退款和子退款的概念,每个售后单对应一个订单子项。
* 每个售后单同时写入 refunds(主记录)和 refund_items(明细)两张表。 * 每个售后单同时写入 refunds(主记录)和 refund_items(明细)两张表。
*/ */
class Refund extends EntityParse class Refund extends AbstractRefundParse
{ {
/** /**
* 公司作用域匹配 * 公司作用域匹配
@@ -140,7 +140,7 @@ class Refund extends EntityParse
* @param array $platform_refund_id_to_local_refund_id_map [platform_refund_id => local db refund id] * @param array $platform_refund_id_to_local_refund_id_map [platform_refund_id => local db refund id]
* @return array * @return array
*/ */
public function formatRefundItemsFromRaw(array $raw_data, array| null $platform_refund_id_to_local_refund_id_map = null): array public function formatRefundItemsFromRaw(array $raw_data, ?array $platform_refund_id_to_local_refund_id_map): array
{ {
$records = isset($raw_data[0]) ? $raw_data : [$raw_data]; $records = isset($raw_data[0]) ? $raw_data : [$raw_data];
$items = []; $items = [];