Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Has been cancelled
- H5 下单带 app_type 且选微信、商户为微信直连时,复用套餐购买的 JSAPI 预下单,返回 pay_config - 调起参数保存在支付单,延期订单详情可继续支付;查单、回调、超时关单、作废沿用原流程 - 后台生成二维码、支付宝、富友商户保持原方式
65 lines
3.0 KiB
Go
65 lines
3.0 KiB
Go
package packagesilence
|
||
|
||
import (
|
||
"context"
|
||
"encoding/json"
|
||
"strings"
|
||
|
||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||
"github.com/break/junhong_cmp_fiber/internal/model/dto"
|
||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||
)
|
||
|
||
// jsapiContentPrefix 标记支付单 qr_content 里保存的是微信 JSAPI 调起参数(JSON),而不是二维码 / 支付链接。
|
||
const jsapiContentPrefix = "jsapi:"
|
||
|
||
// JSAPIPayer 为 C 端客户按已冻结商户创建微信 JSAPI 预下单(复用套餐购买的公众号 / 小程序支付)。
|
||
type JSAPIPayer interface {
|
||
CreateJSAPIPayConfig(ctx context.Context, customerID uint, appType string, config *model.WechatConfig,
|
||
paymentNo, description string, amount int64) (*dto.ClientPayConfig, error)
|
||
}
|
||
|
||
// SetJSAPIPayer 注入微信 JSAPI 预下单能力;未注入时 H5 微信延期仍走 H5 支付链接。
|
||
func (s *ExtensionService) SetJSAPIPayer(payer JSAPIPayer) { s.jsapi = payer }
|
||
|
||
// useJSAPI 判断本次下单是否走微信内直接支付:H5 客户、微信支付、带应用类型、商户为微信直连(v3 / v2)。
|
||
// 富友商户仍走扫码,避免查单与下单协议不一致。
|
||
func (s *ExtensionService) useJSAPI(source string, req dto.SilenceOnlineOrderRequest, config *model.WechatConfig) bool {
|
||
return s.jsapi != nil && source == constants.SilenceOrderSourceClient && req.PaymentMethod == model.PaymentByWechat &&
|
||
strings.TrimSpace(req.AppType) != "" && config != nil &&
|
||
(config.ProviderType == model.ProviderTypeWechat || config.ProviderType == model.ProviderTypeWechatV2)
|
||
}
|
||
|
||
// createJSAPIContent 预下单并把调起参数编码成支付单内容,便于"继续支付"复用(预支付有效期 2 小时,长于支付截止)。
|
||
func (s *ExtensionService) createJSAPIContent(ctx context.Context, customerID uint, appType string, config *model.WechatConfig, payment *model.Payment) (string, error) {
|
||
payConfig, err := s.jsapi.CreateJSAPIPayConfig(ctx, customerID, appType, config, payment.PaymentNo, "沉默期延期", payment.Amount)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
if payConfig == nil || strings.TrimSpace(payConfig.PackageVal) == "" {
|
||
return "", errors.New(errors.CodeWechatPayFailed, "微信支付未返回调起参数")
|
||
}
|
||
raw, err := json.Marshal(payConfig)
|
||
if err != nil {
|
||
return "", errors.Wrap(errors.CodeInternalError, err, "编码微信支付参数失败")
|
||
}
|
||
return jsapiContentPrefix + string(raw), nil
|
||
}
|
||
|
||
// ApplyPaymentContent 把支付单内容写到响应:JSAPI 参数放 pay_config,其余(二维码 / 支付链接)放 qr_content。
|
||
func ApplyPaymentContent(resp *dto.SilenceExtensionOrderResponse, content string) {
|
||
if resp == nil || content == "" {
|
||
return
|
||
}
|
||
if strings.HasPrefix(content, jsapiContentPrefix) {
|
||
var payConfig dto.ClientPayConfig
|
||
if err := json.Unmarshal([]byte(strings.TrimPrefix(content, jsapiContentPrefix)), &payConfig); err == nil {
|
||
resp.PayConfig = &payConfig
|
||
resp.QRContent = ""
|
||
}
|
||
return
|
||
}
|
||
resp.QRContent = content
|
||
}
|