shopee refund entity parse draft
This commit is contained in:
@@ -0,0 +1,265 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Platform\Shopee\EntityParse;
|
||||||
|
|
||||||
|
use App\Constants\RefundStatus;
|
||||||
|
use App\Constants\RefundType;
|
||||||
|
use App\Platform\Shopee\Constants\ReturnStatus as ShopeeReturnStatus;
|
||||||
|
use App\Model\Company;
|
||||||
|
use App\Model\Store;
|
||||||
|
use App\Entity\Parse\EntityParse;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Hyperf\Collection\LazyCollection;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shopee 退款解析器
|
||||||
|
*
|
||||||
|
* Shopee 具有完整的父子退款结构:一个 return 包含多个 item。
|
||||||
|
* 每个 return 同时写入 refunds(主记录)和 refund_items(明细)两张表。
|
||||||
|
*/
|
||||||
|
class Refund 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 店铺作用域匹配
|
||||||
|
*
|
||||||
|
* Shopee 使用 platform_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)
|
||||||
|
->where('platform_store_id', '=', $platform_store_id)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if (!$store) {
|
||||||
|
throw new InvalidArgumentException("Platform shopee store id {$platform_store_id} not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $store;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实体数据映射 - 映射到 refunds 表
|
||||||
|
*
|
||||||
|
* @param array $raw_data 原始数据数组
|
||||||
|
* @return LazyCollection 每个元素为可供 Refund Model::fill() 使用的数组
|
||||||
|
*/
|
||||||
|
public function entityMap(array $raw_data): LazyCollection
|
||||||
|
{
|
||||||
|
return LazyCollection::make(function () use ($raw_data) {
|
||||||
|
$records = isset($raw_data[0]) ? $raw_data : [$raw_data];
|
||||||
|
$tz = $this->getStore()->getTimezoneString();
|
||||||
|
|
||||||
|
foreach ($records as $record) {
|
||||||
|
$raw = \json_encode($record);
|
||||||
|
$refund_amount = (float) ($record['refund_amount'] ?? 0);
|
||||||
|
|
||||||
|
yield [
|
||||||
|
'company_id' => $this->getCompany()->id,
|
||||||
|
'platform_id' => $this->getPlatform()->id,
|
||||||
|
'store_id' => $this->getStore()->id,
|
||||||
|
'order_id' => $record['t_order_id'] ?? null,
|
||||||
|
'platform_order_id' => $record['order_sn'],
|
||||||
|
'platform_refund_id' => $record['return_sn'],
|
||||||
|
'refund_status_id' => $this->getRefundStatusId($record['status']),
|
||||||
|
'refund_type_id' => $this->getRefundTypeId($record),
|
||||||
|
'reason' => $record['text_reason'] ?? $record['reason'] ?? null,
|
||||||
|
'refund_amount' => $refund_amount,
|
||||||
|
'freight_refund' => 0,
|
||||||
|
'refund_total' => $refund_amount,
|
||||||
|
'currency' => $record['currency'] ?? 'USD',
|
||||||
|
'buyer_user_id' => $record['user']['username'] ?? null,
|
||||||
|
'order_created_date' => Carbon::createFromTimestamp($record['create_time'], $tz)->format('Y-m-d H:i:sP'),
|
||||||
|
'order_paid_date' => Carbon::createFromTimestamp($record['create_time'], $tz)->format('Y-m-d H:i:sP'),
|
||||||
|
'created_date' => Carbon::createFromTimestamp($record['create_time'], $tz)->format('Y-m-d H:i:sP'),
|
||||||
|
'updated_date' => isset($record['update_time']) ? Carbon::createFromTimestamp($record['update_time'], $tz)->format('Y-m-d H:i:sP') : null,
|
||||||
|
'completed_date' => ($record['status'] === 'CLOSED' || $record['status'] === 'ACCEPTED') && isset($record['update_time'])
|
||||||
|
? Carbon::createFromTimestamp($record['update_time'], $tz)->format('Y-m-d H:i:sP')
|
||||||
|
: null,
|
||||||
|
'raw' => $raw,
|
||||||
|
'ext' => null,
|
||||||
|
'hash' => \md5($raw),
|
||||||
|
'created_at' => Carbon::now()->format('Y-m-d H:i:sP'),
|
||||||
|
'updated_at' => Carbon::now()->format('Y-m-d H:i:sP'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取实体的唯一键字段
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getUniqueBy(): array
|
||||||
|
{
|
||||||
|
return ['store_id', 'platform_refund_id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取可更新的字段列表
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getUpdateFields(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'order_id',
|
||||||
|
'refund_status_id',
|
||||||
|
'refund_type_id',
|
||||||
|
'reason',
|
||||||
|
'refund_amount',
|
||||||
|
'freight_refund',
|
||||||
|
'refund_total',
|
||||||
|
'buyer_user_id',
|
||||||
|
'updated_date',
|
||||||
|
'completed_date',
|
||||||
|
'raw',
|
||||||
|
'ext',
|
||||||
|
'hash',
|
||||||
|
'updated_at',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化退款子项数据 - 映射到 refund_items 表
|
||||||
|
*
|
||||||
|
* Shopee 一个 return 包含多个 item,每个 item 映射为一条 refund_item
|
||||||
|
*
|
||||||
|
* @param array $raw_data 原始数据数组
|
||||||
|
* @param array $platform_refund_id_to_local_refund_id_map [platform_refund_id => local db refund id]
|
||||||
|
* @return 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];
|
||||||
|
$items = [];
|
||||||
|
$tz = $this->getStore()->getTimezoneString();
|
||||||
|
|
||||||
|
foreach ($records as $record) {
|
||||||
|
$return_sn = $record['return_sn'];
|
||||||
|
$refund_id = $platform_refund_id_to_local_refund_id_map[$return_sn] ?? 0;
|
||||||
|
$refund_status_id = $this->getRefundStatusId($record['status']);
|
||||||
|
$refund_type_id = $this->getRefundTypeId($record);
|
||||||
|
|
||||||
|
foreach ($record['item'] ?? [] as $item) {
|
||||||
|
$raw = \json_encode($item);
|
||||||
|
|
||||||
|
$items[] = [
|
||||||
|
'company_id' => $this->getCompany()->id,
|
||||||
|
'platform_id' => $this->getPlatform()->id,
|
||||||
|
'store_id' => $this->getStore()->id,
|
||||||
|
'refund_id' => $refund_id,
|
||||||
|
'platform_parent_refund_id' => $return_sn,
|
||||||
|
'platform_refund_id' => strval($item['item_id']) . '_' . strval($item['model_id'] ?? 0),
|
||||||
|
'refund_status_id' => $refund_status_id,
|
||||||
|
'refund_type_id' => $refund_type_id,
|
||||||
|
'reason' => $record['text_reason'] ?? $record['reason'] ?? null,
|
||||||
|
'currency' => $record['currency'] ?? 'USD',
|
||||||
|
'buyer_user_id' => $record['user']['username'] ?? null,
|
||||||
|
'platform_order_id' => $record['order_sn'],
|
||||||
|
'platform_sub_order_id' => null,
|
||||||
|
'platform_product_id' => strval($item['item_id']),
|
||||||
|
'quantity' => $item['amount'] ?? 0,
|
||||||
|
'refund_amount' => (float) ($item['refund_amount'] ?? 0),
|
||||||
|
'order_created_date' => Carbon::createFromTimestamp($record['create_time'], $tz)->format('Y-m-d H:i:sP'),
|
||||||
|
'order_paid_date' => Carbon::createFromTimestamp($record['create_time'], $tz)->format('Y-m-d H:i:sP'),
|
||||||
|
'created_date' => Carbon::createFromTimestamp($record['create_time'], $tz)->format('Y-m-d H:i:sP'),
|
||||||
|
'updated_date' => isset($record['update_time']) ? Carbon::createFromTimestamp($record['update_time'], $tz)->format('Y-m-d H:i:sP') : null,
|
||||||
|
'completed_date' => ($record['status'] === 'CLOSED' || $record['status'] === 'ACCEPTED') && isset($record['update_time'])
|
||||||
|
? Carbon::createFromTimestamp($record['update_time'], $tz)->format('Y-m-d H:i:sP')
|
||||||
|
: null,
|
||||||
|
'raw' => $raw,
|
||||||
|
'ext' => null,
|
||||||
|
'created_at' => Carbon::now()->format('Y-m-d H:i:sP'),
|
||||||
|
'updated_at' => Carbon::now()->format('Y-m-d H:i:sP'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $items;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 Shopee 退款状态映射为系统退款状态 ID
|
||||||
|
*
|
||||||
|
* @param string $platform_status Shopee ReturnStatus 字符串
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getRefundStatusId(string $platform_status): int
|
||||||
|
{
|
||||||
|
$map = $this->refundStatusMap();
|
||||||
|
return $map[$platform_status] ?? RefundStatus::APPLIED->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shopee ReturnStatus → 系统 RefundStatus 映射
|
||||||
|
*
|
||||||
|
* @return array<string, int>
|
||||||
|
*/
|
||||||
|
private function refundStatusMap(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
ShopeeReturnStatus::REQUESTED->value => RefundStatus::APPLIED->value,
|
||||||
|
ShopeeReturnStatus::ACCEPTED->value => RefundStatus::SELLER_ACCEPTED->value,
|
||||||
|
ShopeeReturnStatus::PROCESSING->value => RefundStatus::SELLER_ACCEPTED->value,
|
||||||
|
ShopeeReturnStatus::JUDGING->value => RefundStatus::SELLER_DISPUTE->value,
|
||||||
|
ShopeeReturnStatus::SELLER_DISPUTE->value => RefundStatus::SELLER_DISPUTE->value,
|
||||||
|
ShopeeReturnStatus::CLOSED->value => RefundStatus::CLOSED->value,
|
||||||
|
ShopeeReturnStatus::CANCELLED->value => RefundStatus::CLOSED->value,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据 Shopee 退款数据判断退款类型
|
||||||
|
*
|
||||||
|
* @param array $record 单条退款原始数据
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getRefundTypeId(array $record): int
|
||||||
|
{
|
||||||
|
$needs_logistics = $record['needs_logistics'] ?? false;
|
||||||
|
|
||||||
|
if ($needs_logistics) {
|
||||||
|
return RefundType::RETURN_AND_REFUND->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RefundType::REFUND_ONLY->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user