完善退款审批材料与恢复流程
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m35s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m35s
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-09-20
|
||||
@@ -0,0 +1,87 @@
|
||||
## Context
|
||||
|
||||
退款主表和每次不可变审批尝试已经保存 `method`、`customer_account_info` 与 `customer_voucher_keys`,但通用审批请求快照目前未写入这些键,企业微信退款场景白名单也没有对应字段。现有必需映射机制只支持场景级固定必需字段,无法表达“仅客户收款信息退款需要收款文本和凭证”。
|
||||
|
||||
通用审批提交已具备稳定事件键、企业微信提交状态、`sp_no`、结果未知恢复和 `last_recovery_at`,因此本变更只增加业务级恢复编排,不重建可靠提交基础设施。历史失败实例的关联审批尝试已经保存所需材料,可作为唯一补齐来源。
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
|
||||
- 让审批人始终明确看到退款方式,并仅在客户收款信息退款时看到完整收款文本和凭证。
|
||||
- 以单一规则来源表达退款场景的固定必需字段与按快照值生效的条件必需字段。
|
||||
- 让模板修复或提交异常后的退款恢复原审批实例,避免重复审批。
|
||||
- 在不改写历史材料的前提下补齐上线前失败实例缺少的快照键。
|
||||
|
||||
**Non-Goals:**
|
||||
|
||||
- 不把客户收款自由文本拆为收款人、账号、开户行等新 Schema,也不修改退款创建前端的数据结构。
|
||||
- 不要求原路退款或钱包退款配置客户收款控件,不向这些方式提交空白占位材料。
|
||||
- 不提供后台人工通过、驳回或强制重建审批,不改变渠道退款恢复。
|
||||
- 不新增数据库迁移或第三方依赖。
|
||||
|
||||
## Decisions
|
||||
|
||||
### 审批快照同时保存方式编码、名称和条件材料
|
||||
|
||||
新建、历史补发和重提路径生成的请求快照增加稳定键:退款方式编码、退款方式中文名称、客户收款信息和客户凭证列表。方式名称统一复用退款领域既有映射,避免表单层维护第二套名称。
|
||||
|
||||
方式编码用于条件规则判断,中文名称用于企微展示。客户字段即使在非客户收款方式下也以空值或空数组存在于新快照中,但表单不要求映射也不提交占位值。审批材料始终从当次审批尝试冻结值组装,而不是从退款主表临时读取。
|
||||
|
||||
备选是把方式和收款文本拼接成单一说明字段;放弃,因为附件仍需独立控件,且字段语义与错误定位不清晰。
|
||||
|
||||
### 必需字段规则扩展为固定与条件两类
|
||||
|
||||
企业微信业务字段规则保持单一注册来源:
|
||||
|
||||
- 固定必需:退款方式中文名称,保存场景映射和构建表单时均强制。
|
||||
- 条件必需:当快照方式编码为 `customer_account` 时,客户收款信息和客户凭证必须存在映射且值非空。
|
||||
|
||||
场景配置保存阶段只强制固定字段;条件字段若已映射则校验业务字段与控件类型。提交阶段读取请求快照,计算本次实际必需字段,再统一校验映射、快照键和值。错误明确指出具体字段和控件。其他退款方式不进入条件集合。
|
||||
|
||||
选择在表单构建层统一判定,而不是退款 Handler 或 Worker 分支判断,因为场景保存与提交必须共享字段定义,且其他审批场景未来可复用条件规则模型。
|
||||
|
||||
### 历史失败快照从不可变尝试受控补齐
|
||||
|
||||
恢复用例锁定退款、最新尝试、通用审批实例和企业微信上下文,并要求退款仍待审批、最新引用一致、尝试的 `approval_instance_id` 等于目标实例。
|
||||
|
||||
若请求快照缺少新增键,则从该尝试读取方式、客户收款信息和凭证,只添加缺失键,不覆盖任何已有值。退款方式中文名称由尝试冻结的方式编码确定。补齐后的请求快照更新与恢复提交事实在同一事务完成,并写入只记录字段名集合、不记录敏感值的审计。
|
||||
|
||||
不得从退款主表补齐:主表可能已被后续操作更新,只有审批尝试是该实例的不可变材料来源。
|
||||
|
||||
### 退款恢复入口编排既有审批恢复能力
|
||||
|
||||
新增 `POST /api/admin/refunds/{id}/recover-approval`,请求只携带路径 ID。权限沿用现有退款管理门禁和数据范围:超级管理员、平台用户及代理可在原范围内操作,企业账号拒绝,越权与不存在不可区分。
|
||||
|
||||
恢复顺序固定为:
|
||||
|
||||
1. 校验退款状态为待审批且最新尝试、实例一致。
|
||||
2. 必要时补齐历史请求快照。
|
||||
3. 已有 `sp_no` 时触发原审批详情查询。
|
||||
4. 提交结果未知时触发既有确认流程,禁止直接重提。
|
||||
5. 明确失败且确认未受理时恢复 `approval:{instance_id}:submission` 稳定事件。
|
||||
6. 活动重试或已在审批中时幂等返回。
|
||||
7. 审批终态、原路处理中或渠道失败时返回状态冲突。
|
||||
|
||||
HTTP 请求不直接调用企业微信创建审批接口,外部提交或查询继续由 Worker 执行,避免 HTTP 超时制造新的结果未知窗口。
|
||||
|
||||
### 查询投影复用既有审批与企微事实
|
||||
|
||||
退款列表和详情增加提交状态、状态名、可恢复标记、安全失败摘要和最近恢复时间。投影按页批量读取最新审批实例、企微上下文和提交事件,禁止逐条查询。最近恢复时间使用既有 `last_recovery_at`;人工恢复动作与操作者由审计表达,不新增业务列。
|
||||
|
||||
失败摘要仅使用脱敏的上下文 `last_error` 或稳定分类,不返回企业微信响应原文、完整客户收款信息、附件对象键或内部 Outbox 键。
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- [条件映射机制影响通用企微表单构建] → 保持默认规则为空,现有场景行为不变;只为退款注册条件规则并覆盖固定、条件和非条件三类 smoke。
|
||||
- [历史实例快照与尝试关联异常] → 关联不一致立即返回冲突,禁止猜测退款主表材料或恢复错误实例。
|
||||
- [模板只配置固定字段导致客户退款提交失败] → 这是有意的明确失败;错误指出缺少的客户收款字段,维护者补齐后恢复原实例。
|
||||
- [恢复与 Worker 正常重试竞争] → 通过实例锁和稳定事件条件更新收敛,活动事件只返回当前状态。
|
||||
- [列表联查增加成本] → 按页批量读取相关实例、上下文和事件,避免 N+1。
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. 不执行数据库迁移;先发布支持完整快照、条件字段规则、历史补齐和恢复入口的 API/Worker。
|
||||
2. 发布前由维护者在退款企微模板配置固定“退款方式”控件,并为客户收款退款配置“客户收款信息”多行文本与“客户收款凭证”附件控件。
|
||||
3. 在维护者指定测试环境分别提交四种退款方式,验证条件映射、明确失败和模板修复后原实例恢复。
|
||||
4. 回滚时关闭新恢复入口并回退二进制;已补齐的请求快照保留新增键,旧版本忽略未知键,不删除审批、退款或审计事实。
|
||||
@@ -0,0 +1,27 @@
|
||||
## Why
|
||||
|
||||
退款申请已经冻结退款方式、客户收款信息和客户凭证,但企业微信审批快照与可映射字段未包含这些材料,审批人无法判断具体退款路径,客户收款信息退款还可能因模板无字段可选而提交失败。模板或提交异常修复后也缺少业务级安全恢复入口,导致在途退款无法继续审批。
|
||||
|
||||
## What Changes
|
||||
|
||||
- 所有新建和重提退款审批材料新增退款方式,并按固定中文名称展示原路退款、客户收款信息退款、退回资产钱包或退回代理主钱包。
|
||||
- 仅客户收款信息退款在企业微信材料中提交多行客户收款信息与客户凭证附件;其他退款方式不要求或伪造收款材料。
|
||||
- 扩展企业微信退款场景字段白名单与表单构建规则:退款方式始终必须映射,客户收款信息和凭证按退款方式条件必需,缺失时明确指出需配置的控件。
|
||||
- 为提交失败、结果未知或已有企业微信审批单号但本地未确认的退款申请新增原审批恢复入口,复用最新审批尝试、原审批实例和稳定提交事实。
|
||||
- 对本变更上线前已失败且请求快照缺少新增材料的原审批实例,从其关联的不可变退款审批尝试补齐缺失键后恢复;不得从退款主表取值、覆盖已有快照或创建第二张审批单。
|
||||
- 退款列表与详情返回审批提交状态、可恢复标记、安全失败摘要和最近恢复时间。
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
无。
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
- `order-refund-exchange`: 补齐企业微信退款审批方式与条件收款材料,并增加原审批实例的受控恢复、状态展示和权限行为。
|
||||
|
||||
## Impact
|
||||
|
||||
- 影响退款审批快照构建、退款审批尝试读取、企业微信业务字段白名单、条件映射校验、表单构建、通用审批恢复接缝、退款查询投影、Handler、路由和 OpenAPI。
|
||||
- 复用现有退款审批尝试、通用审批实例、企业微信上下文、Outbox、Asynq 与审计事实;不新增第三方依赖或数据库迁移。
|
||||
@@ -0,0 +1,67 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: 企业微信退款审批展示方式与条件收款材料
|
||||
系统 SHALL 在每次新建或重提退款审批的不可变材料中保存并向企业微信展示退款方式,固定取值对应为:`original_route` 显示“原路退款”、`customer_account` 显示“客户收款信息退款”、`asset_wallet` 显示“退回资产钱包”、`agent_wallet` 显示“退回代理主钱包”。退款方式控件映射 MUST 为退款审批场景的固定必需配置,缺失时系统 MUST 明确拒绝保存场景或提交审批。
|
||||
|
||||
仅当退款方式为 `customer_account` 时,系统 MUST 向企业微信提交当次审批尝试冻结的客户收款信息多行文本和客户凭证附件,并 MUST 要求两类材料均非空且存在对应控件映射。其他退款方式 MUST NOT 要求客户收款信息或客户凭证控件,不得因这两个条件控件未映射而拒绝提交,也不得使用空白占位或其它退款资料伪造客户收款材料。
|
||||
|
||||
审批材料 MUST 取自当次不可变退款审批尝试,不得因退款主表后续修改或新一次重提而改变历史审批实例的材料。缺少当前退款方式所需的映射或材料时,错误 MUST 指出缺失的具体业务字段或控件。
|
||||
|
||||
#### Scenario: 客户收款信息退款提交完整材料
|
||||
- **GIVEN** 退款方式为客户收款信息退款,且当次尝试冻结了非空客户收款信息和至少一个客户凭证
|
||||
- **WHEN** 系统构建企业微信退款审批表单
|
||||
- **THEN** 表单展示“客户收款信息退款”、完整多行客户收款信息和客户凭证附件
|
||||
|
||||
#### Scenario: 客户收款信息退款缺少条件控件
|
||||
- **WHEN** 客户收款信息退款对应场景缺少客户收款信息或客户凭证控件映射
|
||||
- **THEN** 系统明确拒绝提交并指出缺失控件,不静默丢弃材料且不创建第二张审批单
|
||||
|
||||
#### Scenario: 原路退款不要求客户收款控件
|
||||
- **WHEN** 退款方式为原路退款且场景未配置客户收款信息与客户凭证控件
|
||||
- **THEN** 系统仍可提交审批,表单明确展示“原路退款”且不提交伪造的客户收款材料
|
||||
|
||||
#### Scenario: 钱包退款展示具体方式
|
||||
- **WHEN** 退款方式为资产钱包或代理主钱包退款
|
||||
- **THEN** 企业微信材料分别展示“退回资产钱包”或“退回代理主钱包”,且不要求客户收款材料
|
||||
|
||||
#### Scenario: 重提不改写历史审批材料
|
||||
- **GIVEN** 同一退款申请以不同材料重提并产生新的审批尝试
|
||||
- **WHEN** 查询或同步任一历史审批实例
|
||||
- **THEN** 每个实例仍使用其关联尝试冻结的退款方式、客户收款信息与客户凭证,不被最新退款主表或后续尝试覆盖
|
||||
|
||||
### Requirement: 退款原审批实例可受控恢复
|
||||
系统 SHALL 提供 `POST /api/admin/refunds/{id}/recover-approval`,允许具有既有退款管理访问权限的超级管理员、平台用户和代理在其数据范围内恢复仍处于待审批的退款申请。恢复对象 MUST 固定为退款申请最新审批尝试与最新审批实例,不接受调用方传入审批实例或新材料;企业账号 MUST 被拒绝,无权操作与退款不存在 MUST 不可区分。
|
||||
|
||||
恢复 MUST 复用原审批实例和同一稳定提交事实,不得新增审批尝试、审批实例或第二张企业微信审批单,不得修改退款方式、金额、客户收款信息、凭证或其它冻结材料,也不得改变退款业务状态、套餐权益、订单状态或触发渠道退款。明确提交失败且可确认企业微信未受理时,系统 SHALL 恢复同一提交事实;提交结果未知时 MUST 优先确认原提交结果;已有企业微信审批单号时 MUST 查询同步原审批单;正常重试或已经处于企业微信审批中的请求 SHALL 幂等返回当前状态;审批终态、原路退款处理中或渠道退款失败状态 MUST 拒绝审批提交恢复。
|
||||
|
||||
对本能力上线前已创建、原请求快照缺少退款方式或条件收款材料的待恢复实例,系统 SHALL 仅从该实例关联的不可变退款审批尝试补齐缺失键。补齐 MUST 校验尝试与审批实例关联一致,只添加缺失键且不得覆盖已有快照,不得从退款主表取值;快照补齐与提交恢复 MUST 原子完成。
|
||||
|
||||
退款列表与详情 SHALL 返回审批提交状态、可恢复标记、安全失败摘要和最近恢复时间。恢复与历史快照补齐 MUST 写入脱敏审计,不得记录完整客户收款信息、附件对象键、企业微信原始响应或内部队列键。
|
||||
|
||||
#### Scenario: 模板修复后恢复原审批
|
||||
- **GIVEN** 待审批退款因模板字段缺失而明确提交失败,且维护者已修复映射
|
||||
- **WHEN** 授权账号请求恢复审批
|
||||
- **THEN** 系统恢复同一审批实例与稳定提交事实,不新增审批尝试或审批单,并保持退款材料和业务状态不变
|
||||
|
||||
#### Scenario: 历史失败实例补齐原尝试材料
|
||||
- **GIVEN** 原审批实例的请求快照缺少新增字段,但其关联退款审批尝试已冻结退款方式和客户收款材料
|
||||
- **WHEN** 授权账号恢复该审批
|
||||
- **THEN** 系统从关联尝试补齐缺失键并恢复原实例,不覆盖已有快照且不从退款主表读取材料
|
||||
|
||||
#### Scenario: 提交结果未知时禁止重提
|
||||
- **GIVEN** 最新退款审批实例的提交结果未知
|
||||
- **WHEN** 授权账号请求恢复
|
||||
- **THEN** 系统进入原提交结果确认流程,在无法证明未受理前不再次创建审批
|
||||
|
||||
#### Scenario: 已有企微审批单号时只查询同步
|
||||
- **GIVEN** 最新审批实例已有企业微信审批单号但本地状态未确认
|
||||
- **WHEN** 授权账号请求恢复
|
||||
- **THEN** 系统查询同步原审批单,不恢复创建提交且不生成新实例
|
||||
|
||||
#### Scenario: 重复和并发恢复保持幂等
|
||||
- **WHEN** 多个授权账号重复或并发恢复同一退款审批
|
||||
- **THEN** 系统至多一次改变原提交事实,其余请求返回相同当前状态,审批尝试数和审批实例数不增加
|
||||
|
||||
#### Scenario: 非审批提交阶段拒绝恢复
|
||||
- **WHEN** 退款审批已终态,或退款已进入原路退款处理中或渠道退款失败状态
|
||||
- **THEN** 系统返回状态冲突,不改变退款、订单、权益、审批或渠道退款事实
|
||||
@@ -0,0 +1,34 @@
|
||||
## 1. 退款审批材料快照
|
||||
|
||||
- [x] 1.1 新增稳定审批业务字段编码:退款方式编码、退款方式中文名称、客户收款信息和客户凭证,并登记到退款企微场景字段白名单及正确控件类型。
|
||||
- [x] 1.2 扩展新建、历史补发与重提的退款审批快照,从当次不可变审批尝试写入方式编码、统一中文名称、客户收款文本和凭证列表;非客户收款方式写空条件值但不伪造材料。
|
||||
- [x] 1.3 核对退款方式名称只复用既有领域映射,历史审批实例仍读取各自请求快照,不因退款主表或后续重提变化。
|
||||
|
||||
## 2. 企业微信条件映射规则
|
||||
|
||||
- [x] 2.1 将企微必需字段规则扩展为固定必需与按请求快照生效的条件必需两类,默认不改变其它审批场景行为。
|
||||
- [x] 2.2 配置保存时固定强制退款方式映射,并对已配置的客户收款信息多行文本与客户凭证附件映射校验控件类型。
|
||||
- [x] 2.3 表单构建时按退款方式编码计算本次必需字段:`customer_account` 强制客户收款文本与凭证映射和值,其他方式不要求;缺失时返回指出具体字段和控件的错误。
|
||||
- [x] 2.4 确认原路退款、资产钱包退款和代理钱包退款在未配置客户收款控件时仍可提交,且企微材料明确展示对应退款方式。
|
||||
|
||||
## 3. 历史快照补齐与审批恢复
|
||||
|
||||
- [x] 3.1 在通用审批 Application/Infrastructure 边界提供按原实例查询同步、确认结果未知和恢复稳定提交事件的接缝,复用 `approval:{instance_id}:submission`,活动事件幂等返回。
|
||||
- [x] 3.2 实现退款历史快照受控补齐:锁定退款、最新尝试和原实例,校验关联一致,只从不可变尝试添加缺失的新键,不覆盖已有快照、不读取退款主表,并写脱敏审计。
|
||||
- [x] 3.3 实现退款恢复用例:仅待审批且最新尝试、实例一致时允许;已有 `sp_no` 只查询,结果未知只确认,明确未受理失败恢复原事件,正常重试返回当前状态。
|
||||
- [x] 3.4 保证重复或并发恢复至多一次改变提交事实;恢复不新增尝试或实例,不修改退款材料和状态,不触发套餐、订单、资金或渠道退款动作。
|
||||
|
||||
## 4. 查询投影与 HTTP 入口
|
||||
|
||||
- [x] 4.1 扩展退款列表与详情 DTO,返回审批提交状态、状态名、可恢复标记、安全失败摘要和最近恢复时间。
|
||||
- [x] 4.2 在退款 Query 中按页批量读取最新审批实例、企微上下文和提交事件计算恢复投影,避免逐条查询;敏感收款信息、附件键、企微原文和内部事件键不得进入失败摘要。
|
||||
- [x] 4.3 新增 `POST /api/admin/refunds/{id}/recover-approval` Handler 与 RouteSpec,只接受路径退款 ID;同步可执行路由、`cmd/api/docs.go`、`cmd/gendocs/main.go` 和 OpenAPI 生成要求。
|
||||
- [x] 4.4 复用退款管理权限和数据范围:超级管理员、平台用户与代理仅操作原可见退款,企业账号拒绝,越权与不存在不可区分;审批终态、原路处理中和渠道失败返回状态冲突。
|
||||
|
||||
## 5. 验证、配置与规格同步
|
||||
|
||||
- [ ] 5.1 在维护者指定测试环境分别提交四种退款方式,核对企微材料中的中文方式;客户收款退款包含多行文本和附件,其他方式不要求客户收款控件。
|
||||
- [ ] 5.2 验证客户收款退款缺文本、凭证、映射或控件时明确失败;修复模板后从原尝试补齐历史快照并恢复同一审批实例。
|
||||
- [ ] 5.3 验证结果未知、已有 `sp_no`、正常重试、重复与并发恢复,以及终态、渠道阶段和越权拒绝;核对尝试数、实例数、退款材料、订单、权益和资金事实不变。
|
||||
- [x] 5.4 核对列表与详情投影、批量查询和审计脱敏,运行 `gofmt -w`、`go build ./cmd/api ./cmd/worker`、`go run cmd/gendocs/main.go`。
|
||||
- [x] 5.5 更新退款企微模板上线前置说明、主 Spec 可达操作索引和证据矩阵,运行 `openspec validate complete-refund-approval-materials-and-recovery --strict`、`openspec doctor --json`、`openspec validate --all` 与 `./scripts/context-health.sh`。
|
||||
@@ -428,6 +428,16 @@
|
||||
- **WHEN** 提交退款审批
|
||||
- **THEN** 系统明确失败并指出缺失控件,不静默丢弃该字段
|
||||
|
||||
### Requirement: 退款原审批实例可受控恢复
|
||||
|
||||
系统 SHALL 提供 `POST /api/admin/refunds/{id}/recover-approval`,允许既有退款管理范围内的超级管理员、平台用户和代理恢复仍处于待审批的退款最新审批实例;企业账号拒绝,越权与不存在不可区分。恢复 MUST 复用原审批实例及 `approval:{instance_id}:submission` 稳定提交事实,不得新增审批尝试/实例、修改冻结退款材料或触发退款、订单、套餐与资金动作。已有 `sp_no` 只查询同步,结果未知只确认,明确提交失败且无 `sp_no` 才恢复原提交事件;审批终态、原路退款处理中或渠道退款失败 MUST 返回状态冲突。历史快照缺失新增键时,只能从关联不可变审批尝试补齐缺失值并写脱敏审计。
|
||||
|
||||
#### Scenario: 恢复入口只处理原审批事实
|
||||
|
||||
- **WHEN** 授权账号请求恢复待审批退款
|
||||
- **THEN** 系统按最新尝试与实例关联选择恢复分支,列表/详情返回提交状态、可恢复标记、安全失败摘要和最近恢复时间,重复或并发请求至多一次改变提交事实。
|
||||
|
||||
|
||||
## 可达操作索引
|
||||
|
||||
本节只用于入口导航,不是行为 Requirement;业务义务以上述 Requirements 为准。
|
||||
@@ -438,7 +448,7 @@
|
||||
|
||||
### 退款管理
|
||||
|
||||
`GET /api/admin/refunds`(退款申请列表);`POST /api/admin/refunds`(创建退款申请);`GET /api/admin/refunds/{id}`(退款申请详情);`POST /api/admin/refunds/{id}/trigger-approval`(补发历史退款审批);`POST /api/admin/refunds/{id}/approve`(审批通过退款申请);`POST /api/admin/refunds/{id}/reject`(审批拒绝退款申请);`POST /api/admin/refunds/{id}/resubmit`(重新提交退款申请);`POST /api/admin/refunds/{id}/return`(退回退款申请);`GET /api/admin/refunds/order-options`(按来源订单查询可选退款方式);`POST /api/admin/refunds/{id}/offline-settlement`(登记或更正线下退款处理流水号)。
|
||||
`GET /api/admin/refunds`(退款申请列表,返回审批提交状态、状态名、可恢复标记、安全失败摘要和最近恢复时间);`POST /api/admin/refunds`(创建退款申请);`GET /api/admin/refunds/{id}`(退款申请详情,返回同一审批恢复投影);`POST /api/admin/refunds/{id}/trigger-approval`(补发历史退款审批);`POST /api/admin/refunds/{id}/recover-approval`(恢复最新退款审批原提交:已有 `sp_no` 查询同步、结果未知确认、明确失败且无 `sp_no` 恢复稳定 submission Outbox);`POST /api/admin/refunds/{id}/approve`(审批通过退款申请);`POST /api/admin/refunds/{id}/reject`(审批拒绝退款申请);`POST /api/admin/refunds/{id}/resubmit`(重新提交退款申请);`POST /api/admin/refunds/{id}/return`(退回退款申请);`GET /api/admin/refunds/order-options`(按来源订单查询可选退款方式);`POST /api/admin/refunds/{id}/offline-settlement`(登记或更正线下退款处理流水号)。
|
||||
|
||||
### 换货管理
|
||||
|
||||
|
||||
Reference in New Issue
Block a user