Files
uniprop-manual/prop-acc/scenarios/adhoc/exception-wechat-callback-delay.md

199 lines
7.0 KiB
Markdown
Raw Permalink Normal View History

2026-05-25 13:54:35 +08:00
---
title: prop-acc · adhoc · 场景 - 异常 - 微信支付回调延迟
P3+P4+P5: prop-acc 迁移到多域 UDAS,新建 4 域骨架与顶层入口 P3 — prop-acc 30 文件迁移到多域 UDAS 结构: - 3 概念:旧 prop-acc/一次性收费/概念-*.md → prop-acc/concepts/adhoc-*.md (kebab-case 英文) - 25 场景:旧 prop-acc/一次性收费/场景-*.md → prop-acc/scenarios/adhoc-*.md - 子文件夹 index.md → prop-acc/maps/knowledge-map.md (域内地图) - prop-acc/index.md 重写为域首页(embed knowledge-map) - 删除空目录 prop-acc/一次性收费/ 每个迁移文件: - title 加域前缀 "prop-acc · " - aliases 含原 title (带空格) + 原文件名 basename (无空格),保证既有 [[...]] 引用解析 - status: stable → 已发布 / draft → 草稿 (UDAS 中文枚举) - last_reviewed → last_review (UDAS 字段名) - tags 补加 UDAS 类型分类 "概念" / "场景" - 路径式 WikiLink 清除: * [[../预存款/index|XX]] → [[预存款]] * [[一次性收费/index|XX]] → [[prop-acc · 一次性收费索引]] P4 — 4 个新业务域骨架: - community (社区管理) - administrative (行政人事) - patrol (巡护工单) - resident-portal (业户门户) 每域含 index.md (域首页) + maps/knowledge-map.md (域内地图模板)。 另补 cross/index.md + cross/maps/cross-domain-map.md。 P5 — 顶层入口: - index.md: 站点首页 (Quartz 着陆点),embed domain-map - maps/domain-map.md: 5 业务域 + cross 的索引表 迁移后状态: - 共 50 篇 .md (30 原 + 8 跨域 stub + 4 域 index + 4 域 map + 2 cross + 2 root) - 残留路径式 WikiLink: 0 - 残留英文 status: 0 - 残留 last_reviewed 字段: 0 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 20:44:43 +08:00
aliases:
- prop-acc · 场景 - 异常 - 微信支付回调延迟
P3+P4+P5: prop-acc 迁移到多域 UDAS,新建 4 域骨架与顶层入口 P3 — prop-acc 30 文件迁移到多域 UDAS 结构: - 3 概念:旧 prop-acc/一次性收费/概念-*.md → prop-acc/concepts/adhoc-*.md (kebab-case 英文) - 25 场景:旧 prop-acc/一次性收费/场景-*.md → prop-acc/scenarios/adhoc-*.md - 子文件夹 index.md → prop-acc/maps/knowledge-map.md (域内地图) - prop-acc/index.md 重写为域首页(embed knowledge-map) - 删除空目录 prop-acc/一次性收费/ 每个迁移文件: - title 加域前缀 "prop-acc · " - aliases 含原 title (带空格) + 原文件名 basename (无空格),保证既有 [[...]] 引用解析 - status: stable → 已发布 / draft → 草稿 (UDAS 中文枚举) - last_reviewed → last_review (UDAS 字段名) - tags 补加 UDAS 类型分类 "概念" / "场景" - 路径式 WikiLink 清除: * [[../预存款/index|XX]] → [[预存款]] * [[一次性收费/index|XX]] → [[prop-acc · 一次性收费索引]] P4 — 4 个新业务域骨架: - community (社区管理) - administrative (行政人事) - patrol (巡护工单) - resident-portal (业户门户) 每域含 index.md (域首页) + maps/knowledge-map.md (域内地图模板)。 另补 cross/index.md + cross/maps/cross-domain-map.md。 P5 — 顶层入口: - index.md: 站点首页 (Quartz 着陆点),embed domain-map - maps/domain-map.md: 5 业务域 + cross 的索引表 迁移后状态: - 共 50 篇 .md (30 原 + 8 跨域 stub + 4 域 index + 4 域 map + 2 cross + 2 root) - 残留路径式 WikiLink: 0 - 残留英文 status: 0 - 残留 last_reviewed 字段: 0 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 20:44:43 +08:00
- 场景 - 异常 - 微信支付回调延迟
- 场景-异常-微信支付回调延迟
2026-05-25 13:54:35 +08:00
tags:
P3+P4+P5: prop-acc 迁移到多域 UDAS,新建 4 域骨架与顶层入口 P3 — prop-acc 30 文件迁移到多域 UDAS 结构: - 3 概念:旧 prop-acc/一次性收费/概念-*.md → prop-acc/concepts/adhoc-*.md (kebab-case 英文) - 25 场景:旧 prop-acc/一次性收费/场景-*.md → prop-acc/scenarios/adhoc-*.md - 子文件夹 index.md → prop-acc/maps/knowledge-map.md (域内地图) - prop-acc/index.md 重写为域首页(embed knowledge-map) - 删除空目录 prop-acc/一次性收费/ 每个迁移文件: - title 加域前缀 "prop-acc · " - aliases 含原 title (带空格) + 原文件名 basename (无空格),保证既有 [[...]] 引用解析 - status: stable → 已发布 / draft → 草稿 (UDAS 中文枚举) - last_reviewed → last_review (UDAS 字段名) - tags 补加 UDAS 类型分类 "概念" / "场景" - 路径式 WikiLink 清除: * [[../预存款/index|XX]] → [[预存款]] * [[一次性收费/index|XX]] → [[prop-acc · 一次性收费索引]] P4 — 4 个新业务域骨架: - community (社区管理) - administrative (行政人事) - patrol (巡护工单) - resident-portal (业户门户) 每域含 index.md (域首页) + maps/knowledge-map.md (域内地图模板)。 另补 cross/index.md + cross/maps/cross-domain-map.md。 P5 — 顶层入口: - index.md: 站点首页 (Quartz 着陆点),embed domain-map - maps/domain-map.md: 5 业务域 + cross 的索引表 迁移后状态: - 共 50 篇 .md (30 原 + 8 跨域 stub + 4 域 index + 4 域 map + 2 cross + 2 root) - 残留路径式 WikiLink: 0 - 残留英文 status: 0 - 残留 last_reviewed 字段: 0 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 20:44:43 +08:00
- 场景
2026-05-25 13:54:35 +08:00
- prop-acc
- 一次性收费
- 业务场景
- 异常故障
audience:
- 业户
- 业务人员
P3+P4+P5: prop-acc 迁移到多域 UDAS,新建 4 域骨架与顶层入口 P3 — prop-acc 30 文件迁移到多域 UDAS 结构: - 3 概念:旧 prop-acc/一次性收费/概念-*.md → prop-acc/concepts/adhoc-*.md (kebab-case 英文) - 25 场景:旧 prop-acc/一次性收费/场景-*.md → prop-acc/scenarios/adhoc-*.md - 子文件夹 index.md → prop-acc/maps/knowledge-map.md (域内地图) - prop-acc/index.md 重写为域首页(embed knowledge-map) - 删除空目录 prop-acc/一次性收费/ 每个迁移文件: - title 加域前缀 "prop-acc · " - aliases 含原 title (带空格) + 原文件名 basename (无空格),保证既有 [[...]] 引用解析 - status: stable → 已发布 / draft → 草稿 (UDAS 中文枚举) - last_reviewed → last_review (UDAS 字段名) - tags 补加 UDAS 类型分类 "概念" / "场景" - 路径式 WikiLink 清除: * [[../预存款/index|XX]] → [[预存款]] * [[一次性收费/index|XX]] → [[prop-acc · 一次性收费索引]] P4 — 4 个新业务域骨架: - community (社区管理) - administrative (行政人事) - patrol (巡护工单) - resident-portal (业户门户) 每域含 index.md (域首页) + maps/knowledge-map.md (域内地图模板)。 另补 cross/index.md + cross/maps/cross-domain-map.md。 P5 — 顶层入口: - index.md: 站点首页 (Quartz 着陆点),embed domain-map - maps/domain-map.md: 5 业务域 + cross 的索引表 迁移后状态: - 共 50 篇 .md (30 原 + 8 跨域 stub + 4 域 index + 4 域 map + 2 cross + 2 root) - 残留路径式 WikiLink: 0 - 残留英文 status: 0 - 残留 last_reviewed 字段: 0 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 20:44:43 +08:00
status: 已发布
sub_feature: adhoc
P3+P4+P5: prop-acc 迁移到多域 UDAS,新建 4 域骨架与顶层入口 P3 — prop-acc 30 文件迁移到多域 UDAS 结构: - 3 概念:旧 prop-acc/一次性收费/概念-*.md → prop-acc/concepts/adhoc-*.md (kebab-case 英文) - 25 场景:旧 prop-acc/一次性收费/场景-*.md → prop-acc/scenarios/adhoc-*.md - 子文件夹 index.md → prop-acc/maps/knowledge-map.md (域内地图) - prop-acc/index.md 重写为域首页(embed knowledge-map) - 删除空目录 prop-acc/一次性收费/ 每个迁移文件: - title 加域前缀 "prop-acc · " - aliases 含原 title (带空格) + 原文件名 basename (无空格),保证既有 [[...]] 引用解析 - status: stable → 已发布 / draft → 草稿 (UDAS 中文枚举) - last_reviewed → last_review (UDAS 字段名) - tags 补加 UDAS 类型分类 "概念" / "场景" - 路径式 WikiLink 清除: * [[../预存款/index|XX]] → [[预存款]] * [[一次性收费/index|XX]] → [[prop-acc · 一次性收费索引]] P4 — 4 个新业务域骨架: - community (社区管理) - administrative (行政人事) - patrol (巡护工单) - resident-portal (业户门户) 每域含 index.md (域首页) + maps/knowledge-map.md (域内地图模板)。 另补 cross/index.md + cross/maps/cross-domain-map.md。 P5 — 顶层入口: - index.md: 站点首页 (Quartz 着陆点),embed domain-map - maps/domain-map.md: 5 业务域 + cross 的索引表 迁移后状态: - 共 50 篇 .md (30 原 + 8 跨域 stub + 4 域 index + 4 域 map + 2 cross + 2 root) - 残留路径式 WikiLink: 0 - 残留英文 status: 0 - 残留 last_reviewed 字段: 0 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 20:44:43 +08:00
last_review: 2026-05-25
2026-05-25 13:54:35 +08:00
code_version: 2026-05-22
---
# 场景:微信支付回调延迟
业户**在微信里付款成功**,但**系统订单还停在 Pending 状态**。等几分钟才更新,业户和业务人员都可能误以为出问题了。
## 典型情境
> [!example] 真实情境
> 周日晚上李太太在小程序下单充电桩电费 ¥200,微信支付成功 —— 微信弹窗"已付款"、扣款记录里也看到了。
>
> 但她切回小程序"我的订单",订单状态还是"待付款"。等了 1 分钟没变化,她以为没成功,**又点了一次"立即支付"**。
>
> 微信弹"您已支付过该订单,无需重复支付",这才放心。3 分钟后小程序终于刷新为"已完成"。
## 为什么会延迟?
> [!info] 微信回调链路
> 业户支付 → 微信服务器 → 物业服务器 webhook → 系统更新订单状态。
>
> 任何一步**网络慢、服务器忙、回调队列堆积**,都可能让"系统知道你付款了"晚几秒到几分钟。**99% 的回调在 10 秒内到达**,**1% 可能要 30 秒~5 分钟**,极少数(0.01%)**完全丢失**。
## 业户视角
### 您可能看到的几种状态
| 时间 | 微信侧 | 小程序订单状态 | 您的感觉 |
|---|---|---|---|
| 0-3 秒 | 支付完成 | 仍然显示"待付款" | 正常,刷新一下 |
| 3-30 秒 | 支付完成 | 已变"已完成" | 完美 |
| 30 秒-5 分钟 | 支付完成 | 仍然"待付款" | 怀疑没成功 |
| > 5 分钟 | 支付完成 | 一直"待付款" | 真的有问题 |
### 您应该怎么办
> [!warning] 不要重复支付!
> 微信有重复支付防护(同一订单只能付一次),但万一系统出问题,**重复支付的钱可能很难退**。
**正确步骤**:
1. 看微信"账单 / 钱包"里是否有这笔扣款记录
- ✅ 有 → **钱已经付了**,不要再付
- ❌ 无 → 钱没出去,可以放心重新支付
2. 钱已付但小程序不更新:
- 等 5 分钟
- 下拉刷新小程序订单页
- 还不更新 → 联系物业前台
3. 联系物业前台:
- 告诉他们订单号 + 微信扣款截图
- 物业能在 Filament 后台**手动核实并标记完成**
### 别担心,钱不会丢
> [!success] 双向保障
> - 微信侧:确认扣款,有微信账单为证
> - 物业侧:即使回调彻底丢失,微信商户后台**能看到这笔交易**,物业人工核对后手动入账
## 业务人员视角
### 业户来问"我付了但显示没付"怎么处理?
```
1. 让业户出示微信扣款记录(截图 / 商家订单号)
2. Filament 后台搜业户订单号(CO-xxx)
├── 状态显示 Pending → 回调真的没到
└── 状态已是 Completed → 回调刚到,提示业户刷新页面
3. 状态 Pending 且业户确认已付:
├── 在微信商户后台查这笔交易
│ └── 找到 transaction_id (微信侧订单号)
├── 与系统 CO-xxx 的 order_no 核对
└── 如确认是同一笔:手动标记完成
```
### 手动标记完成
> [!warning] 当前 UI 没有直接的"标记完成"按钮
> 当前只能通过 `MarkAdHocEventPaidAction` 业务方法调用。临时方案:
> - 走 Tinker:`app(MarkAdHocEventPaidAction::class)->handle($event, [...])`
> - 或者在 Filament 后台为业户**重新建一笔**(走 A 流即收即付),把原 Pending 单走作废
>
> 长期方案:**给 ViewAdHocEvent 加一个"手动标记已付款"Action**,挂 TODO。
### 后台技术细节
```mermaid
sequenceDiagram
participant 业户
participant 微信
participant 微信服务器
participant 物业 webhook
participant 系统
participant 业务人员
业户->>微信: 付款 ¥200
微信->>业户: 弹窗"已付款"
微信->>微信服务器: 入账
Note over 微信服务器: 网络/服务器繁忙
微信服务器-->>物业 webhook: ⏳ 延迟 30s ~ 5min ⏳
Note over 业户: 业户看小程序仍显示待付款
业户->>业务人员: 询问"我付了为什么还是待付款"
业务人员->>微信商户后台: 查 transaction_id
业务人员->>系统: 手动 MarkAsPaid
系统->>系统: CollectionOrder + AdHocEvent → Completed
系统-->>业户: 推通知"已付款"
Note over 微信服务器: 几分钟后,延迟回调终于到了
微信服务器->>物业 webhook: 现在才到
物业 webhook->>系统: 检查订单已 Completed → 跳过 (幂等)
```
## 几个关键设计决策
### 1. 回调幂等
> [!info] 系统设计
> webhook 处理时**先查订单状态**:
> - 若是 Pending → 走 MarkAdHocEventPaidAction 完成流程
> - 若已是 Completed → 直接返回成功,不做任何事
> - 若是 Voided → 退回退款流程(钱原路退回业户)
>
> 这样**不论回调到达多少次**,系统都保持一致状态。
### 2. 业户重复支付的处理
如果业户没看到状态更新而**重复点了"立即支付"**:
- 微信端会拦截(同一订单只能付一次)
- 系统侧**不会收到第二笔扣款**
但万一某些渠道允许重复支付(罕见):
- 系统会收到**两笔 transaction_id 不同的回调**
- 第一笔正常处理 → 翻 Completed
- 第二笔到达时 → 系统发现订单已 Completed,**直接对第二笔发起原路退款**
### 3. 超时 vs 回调延迟的竞争
> [!warning] 一个微妙的边界情况
> 业户付款的瞬间正好是订单 expires_at,超时 job 同时跑:
>
> - 超时 job 拿到锁先把订单 → Voided
> - 微信回调晚 1 秒到 → 看到 Voided,触发**原路退款**(钱退回业户)
>
> 业户此时看到"扣款 + 几小时后退款"。这是正常容错行为,不是 bug。
## 常见问题
> [!question] 业户已经离开了,但延迟回调到了,会怎样?
> 系统正常翻 Completed,生成 Receipt。业户**下次打开小程序**就能看到状态更新和收据。无需联系物业。
> [!question] 5 分钟还没到回调,但业户急着要 IC 卡怎么办?
> 走业务人员的"手动标记完成"路径(见上)。**信任微信侧扣款记录优先**。
> [!question] 同一笔订单回调收到 2 次怎么办?
> 幂等设计 → 第二次直接返回成功。详见上述设计决策 1。
> [!question] 物业怎么知道是不是真的"回调丢了"?
> 监控 + 报警:
> - 每天对账微信商户后台 vs 系统订单总数
> - 差额 > 阈值(比如 5 笔)发警报
> - 人工补单(查商户后台 → 手动标记)
## 相关概念
- [[概念-CollectionOrder与Receipt]] — Pending → Completed 流转
- [[概念-AdHocEvent状态机]]
- [[场景-B流-小程序下单+微信支付]] — 正向流程
- [[场景-超时未付自动作废]] — 时间竞争场景
## 异常分支
- 业户付了款但物业拒绝处理 → 走 [[场景-已收款作废]] 退款给业户
- 回调收到但金额对不上 → 数据问题,技术介入