有效天数问题,充值单回调问题
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||||
"github.com/break/junhong_cmp_fiber/internal/model/dto"
|
||||
asset "github.com/break/junhong_cmp_fiber/internal/service/asset"
|
||||
packagepkg "github.com/break/junhong_cmp_fiber/internal/service/package"
|
||||
"github.com/break/junhong_cmp_fiber/internal/service/packageprice"
|
||||
"github.com/break/junhong_cmp_fiber/internal/store"
|
||||
"github.com/break/junhong_cmp_fiber/internal/store/postgres"
|
||||
@@ -560,10 +561,7 @@ func buildClientPackageItem(
|
||||
return dto.ClientPackageItem{}, false
|
||||
}
|
||||
|
||||
validityDays := pkg.DurationDays
|
||||
if validityDays <= 0 && pkg.DurationMonths > 0 {
|
||||
validityDays = pkg.DurationMonths * 30
|
||||
}
|
||||
validityDays := packagepkg.CalculateValidityDays(pkg.CalendarType, time.Now(), pkg.DurationMonths, pkg.DurationDays)
|
||||
|
||||
dataAllowance := pkg.RealDataMB
|
||||
if dataAllowance <= 0 {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -16,6 +17,7 @@ import (
|
||||
"github.com/break/junhong_cmp_fiber/internal/store/postgres"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/fuiou"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/response"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/wechat"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
@@ -300,12 +302,13 @@ func (h *ClientWalletHandler) CreateRecharge(c *fiber.Ctx) error {
|
||||
rechargeNo := generateClientRechargeNo()
|
||||
paymentNo := generateClientPaymentNo()
|
||||
|
||||
// 先初始化微信支付实例并创建预支付订单,确认支付通道可用
|
||||
// 先初始化生效支付通道并创建预支付订单,确认支付通道可用
|
||||
// 避免先写入充值记录后支付初始化失败,导致产生孤儿记录
|
||||
payResult, err := h.createJSAPIPayOrder(
|
||||
payConfig, err := h.createClientRechargePayConfig(
|
||||
resolved.SkipPermissionCtx,
|
||||
config,
|
||||
appID,
|
||||
req.AppType,
|
||||
paymentNo,
|
||||
"资产钱包充值",
|
||||
openID,
|
||||
@@ -347,7 +350,6 @@ func (h *ClientWalletHandler) CreateRecharge(c *fiber.Ctx) error {
|
||||
return errors.Wrap(errors.CodeDatabaseError, err, "创建支付记录失败")
|
||||
}
|
||||
|
||||
payConfig := buildClientRechargePayConfig(appID, payResult)
|
||||
resp := &dto.ClientRechargeResponse{
|
||||
Recharge: dto.ClientRechargeResult{
|
||||
RechargeID: rechargeOrder.ID,
|
||||
@@ -607,33 +609,107 @@ func pickAppIDByType(config *model.WechatConfig, appType string) (string, error)
|
||||
}
|
||||
}
|
||||
|
||||
// createJSAPIPayOrder 根据支付配置的提供者类型路由到对应支付通道,发起 JSAPI 预下单。
|
||||
// 与 client_order.Service.newPaymentProvider 保持相同的路由逻辑,支持 wechat_v2 和 wechat(v3)。
|
||||
func (h *ClientWalletHandler) createJSAPIPayOrder(
|
||||
// createClientRechargePayConfig 根据当前生效支付配置创建充值预支付订单。
|
||||
// provider_type 必须显式匹配,避免富友等渠道误落到微信直连。
|
||||
func (h *ClientWalletHandler) createClientRechargePayConfig(
|
||||
ctx context.Context,
|
||||
config *model.WechatConfig,
|
||||
appID, orderNo, description, openID string,
|
||||
appID, appType, orderNo, description, openID string,
|
||||
amount int,
|
||||
) (*wechat.JSAPIPayResult, error) {
|
||||
) (dto.ClientRechargePayConfig, error) {
|
||||
switch config.ProviderType {
|
||||
case model.ProviderTypeWechatV2:
|
||||
// 微信 v2:仅需 APIv2Key,无需证书序列号
|
||||
svc, err := wechat.NewPaymentV2ServiceFromConfig(config, appID, h.logger)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errors.CodeWechatPayFailed, err, "初始化微信 v2 支付实例失败")
|
||||
return dto.ClientRechargePayConfig{}, errors.Wrap(errors.CodeWechatPayFailed, err, "初始化微信 v2 支付实例失败")
|
||||
}
|
||||
return svc.CreateJSAPIOrder(ctx, orderNo, description, openID, amount)
|
||||
default:
|
||||
result, err := svc.CreateJSAPIOrder(ctx, orderNo, description, openID, amount)
|
||||
if err != nil {
|
||||
return dto.ClientRechargePayConfig{}, err
|
||||
}
|
||||
return buildClientRechargePayConfig(appID, result), nil
|
||||
case model.ProviderTypeWechat:
|
||||
// 微信 v3(PowerWeChat):需要证书序列号和 API v3 Key
|
||||
cache := wechat.NewRedisCache(h.redis)
|
||||
paymentApp, err := wechat.NewPaymentAppFromConfig(config, appID, cache, h.logger)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errors.CodeWechatPayFailed, err, "初始化微信支付实例失败")
|
||||
return dto.ClientRechargePayConfig{}, errors.Wrap(errors.CodeWechatPayFailed, err, "初始化微信支付实例失败")
|
||||
}
|
||||
return wechat.NewPaymentService(paymentApp, h.logger).CreateJSAPIOrder(ctx, orderNo, description, openID, amount)
|
||||
result, err := wechat.NewPaymentService(paymentApp, h.logger).CreateJSAPIOrder(ctx, orderNo, description, openID, amount)
|
||||
if err != nil {
|
||||
return dto.ClientRechargePayConfig{}, err
|
||||
}
|
||||
return buildClientRechargePayConfig(appID, result), nil
|
||||
case model.ProviderTypeFuiou:
|
||||
return h.createFuiouRechargePayConfig(ctx, config, appID, appType, orderNo, description, openID, amount)
|
||||
default:
|
||||
return dto.ClientRechargePayConfig{}, errors.New(errors.CodeWechatConfigUnavailable, "不支持的支付渠道类型")
|
||||
}
|
||||
}
|
||||
|
||||
// createFuiouRechargePayConfig 使用富友支付配置创建充值预支付订单。
|
||||
func (h *ClientWalletHandler) createFuiouRechargePayConfig(
|
||||
ctx context.Context,
|
||||
config *model.WechatConfig,
|
||||
appID, appType, orderNo, description, openID string,
|
||||
amount int,
|
||||
) (dto.ClientRechargePayConfig, error) {
|
||||
if strings.TrimSpace(config.FyInsCd) == "" ||
|
||||
strings.TrimSpace(config.FyMchntCd) == "" ||
|
||||
strings.TrimSpace(config.FyTermID) == "" ||
|
||||
strings.TrimSpace(config.FyPrivateKey) == "" ||
|
||||
strings.TrimSpace(config.FyPublicKey) == "" ||
|
||||
strings.TrimSpace(config.FyAPIURL) == "" ||
|
||||
strings.TrimSpace(config.FyNotifyURL) == "" ||
|
||||
strings.TrimSpace(appID) == "" {
|
||||
return dto.ClientRechargePayConfig{}, errors.New(errors.CodeFuiouPayFailed, "富友支付配置不完整")
|
||||
}
|
||||
|
||||
client, err := fuiou.NewClient(
|
||||
config.FyInsCd,
|
||||
config.FyMchntCd,
|
||||
config.FyTermID,
|
||||
config.FyAPIURL,
|
||||
config.FyNotifyURL,
|
||||
config.FyPrivateKey,
|
||||
config.FyPublicKey,
|
||||
h.logger,
|
||||
)
|
||||
if err != nil {
|
||||
return dto.ClientRechargePayConfig{}, errors.Wrap(errors.CodeFuiouPayFailed, err, "创建富友支付客户端失败")
|
||||
}
|
||||
|
||||
tradeType := "JSAPI"
|
||||
if appType == "miniapp" {
|
||||
tradeType = "LETPAY"
|
||||
}
|
||||
|
||||
termIP := fuiou.GetServerIP()
|
||||
if ip, ok := ctx.Value(constants.ContextKeyIP).(string); ok && strings.TrimSpace(ip) != "" {
|
||||
termIP = ip
|
||||
}
|
||||
|
||||
resp, err := client.WxPreCreate(orderNo, strconv.Itoa(amount), description, termIP, tradeType, appID, openID)
|
||||
if err != nil {
|
||||
h.logger.Error("富友充值预下单失败",
|
||||
zap.String("payment_no", orderNo),
|
||||
zap.String("trade_type", tradeType),
|
||||
zap.Error(err),
|
||||
)
|
||||
return dto.ClientRechargePayConfig{}, errors.Wrap(errors.CodeFuiouPayFailed, err, "富友预下单失败")
|
||||
}
|
||||
|
||||
return dto.ClientRechargePayConfig{
|
||||
AppID: resp.SdkAppid,
|
||||
Timestamp: resp.SdkTimestamp,
|
||||
NonceStr: resp.SdkNoncestr,
|
||||
PackageVal: resp.SdkPackage,
|
||||
SignType: resp.SdkSigntype,
|
||||
PaySign: resp.SdkPaysign,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func generateClientRechargeNo() string {
|
||||
timestamp := time.Now().Format("20060102150405")
|
||||
randomNum := rand.Intn(1000000)
|
||||
|
||||
Reference in New Issue
Block a user