diff --git a/backend/app/Platform/Shopee/EntityParse/Refund.php b/backend/app/Platform/Shopee/EntityParse/Refund.php new file mode 100644 index 0000000..f2f9810 --- /dev/null +++ b/backend/app/Platform/Shopee/EntityParse/Refund.php @@ -0,0 +1,265 @@ +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 + */ + 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; + } +}