This commit is contained in:
@@ -648,7 +648,7 @@ func (h *AssetHandler) resolveAssetPackageUsagePath(c *fiber.Ctx) (*dto.AssetRes
|
||||
}
|
||||
|
||||
func ensureAssetPackageAdjuster(c *fiber.Ctx) error {
|
||||
if middleware.GetUserIDFromContext(c.UserContext()) != 41 && middleware.GetUserIDFromContext(c.UserContext()) != 127 {
|
||||
if middleware.GetUserIDFromContext(c.UserContext()) != 1124 && middleware.GetUserIDFromContext(c.UserContext()) != 127 {
|
||||
return errors.New(errors.CodeForbidden, "无权限操作该资源或资源不存在")
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -23,13 +23,24 @@ func requirePaymentMerchantAccess(handler fiber.Handler) fiber.Handler {
|
||||
}
|
||||
}
|
||||
|
||||
// paymentMerchantCredentialDoc 说明商户 credentials 允许的键,与 validateMerchantConfiguration 的校验口径一致。
|
||||
// credentials 是 JSONB,生成的 OpenAPI 只能给它一个通用 object 模式,因此键枚举写进操作说明供前端枚举。
|
||||
const paymentMerchantCredentialDoc = `商户凭证 credentials 为扁平 JSON 对象,键名与渠道配置字段一致;必填键由 payment_method 与 provider_type 组合决定:
|
||||
- payment_method=wechat、provider_type=wechat:wx_mch_id、wx_api_v3_key、wx_cert_content、wx_key_content、wx_serial_no、wx_notify_url
|
||||
- payment_method=wechat、provider_type=wechat_v2:wx_mch_id、wx_api_v2_key、wx_notify_url
|
||||
- payment_method=wechat、provider_type=fuiou:fy_mchnt_cd、fy_ins_cd、fy_term_id、fy_private_key、fy_public_key、fy_api_url、fy_notify_url
|
||||
- payment_method=alipay、provider_type=alipay:ali_app_id、ali_private_key、ali_public_key、ali_notify_url、ali_return_url
|
||||
可选键:微信商户可附 wx_api_v2_key;支付宝商户可附 ali_production(布尔,是否生产环境)与 ali_pay_expire_minutes(整数,支付过期分钟数)。
|
||||
除 ali_production 与 ali_pay_expire_minutes 外,凭证值必须为字符串;merchant_identity 必须分别等于 wx_mch_id、fy_mchnt_cd 或 ali_app_id。
|
||||
商户凭证为敏感信息,仅超级管理员与平台用户可读可写,日志、审计与支付快照不保存凭证内容。`
|
||||
|
||||
func registerPaymentMerchantRoutes(router fiber.Router, handler *admin.PaymentMerchantHandler, doc *openapi.Generator, basePath string) {
|
||||
group := router
|
||||
wrap := requirePaymentMerchantAccess
|
||||
Register(group, doc, basePath, "GET", "/payment-merchants", wrap(handler.ListMerchants), RouteSpec{Summary: "查询支付商户", Description: "仅超级管理员和平台用户可访问。", Tags: []string{"支付商户管理"}, Input: new(dto.PaymentMerchantListRequest), Output: new(dto.PaymentMerchantResponse), Auth: true})
|
||||
Register(group, doc, basePath, "POST", "/payment-merchants", wrap(handler.CreateMerchant), RouteSpec{Summary: "创建支付商户", Description: "仅超级管理员和平台用户可访问。", Tags: []string{"支付商户管理"}, Input: new(dto.PaymentMerchantRequest), Output: new(dto.PaymentMerchantResponse), Auth: true})
|
||||
Register(group, doc, basePath, "GET", "/payment-merchants/:id", wrap(handler.GetMerchant), RouteSpec{Summary: "查询支付商户详情", Description: "仅超级管理员和平台用户可访问。", Tags: []string{"支付商户管理"}, Input: new(dto.IDReq), Output: new(dto.PaymentMerchantResponse), Auth: true})
|
||||
Register(group, doc, basePath, "PUT", "/payment-merchants/:id", wrap(handler.UpdateMerchant), RouteSpec{Summary: "更新支付商户", Description: "仅超级管理员和平台用户可访问。", Tags: []string{"支付商户管理"}, Input: new(dto.IDReq), Body: new(dto.PaymentMerchantUpdateRequest), Output: new(dto.PaymentMerchantResponse), Auth: true})
|
||||
Register(group, doc, basePath, "POST", "/payment-merchants", wrap(handler.CreateMerchant), RouteSpec{Summary: "创建支付商户", Description: "仅超级管理员和平台用户可访问。\n\n" + paymentMerchantCredentialDoc, Tags: []string{"支付商户管理"}, Input: new(dto.PaymentMerchantRequest), Output: new(dto.PaymentMerchantResponse), Auth: true})
|
||||
Register(group, doc, basePath, "GET", "/payment-merchants/:id", wrap(handler.GetMerchant), RouteSpec{Summary: "查询支付商户详情", Description: "仅超级管理员和平台用户可访问。\n\n" + paymentMerchantCredentialDoc, Tags: []string{"支付商户管理"}, Input: new(dto.IDReq), Output: new(dto.PaymentMerchantResponse), Auth: true})
|
||||
Register(group, doc, basePath, "PUT", "/payment-merchants/:id", wrap(handler.UpdateMerchant), RouteSpec{Summary: "更新支付商户", Description: "仅超级管理员和平台用户可访问。\n\n" + paymentMerchantCredentialDoc, Tags: []string{"支付商户管理"}, Input: new(dto.IDReq), Body: new(dto.PaymentMerchantUpdateRequest), Output: new(dto.PaymentMerchantResponse), Auth: true})
|
||||
Register(group, doc, basePath, "DELETE", "/payment-merchants/:id", wrap(handler.DeleteMerchant), RouteSpec{Summary: "删除支付商户", Description: "仅超级管理员和平台用户可访问。", Tags: []string{"支付商户管理"}, Input: new(dto.IDReq), Body: new(dto.PaymentMerchantDeleteRequest), Output: nil, Auth: true})
|
||||
Register(group, doc, basePath, "GET", "/payment-merchant-pools", wrap(handler.ListPools), RouteSpec{Summary: "查询商户池", Description: "仅超级管理员和平台用户可访问。支持分页,返回当前页商户池及其有序成员。", Tags: []string{"商户池管理"}, Input: new(dto.PaymentMerchantPoolListRequest), Output: new(dto.PaymentMerchantPoolResponse), Auth: true})
|
||||
Register(group, doc, basePath, "GET", "/payment-merchant-pools/:id", wrap(handler.GetPool), RouteSpec{Summary: "查询商户池详情", Description: "仅超级管理员和平台用户可访问。", Tags: []string{"商户池管理"}, Input: new(dto.IDReq), Output: new(dto.PaymentMerchantPoolResponse), Auth: true})
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
## Requirements
|
||||
|
||||
### Requirement: 商户与微信授权配置管理
|
||||
系统 SHALL 将实际收款商户与微信授权配置分离。一个商户 MUST 仅对应 `wechat` 或 `alipay` 一种支付方式,并保存名称、支付方式、服务商类型、商户号或应用标识、敏感凭证、状态和备注;微信直连与富友均为微信支付商户。平台最多存在一个启用的微信授权配置,该配置保存 C 端公众号 H5/JSSDK、小程序登录所需参数,C 端微信登录、OpenID 和微信支付 AppID MUST 只读取该配置。
|
||||
系统 SHALL 将实际收款商户与微信授权配置分离。一个商户 MUST 仅对应 `wechat` 或 `alipay` 一种支付方式,并保存名称、支付方式、服务商类型、商户号或应用标识、敏感凭证、状态和备注;微信直连与富友均为微信支付商户。创建或更新商户时 `credentials` MUST 为扁平 JSON 对象,必填键由支付方式与服务商类型组合确定:`wechat/wechat` 为 `wx_mch_id`、`wx_api_v3_key`、`wx_cert_content`、`wx_key_content`、`wx_serial_no`、`wx_notify_url`;`wechat/wechat_v2` 为 `wx_mch_id`、`wx_api_v2_key`、`wx_notify_url`;`wechat/fuiou` 为 `fy_mchnt_cd`、`fy_ins_cd`、`fy_term_id`、`fy_private_key`、`fy_public_key`、`fy_api_url`、`fy_notify_url`;`alipay/alipay` 为 `ali_app_id`、`ali_private_key`、`ali_public_key`、`ali_notify_url`、`ali_return_url`。凭证值 MUST 为字符串,仅可选的 `ali_production`(布尔)与 `ali_pay_expire_minutes`(整数)例外;`merchant_identity` MUST 分别等于 `wx_mch_id`、`fy_mchnt_cd` 或 `ali_app_id`。平台最多存在一个启用的微信授权配置,该配置保存 C 端公众号 H5/JSSDK、小程序登录所需参数,C 端微信登录、OpenID 和微信支付 AppID MUST 只读取该配置。
|
||||
|
||||
超级管理员和平台用户可创建、编辑、启用、停用商户、商户池和微信授权配置,其他角色无管理入口。仅上述角色的专用管理列表和详情响应可返回完整凭证;日志、审计快照、错误、导出、支付快照和其他业务响应 MUST NOT 保存或返回敏感凭证。被支付单引用的商户 MUST NOT 删除且其支付方式、服务商类型、商户号/应用标识不得修改;未被引用商户仅可移出所有商户池并经二次确认删除。停用只影响新支付单,历史支付的回调、查单和已有可达的原路退款仍使用该商户当前凭证;服务商无既有退款能力时保持不支持,本能力不得为此新增渠道退款调用或人工开关。
|
||||
|
||||
@@ -24,6 +24,10 @@
|
||||
- **WHEN** 更新提交后创建支付、处理回调、查单或原路退款
|
||||
- **THEN** 系统只使用更新后的当前有效凭证,不得继续使用更新前的缓存凭证
|
||||
|
||||
#### Scenario: 凭证键不完整或身份不一致被拒
|
||||
- **WHEN** 管理员创建或更新商户时提交缺少该支付方式与服务商类型必填键的 `credentials`,或 `merchant_identity` 与凭证中的商户号或应用标识不一致
|
||||
- **THEN** 系统拒绝写入并返回参数错误,不创建或修改商户记录
|
||||
|
||||
### Requirement: 商户池唯一性与轮询配置
|
||||
系统 SHALL 为每种支付方式最多启用一个商户池;停用历史池可保留,但不得同时启用多个同支付方式池。商户池成员支付方式 MUST 与池一致,成员按明确顺序排列;金额/笔数方式必须配置 `每轮累计`、`自然日累计` 或 `自然月累计` 统计周期,时间方式必须配置最小为 1 分钟的数值、单位和起始时间。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user