# 需求09:C端支付方式限制配置化 > 状态:原需求独立稿;最终口径以标准评审稿为准。 > 依赖:[系统配置](../基础规范/系统配置.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`。 > 注意:**微信支付参数申请下来后**,直接在系统配置里把对应资产类型勾上微信即可生效,无需改代码。