From a280385c5c1809a522719f2f02eb2f1c0c981fa2 Mon Sep 17 00:00:00 2001 From: Nick Zeng Date: Tue, 10 Feb 2026 13:53:53 +0800 Subject: [PATCH] tmall entity parse draft --- .../app/Platform/Tmall/EntityParse/Refund.php | 262 ++++++++++++++++++ 1 file changed, 262 insertions(+) create mode 100644 backend/app/Platform/Tmall/EntityParse/Refund.php diff --git a/backend/app/Platform/Tmall/EntityParse/Refund.php b/backend/app/Platform/Tmall/EntityParse/Refund.php new file mode 100644 index 0000000..a04f85a --- /dev/null +++ b/backend/app/Platform/Tmall/EntityParse/Refund.php @@ -0,0 +1,262 @@ +getStore()->getTimezoneString(); + $refund_fee = (float) ($record['refund_fee'] ?? 0); + + yield [ + 'company_id' => $this->getCompany()->id, + 'platform_id' => $this->getPlatform()->id, + 'store_id' => $this->getStore()->id, + 'order_id' => null, + 'platform_order_id' => strval($record['tid']), + 'platform_refund_id' => strval($record['refund_id']), + 'refund_status_id' => $this->getRefundStatusId($record['status']), + 'refund_type_id' => $this->getRefundTypeId($record), + 'reason' => $record['reason'] ?? null, + 'refund_amount' => $refund_fee, + 'freight_refund' => 0, + 'refund_total' => $refund_fee, + 'currency' => 'CNY', + 'buyer_user_id' => $record['buyer_open_uid'] ?? null, + 'order_created_date' => Carbon::parse($record['created'], $tz)->format('Y-m-d H:i:sP'), + 'order_paid_date' => Carbon::parse($record['created'], $tz)->format('Y-m-d H:i:sP'), + 'created_date' => Carbon::parse($record['created'], $tz)->format('Y-m-d H:i:sP'), + 'updated_date' => isset($record['modified']) ? Carbon::parse($record['modified'], $tz)->format('Y-m-d H:i:sP') : null, + 'completed_date' => isset($record['end_time']) ? Carbon::parse($record['end_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'), + ]; + } + }); + } + + /** + * 获取实体的唯一键字段(用于 upsert 的 uniqueBy 参数) + * + * @return array + */ + public function getUniqueBy(): array + { + return ['store_id', 'platform_refund_id']; + } + + /** + * 获取可更新的字段列表(用于 upsert 的 update 参数) + * + * @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 表 + * + * Tmall 每个售后单同时作为一条 refund_item 记录 + * 需要在 refunds upsert 完成后调用,以获取 refund_id 映射 + * + * @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 = []; + + foreach ($records as $record) { + $platform_refund_id = strval($record['refund_id']); + $refund_id = $platform_refund_id_to_local_refund_id_map[$platform_refund_id] ?? 0; + $tz = $this->getStore()->getTimezoneString(); + $raw = \json_encode($record); + + $items[] = [ + 'company_id' => $this->getCompany()->id, + 'platform_id' => $this->getPlatform()->id, + 'store_id' => $this->getStore()->id, + 'refund_id' => $refund_id, + 'platform_parent_refund_id' => '', + 'platform_refund_id' => $platform_refund_id, + 'refund_status_id' => $this->getRefundStatusId($record['status']), + 'refund_type_id' => $this->getRefundTypeId($record), + 'reason' => $record['reason'] ?? null, + 'currency' => 'CNY', + 'buyer_user_id' => $record['buyer_open_uid'] ?? null, + 'platform_order_id' => strval($record['tid']), + 'platform_sub_order_id' => strval($record['oid']), + 'platform_product_id' => isset($record['num_iid']) ? strval($record['num_iid']) : null, + 'quantity' => $record['num'] ?? 0, + 'refund_amount' => (float) ($record['refund_fee'] ?? 0), + 'order_created_date' => Carbon::parse($record['created'], $tz)->format('Y-m-d H:i:sP'), + 'order_paid_date' => Carbon::parse($record['created'], $tz)->format('Y-m-d H:i:sP'), + 'created_date' => Carbon::parse($record['created'], $tz)->format('Y-m-d H:i:sP'), + 'updated_date' => isset($record['modified']) ? Carbon::parse($record['modified'], $tz)->format('Y-m-d H:i:sP') : null, + 'completed_date' => isset($record['end_time']) ? Carbon::parse($record['end_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; + } + + /** + * 将 Tmall 退款状态映射为系统退款状态 ID + * + * @param string $platformStatus + * @return int + */ + public function getRefundStatusId(string $platform_status): int + { + $map = $this->refundStatusMap(); + return $map[$platform_status] ?? RefundStatus::APPLIED->value; + } + + /** + * Tmall 退款状态 → 系统退款状态映射 + * + * @return array + */ + private function refundStatusMap(): array + { + return [ + TmallRefundStatus::WAIT_SELLER_AGREE->value => RefundStatus::APPLIED->value, + TmallRefundStatus::WAIT_BUYER_RETURN_GOODS->value => RefundStatus::SELLER_ACCEPTED->value, + TmallRefundStatus::WAIT_SELLER_CONFIRM_GOODS->value => RefundStatus::SELLER_ACCEPTED->value, + TmallRefundStatus::SELLER_REFUSE_BUYER->value => RefundStatus::REFUSED->value, + TmallRefundStatus::SUCCESS->value => RefundStatus::SUCCESS->value, + TmallRefundStatus::CLOSED->value => RefundStatus::CLOSED->value, + ]; + } + + /** + * 根据 Tmall 售后单数据判断退款类型 + * + * @param array $record 单条售后单原始数据 + * @return int + */ + public function getRefundTypeId(array $record): int + { + $has_good_return = $record['has_good_return'] ?? false; + $good_status = $record['good_status'] ?? ''; + + // 买家已退货或等待退货 → 退货退款 + if ($has_good_return) { + return RefundType::RETURN_AND_REFUND->value; + } + + // 买家未收到货 → 仅退款 + if ($good_status === 'BUYER_NOT_RECEIVED') { + return RefundType::REFUND_ONLY->value; + } + + // 买家已收货但无须退货 → 退款无须退货 + if ($good_status === 'BUYER_RECEIVED') { + return RefundType::REFUND_WITHOUT_RETURN->value; + } + + return RefundType::REFUND_ONLY->value; + } +}