同步历史版本代码
This commit is contained in:
@@ -3,7 +3,10 @@ package portal
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/perfect-panel/server/internal/model/log"
|
||||
@@ -26,6 +29,7 @@ import (
|
||||
"github.com/perfect-panel/server/pkg/payment/alipay"
|
||||
"github.com/perfect-panel/server/pkg/payment/epay"
|
||||
"github.com/perfect-panel/server/pkg/payment/stripe"
|
||||
"github.com/perfect-panel/server/pkg/tool"
|
||||
"github.com/perfect-panel/server/pkg/xerr"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@@ -73,6 +77,13 @@ func (l *PurchaseCheckoutLogic) PurchaseCheckout(req *types.CheckoutOrderRequest
|
||||
}
|
||||
// Route to appropriate payment handler based on payment platform
|
||||
switch paymentPlatform.ParsePlatform(orderInfo.Method) {
|
||||
case paymentPlatform.AppleIAP:
|
||||
productId := fmt.Sprintf("merchant.hifastvpn.day%d", orderInfo.Quantity)
|
||||
resp = &types.CheckoutOrderResponse{
|
||||
Type: "apple_iap",
|
||||
ProductIds: []string{productId},
|
||||
}
|
||||
return resp, nil
|
||||
case paymentPlatform.EPay:
|
||||
// Process EPay payment - generates payment URL for redirect
|
||||
url, err := l.epayPayment(paymentConfig, orderInfo, req.ReturnUrl)
|
||||
@@ -186,13 +197,20 @@ func (l *PurchaseCheckoutLogic) alipayF2fPayment(pay *payment.Payment, info *ord
|
||||
l.Errorw("[PurchaseCheckout] queryExchangeRate error", logger.Field("error", err.Error()))
|
||||
return "", errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "queryExchangeRate error: %s", err.Error())
|
||||
}
|
||||
convertAmount := int64(amount * 100) // Convert to cents for API
|
||||
convertAmount := int64(math.Round(amount * 100))
|
||||
l.Infow("alipay amount",
|
||||
logger.Field("src_cents", info.Amount),
|
||||
logger.Field("decimal", amount),
|
||||
logger.Field("cents", convertAmount),
|
||||
)
|
||||
|
||||
// Create pre-payment trade and generate QR code
|
||||
QRCode, err := client.PreCreateTrade(l.ctx, alipay.Order{
|
||||
o := alipay.Order{
|
||||
OrderNo: info.OrderNo,
|
||||
Amount: convertAmount,
|
||||
})
|
||||
}
|
||||
l.Infow("alipay request", logger.Field("order", o))
|
||||
QRCode, err := client.PreCreateTrade(l.ctx, o)
|
||||
if err != nil {
|
||||
l.Errorw("[PurchaseCheckout] PreCreateTrade error", logger.Field("error", err.Error()))
|
||||
return "", errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "PreCreateTrade error: %s", err.Error())
|
||||
@@ -218,25 +236,50 @@ func (l *PurchaseCheckoutLogic) stripePayment(config string, info *order.Order,
|
||||
WebhookSecret: stripeConfig.WebhookSecret,
|
||||
})
|
||||
|
||||
// Convert order amount to CNY using current exchange rate
|
||||
amount, err := l.queryExchangeRate("CNY", info.Amount)
|
||||
currency := "USD"
|
||||
sysCurrency, _ := l.svcCtx.SystemModel.GetCurrencyConfig(l.ctx)
|
||||
if sysCurrency != nil {
|
||||
configs := struct {
|
||||
CurrencyUnit string
|
||||
CurrencySymbol string
|
||||
AccessKey string
|
||||
}{}
|
||||
tool.SystemConfigSliceReflectToStruct(sysCurrency, &configs)
|
||||
if configs.CurrencyUnit != "" {
|
||||
currency = configs.CurrencyUnit
|
||||
}
|
||||
}
|
||||
|
||||
// Convert order amount to configured currency using current exchange rate
|
||||
amount, err := l.queryExchangeRate(strings.ToUpper(currency), info.Amount)
|
||||
if err != nil {
|
||||
l.Errorw("[PurchaseCheckout] queryExchangeRate error", logger.Field("error", err.Error()))
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "queryExchangeRate error: %s", err.Error())
|
||||
}
|
||||
convertAmount := int64(amount * 100) // Convert to cents for Stripe API
|
||||
convertAmount := int64(math.Round(amount * 100))
|
||||
l.Infow("stripe amount",
|
||||
logger.Field("src_cents", info.Amount),
|
||||
logger.Field("decimal", amount),
|
||||
logger.Field("cents", convertAmount),
|
||||
logger.Field("currency", currency),
|
||||
)
|
||||
|
||||
// Create Stripe payment sheet for client-side processing
|
||||
result, err := client.CreatePaymentSheet(&stripe.Order{
|
||||
// Map apple_pay to card for Stripe API, but keep apple_pay in config/response
|
||||
paymentMethod := stripeConfig.Payment
|
||||
if paymentMethod == "apple_pay" {
|
||||
paymentMethod = "card"
|
||||
}
|
||||
ord := &stripe.Order{
|
||||
OrderNo: info.OrderNo,
|
||||
Subscribe: strconv.FormatInt(info.SubscribeId, 10),
|
||||
Amount: convertAmount,
|
||||
Currency: "cny",
|
||||
Payment: stripeConfig.Payment,
|
||||
},
|
||||
&stripe.User{
|
||||
Email: identifier,
|
||||
})
|
||||
Currency: strings.ToLower(currency),
|
||||
Payment: paymentMethod,
|
||||
}
|
||||
usr := &stripe.User{Email: identifier}
|
||||
l.Infow("stripe request", logger.Field("order", ord), logger.Field("user", usr))
|
||||
result, err := client.CreatePaymentSheet(ord, usr)
|
||||
if err != nil {
|
||||
l.Errorw("[PurchaseCheckout] CreatePaymentSheet error", logger.Field("error", err.Error()))
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "CreatePaymentSheet error: %s", err.Error())
|
||||
@@ -282,6 +325,11 @@ func (l *PurchaseCheckoutLogic) epayPayment(config *payment.Payment, info *order
|
||||
} else {
|
||||
amount = float64(info.Amount) / float64(100)
|
||||
}
|
||||
amount = math.Round(amount*100) / 100
|
||||
l.Infow("epay amount",
|
||||
logger.Field("src_cents", info.Amount),
|
||||
logger.Field("decimal", amount),
|
||||
)
|
||||
|
||||
// gateway mod
|
||||
isGatewayMod := report.IsGatewayMode()
|
||||
@@ -342,6 +390,11 @@ func (l *PurchaseCheckoutLogic) CryptoSaaSPayment(config *payment.Payment, info
|
||||
} else {
|
||||
amount = float64(info.Amount) / float64(100)
|
||||
}
|
||||
amount = math.Round(amount*100) / 100
|
||||
l.Infow("crypto amount",
|
||||
logger.Field("src_cents", info.Amount),
|
||||
logger.Field("decimal", amount),
|
||||
)
|
||||
|
||||
// gateway mod
|
||||
isGatewayMod := report.IsGatewayMode()
|
||||
@@ -395,18 +448,53 @@ func (l *PurchaseCheckoutLogic) queryExchangeRate(to string, src int64) (amount
|
||||
return amount, nil
|
||||
}
|
||||
|
||||
// Retrieve system currency configuration from DB for FixedRate fallback
|
||||
currency, dbErr := l.svcCtx.SystemModel.GetCurrencyConfig(l.ctx)
|
||||
var fixedRate string
|
||||
if dbErr == nil && currency != nil {
|
||||
configs := struct {
|
||||
CurrencyUnit string
|
||||
CurrencySymbol string
|
||||
AccessKey string
|
||||
FixedRate string
|
||||
}{}
|
||||
tool.SystemConfigSliceReflectToStruct(currency, &configs)
|
||||
fixedRate = strings.TrimSpace(configs.FixedRate)
|
||||
}
|
||||
|
||||
// Skip conversion if no exchange rate API key configured
|
||||
if l.svcCtx.Config.Currency.AccessKey == "" {
|
||||
if to == "CNY" && strings.TrimSpace(l.svcCtx.Config.Currency.Unit) == "USD" && fixedRate != "" {
|
||||
r := tool.FormatStringToFloat(fixedRate)
|
||||
if r > 0 {
|
||||
l.Infow("exchangeRate.fixed", logger.Field("rate", r))
|
||||
return amount * r, nil
|
||||
}
|
||||
}
|
||||
l.Infof("[PurchaseCheckout] AccessKey is empty, skip conversion")
|
||||
return amount, nil
|
||||
}
|
||||
|
||||
// Convert currency if system currency differs from target currency
|
||||
result, err := exchangeRate.GetExchangeRete(l.svcCtx.Config.Currency.Unit, to, l.svcCtx.Config.Currency.AccessKey, 1)
|
||||
if err != nil {
|
||||
l.Logger.Error("[PurchaseCheckout] QueryExchangeRate error", logger.Field("error", err.Error()))
|
||||
return 0, err
|
||||
if to == "CNY" && strings.TrimSpace(l.svcCtx.Config.Currency.Unit) == "USD" && fixedRate != "" {
|
||||
r := tool.FormatStringToFloat(fixedRate)
|
||||
if r > 0 {
|
||||
l.Infow("exchangeRate.fixed.fallback", logger.Field("rate", r), logger.Field("error", err.Error()))
|
||||
return amount * r, nil
|
||||
}
|
||||
}
|
||||
// fallback: try without access key
|
||||
result2, err2 := exchangeRate.GetExchangeRete(l.svcCtx.Config.Currency.Unit, to, "", 1)
|
||||
if err2 != nil {
|
||||
l.Logger.Error("[PurchaseCheckout] QueryExchangeRate error", logger.Field("error", err.Error()))
|
||||
return 0, err
|
||||
}
|
||||
result = result2
|
||||
}
|
||||
l.svcCtx.ExchangeRate = result
|
||||
l.Infow("exchangeRate", logger.Field("from", l.svcCtx.Config.Currency.Unit), logger.Field("to", to), logger.Field("rate", result))
|
||||
return result * amount, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user