From a9ec179ead40f5c5b247c077991bad03032fbab4 Mon Sep 17 00:00:00 2001 From: Nick Zeng Date: Wed, 4 Mar 2026 14:29:25 +0800 Subject: [PATCH] update refund parse --- backend/app/Platform/RefundConsumer.php | 26 ++++++++++++++++--- .../app/Platform/Tmall/EntityParse/Refund.php | 17 ++++++++---- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/backend/app/Platform/RefundConsumer.php b/backend/app/Platform/RefundConsumer.php index 5ddb85d..dc8628b 100644 --- a/backend/app/Platform/RefundConsumer.php +++ b/backend/app/Platform/RefundConsumer.php @@ -85,17 +85,19 @@ class RefundConsumer extends ConsumerMessage $raw_data = $data['data'] ?? []; $entity_map_result = $parse->entityMap($raw_data); + $data_to_upsert = $entity_map_result->all(); + $platform_refund_id_to_local_refund_id_map = null; // 退款信息为空且有父退款,直接返回 ACK - if (empty($data_to_upsert) && $parse->hasParentRefund) { + if (empty($data_to_upsert) && $parse->hasParentRefund()) { dump('No data to process'); return Result::ACK; } // 无父级退款,直接使用平台售后单的情况, 比如 Tmall - if(!$parse->hasParentRefund){ + if(!$parse->hasParentRefund()){ goto PROCESS_REFUND_ITEMS; } @@ -127,7 +129,15 @@ class RefundConsumer extends ConsumerMessage ->pluck('id', 'platform_refund_id') ->toArray(); - dump("ID mapping: " . count($platform_refund_id_to_local_refund_id_map) . " refunds"); + if ($parse->hasParentRefund() && empty($platform_refund_id_to_local_refund_id_map)) { + Log::get()->warning('Refund ID mapping is empty after upsert, refund_items.refund_id will not be populated', [ + 'store_id' => $parse->getStore()->id, + 'platform' => $parse->getPlatform()->name ?? '', + ]); + } + + + // @TODO refund type 也需要进一步确定 app/Constants/RefundType.php // @attention 没有父退款的平台,业务直接跳到此处执行 @@ -139,10 +149,20 @@ class RefundConsumer extends ConsumerMessage // 4. 处理退款子项 $this->processRefundItems($items); + // 5. Tmall 闪电退款订单重建(从退款数据恢复缺失的 Order/OrderItem) + // @TODO 添加平台检查,而不仅限于 Tmall, 其他平台可能存在类似情况 + if (method_exists($parse, 'fixInstantRefundOrders')) { + $parse->fixInstantRefundOrders($raw_data); + } + Db::commit(); return Result::ACK; } catch (Throwable $error) { + + dump($error->getMessage()); + dump($error->getTraceAsString()); + Log::get()->error('Refund consumer processing failed', [ 'error' => $error->getMessage(), 'retry_count' => $retry_count, diff --git a/backend/app/Platform/Tmall/EntityParse/Refund.php b/backend/app/Platform/Tmall/EntityParse/Refund.php index ab9dbe5..cd0c034 100644 --- a/backend/app/Platform/Tmall/EntityParse/Refund.php +++ b/backend/app/Platform/Tmall/EntityParse/Refund.php @@ -150,12 +150,18 @@ class Refund extends EntityParse $tz = $this->getStore()->getTimezoneString(); $raw = \json_encode($record); - // 闪电退款优先使用 INSTANT_REFUND_WITHOUT_RETURN 类型 + // 闪电退款: 覆盖退款类型 + 预填订单日期(闪电退款无原始订单,fillOrderDates 查不到) $refund_type_id = $this->getRefundTypeId($record); + $instant_refund_order_date = null; if (isset($record['attribute']) && $record['attribute'] !== '') { $attr = $this->parseRefundItemAttribute($record['attribute']); if (!empty($attr) && $attr['clj_zero_second_refund']) { $refund_type_id = RefundType::INSTANT_REFUND_WITHOUT_RETURN->value; + // bgmtc 是「退款后台创建时间」,并非真实订单创建时间。 + // 闪电退款场景下 Tmall 不推送原始订单,bgmtc 是我们能获取到的最接近订单创建时间的时间戳(误差在秒~分钟级别), + // 用作 order_created_date / order_paid_date 的近似值。 + $date_str = $attr['bgmtc'] ?? $record['created']; + $instant_refund_order_date = Carbon::parse($date_str, $tz)->format('Y-m-d H:i:sP'); } } @@ -176,8 +182,8 @@ class Refund extends EntityParse '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' => null, // @attention 暂时设置为 null, 后续会批量更新 - 'order_paid_date' => null, // @attention 暂时设置为 null, 后续会批量更新 + 'order_created_date' => $instant_refund_order_date, // 闪电退款用 bgmtc 预填,普通退款由 fillOrderDates 回填 + 'order_paid_date' => $instant_refund_order_date, '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, @@ -424,7 +430,8 @@ class Refund extends EntityParse $refund_ids[] = strval($record['refund_id']); $buyer_user_id = $record['buyer_open_uid'] ?? $buyer_user_id; - // bgmtc(后台创建时间)优先,否则使用退款创建时间 + // bgmtc 是「退款后台创建时间」,非真实订单创建时间, + // 但闪电退款场景下是最接近订单创建时间的近似值(误差秒~分钟级)。 if ($created_date === null) { $date_str = $attr['bgmtc'] ?? $record['created']; $created_date = Carbon::parse($date_str, $tz)->format('Y-m-d H:i:sP'); @@ -719,7 +726,7 @@ class Refund extends EntityParse 'channel_sub_order_id' => $pairs['chnlObn'] ?? null, // 渠道子订单编号 'last_order' => (bool) ($pairs['lastOrder'] ?? 0), // 是否最后一笔子单 'b2c' => (bool) ($pairs['b2c'] ?? 0), // 是否B2C - 'bgmtc' => $pairs['bgmtc'] ?? null, // 退款后台创建时间 + 'bgmtc' => $pairs['bgmtc'] ?? null, // 退款后台创建时间(非订单创建时间,闪电退款场景用作订单时间近似值) ]; }