Files
junhong_cmp_fiber/docs/7月迭代/独立方案/原需求/需求09-C端支付限制配置化.md
2026-07-17 16:39:41 +08:00

147 lines
5.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 需求09C端支付方式限制配置化
> 状态:原需求独立稿;最终口径以标准评审稿为准。
> 依赖:[系统配置](../基础规范/系统配置.md)
---
## 背景
代码已经写好但被注释,注释原因是**微信支付参数未申请下来**,临时注释。
注释位置:
- `internal/handler/app/client_wallet.go`(钱包充值入口)
- `internal/service/client_order/service.go`(订单支付入口)
两处均有注释:`// 第三方支付方式与资产类型必须匹配:单卡只允许支付宝,设备只允许微信(已暂时注释)`
---
## 业务规则
| 资产类型 | 允许的第三方支付 | 禁止的第三方支付 |
|---------|----------------|----------------|
| IoT 卡 | 支付宝、钱包 | 微信 |
| 设备 | 微信、钱包 | 支付宝 |
**钱包支付对所有资产类型均允许。**
```mermaid
flowchart TD
Pay[用户选择支付方式] --> Asset{资产类型}
Asset -->|IoT卡| Card[读取卡允许方式]
Asset -->|设备| Device[读取设备允许方式]
Asset -->|未知| RejectUnknown[拒绝:资产类型无效]
Card --> ConfigOK{配置可用?}
Device --> ConfigOK
ConfigOK -->|是| Match{支付方式在允许集合?}
ConfigOK -->|否| SafeDefault[使用代码内安全默认集合]
SafeDefault --> Match
Match -->|是| Continue[继续支付]
Match -->|否| Reject[拒绝并返回对应中文提示]
```
---
## 实现方案
### 1. 系统配置初始化(已在系统配置文档中定义)
```go
// tb_system_config 初始数据
config_key: "c2b.payment.card_allowed_methods" ["alipay","wallet"]
config_key: "c2b.payment.device_allowed_methods" ["wechat","wallet"]
```
### 2. 恢复注释代码,改为读取配置
**文件**`internal/service/client_order/service.go`
```go
// validatePaymentMethod 校验资产类型与支付方式是否匹配
func (s *Service) validatePaymentMethod(ctx context.Context, assetType string, paymentMethod string) error {
// 钱包支付始终允许
if paymentMethod == model.PaymentMethodWallet {
return nil
}
var configKey string
switch assetType {
case model.AssetTypeIotCard: // "iot_card",定义在 internal/model/asset_identifier.go
configKey = "c2b.payment.card_allowed_methods"
case model.AssetTypeDevice: // "device",定义在 internal/model/asset_identifier.go
configKey = "c2b.payment.device_allowed_methods"
default:
return errors.New(errors.CodeInvalidParam, "资产类型无效")
}
allowedMethods, err := sysconfig.GetStringSlice(ctx, configKey)
if err != nil || len(allowedMethods) == 0 {
// 配置异常时回退到代码内安全默认值,禁止放开全部支付方式。
allowedMethods = defaultAllowedMethods(assetType)
s.logger.Error("读取支付方式配置失败,已使用安全默认值",
zap.String("config_key", configKey),
zap.Error(err))
}
for _, m := range allowedMethods {
if m == paymentMethod {
return nil
}
}
return errors.New(errors.CodeForbidden, "该资产类型不支持此支付方式")
}
```
`client_wallet.go`(充值)和 `client_order/service.go`(订单支付)的对应位置恢复调用。
系统配置更新时必须保证 `wallet` 始终存在于两个允许集合中;前端将钱包选项显示为勾选且不可取消,后端再次校验,避免配置破坏业务规则。
### 3. 错误信息
用户端错误提示(友好文案):
```go
// 根据资产类型给出具体提示
switch assetType {
case model.AssetTypeIotCard:
return errors.New(errors.CodeForbidden, "卡资产仅支持支付宝或余额支付")
case model.AssetTypeDevice:
return errors.New(errors.CodeForbidden, "设备仅支持微信或余额支付")
}
```
---
## 前端对接
### C端支付页面
前端不维护另一份固定规则。资产初始化/详情接口返回后端已经计算好的:
```go
AllowedPaymentMethods []string `json:"allowed_payment_methods" description:"当前资产允许的支付方式"`
```
支付页只展示该集合中的方式,后端支付接口再次执行相同校验。配置变化后重新进入支付页或刷新资产信息即可获得新集合。
```
allowed_payment_methods = ["alipay", "wallet"] → 展示支付宝、余额
allowed_payment_methods = ["wechat", "wallet"] → 展示微信、余额
```
### 后台配置页面
在系统配置(系统设置 > 系统配置 > `c2b.payment` 模块)中,用 CheckboxGroup 展示:
```
卡资产允许支付方式:☑ 支付宝 ☑ 余额 ☐ 微信
设备允许支付方式: ☐ 支付宝 ☑ 余额 ☑ 微信
```
余额选项固定勾选且禁用,不允许管理员取消。
修改后调用 `PUT /api/admin/system/config/c2b.payment.card_allowed_methods`
> 注意:**微信支付参数申请下来后**,直接在系统配置里把对应资产类型勾上微信即可生效,无需改代码。