sync: bring over remaining release/custom-0.1.115 changes
- Extract PublicSettingsInjectionPayload named struct with drift test - Add channel_monitor_default_interval_seconds to SSR injection - Add image_output_price to SupportedModelChip - Simplify AppSidebar buildSelfNavItems (admins see available channels) - Add gateway WARN logs for 503 no-available-accounts branches - Wire ChannelMonitorRunner into provideCleanup for graceful shutdown - Add migrations 130/131 (CC template userid fix + mimicry field cleanup) - Clean up fork-only features (sora, claude max simulation, client affinity) - Remove ~320 obsolete i18n keys - Add codexUsage utility, WechatServiceButton, BulkEditAccountModal - Tidy go.sum
This commit is contained in:
@@ -15,9 +15,8 @@ import (
|
||||
|
||||
// Alipay product codes.
|
||||
const (
|
||||
alipayProductCodePreCreate = "FACE_TO_FACE_PAYMENT"
|
||||
alipayProductCodeWapPay = "QUICK_WAP_WAY"
|
||||
alipayProductCodePagePay = "FAST_INSTANT_TRADE_PAY"
|
||||
alipayProductCodeWapPay = "QUICK_WAP_WAY"
|
||||
alipayProductCodePagePay = "FAST_INSTANT_TRADE_PAY"
|
||||
)
|
||||
|
||||
// Alipay response constants.
|
||||
@@ -31,9 +30,6 @@ var (
|
||||
alipayTradeWapPay = func(client *alipay.Client, param alipay.TradeWapPay) (*url.URL, error) {
|
||||
return client.TradeWapPay(param)
|
||||
}
|
||||
alipayTradePreCreate = func(ctx context.Context, client *alipay.Client, param alipay.TradePreCreate) (*alipay.TradePreCreateRsp, error) {
|
||||
return client.TradePreCreate(ctx, param)
|
||||
}
|
||||
alipayTradePagePay = func(client *alipay.Client, param alipay.TradePagePay) (*url.URL, error) {
|
||||
return client.TradePagePay(param)
|
||||
}
|
||||
@@ -103,13 +99,13 @@ func (a *Alipay) MerchantIdentityMetadata() map[string]string {
|
||||
return map[string]string{"app_id": appID}
|
||||
}
|
||||
|
||||
// CreatePayment creates an Alipay payment using the following routing:
|
||||
// - Mobile (H5): alipay.trade.wap.pay — browser redirect into Alipay.
|
||||
// - Desktop: prefer alipay.trade.precreate to get a scan payload directly.
|
||||
// - Desktop fallback: if precreate is unavailable for the merchant, fall back
|
||||
// to alipay.trade.page.pay and expose both pay_url and qr_code so the
|
||||
// frontend can render a QR while still allowing direct page open.
|
||||
func (a *Alipay) CreatePayment(ctx context.Context, req payment.CreatePaymentRequest) (*payment.CreatePaymentResponse, error) {
|
||||
// CreatePayment creates an Alipay payment using redirect-only flow:
|
||||
// - Mobile (H5): alipay.trade.wap.pay — returns a URL the browser jumps to.
|
||||
// - PC: alipay.trade.page.pay — returns a gateway URL the browser opens in a
|
||||
// new window; Alipay's own page then shows login/QR. We intentionally do
|
||||
// NOT encode the URL into a QR on the client (it isn't a scannable payload
|
||||
// and would produce an invalid scan result).
|
||||
func (a *Alipay) CreatePayment(_ context.Context, req payment.CreatePaymentRequest) (*payment.CreatePaymentResponse, error) {
|
||||
client, err := a.getClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -127,7 +123,7 @@ func (a *Alipay) CreatePayment(ctx context.Context, req payment.CreatePaymentReq
|
||||
if req.IsMobile {
|
||||
return a.createWapTrade(client, req, notifyURL, returnURL)
|
||||
}
|
||||
return a.createDesktopTrade(ctx, client, req, notifyURL, returnURL)
|
||||
return a.createPagePayTrade(client, req, notifyURL, returnURL)
|
||||
}
|
||||
|
||||
func (a *Alipay) createWapTrade(client *alipay.Client, req payment.CreatePaymentRequest, notifyURL, returnURL string) (*payment.CreatePaymentResponse, error) {
|
||||
@@ -149,48 +145,6 @@ func (a *Alipay) createWapTrade(client *alipay.Client, req payment.CreatePayment
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (a *Alipay) createDesktopTrade(ctx context.Context, client *alipay.Client, req payment.CreatePaymentRequest, notifyURL, returnURL string) (*payment.CreatePaymentResponse, error) {
|
||||
resp, precreateErr := a.createPrecreateTrade(ctx, client, req, notifyURL)
|
||||
if precreateErr == nil {
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
resp, pagePayErr := a.createPagePayTrade(client, req, notifyURL, returnURL)
|
||||
if pagePayErr == nil {
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("alipay desktop payment failed: precreate=%v; pagepay=%w", precreateErr, pagePayErr)
|
||||
}
|
||||
|
||||
func (a *Alipay) createPrecreateTrade(ctx context.Context, client *alipay.Client, req payment.CreatePaymentRequest, notifyURL string) (*payment.CreatePaymentResponse, error) {
|
||||
param := alipay.TradePreCreate{}
|
||||
param.OutTradeNo = req.OrderID
|
||||
param.TotalAmount = req.Amount
|
||||
param.Subject = req.Subject
|
||||
param.ProductCode = alipayProductCodePreCreate
|
||||
param.NotifyURL = notifyURL
|
||||
|
||||
rsp, err := alipayTradePreCreate(ctx, client, param)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("alipay TradePreCreate: %w", err)
|
||||
}
|
||||
if rsp == nil {
|
||||
return nil, fmt.Errorf("alipay TradePreCreate: empty response")
|
||||
}
|
||||
if rsp.IsFailure() {
|
||||
return nil, fmt.Errorf("alipay TradePreCreate failed: %s", rsp.Error.Error())
|
||||
}
|
||||
if strings.TrimSpace(rsp.QRCode) == "" {
|
||||
return nil, fmt.Errorf("alipay TradePreCreate: empty qr_code")
|
||||
}
|
||||
|
||||
return &payment.CreatePaymentResponse{
|
||||
TradeNo: req.OrderID,
|
||||
QRCode: rsp.QRCode,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (a *Alipay) createPagePayTrade(client *alipay.Client, req payment.CreatePaymentRequest, notifyURL, returnURL string) (*payment.CreatePaymentResponse, error) {
|
||||
param := alipay.TradePagePay{}
|
||||
param.OutTradeNo = req.OrderID
|
||||
@@ -207,7 +161,6 @@ func (a *Alipay) createPagePayTrade(client *alipay.Client, req payment.CreatePay
|
||||
return &payment.CreatePaymentResponse{
|
||||
TradeNo: req.OrderID,
|
||||
PayURL: payURL.String(),
|
||||
QRCode: payURL.String(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -239,15 +192,7 @@ func (a *Alipay) QueryOrder(ctx context.Context, tradeNo string) (*payment.Query
|
||||
|
||||
amount, err := strconv.ParseFloat(result.TotalAmount, 64)
|
||||
if err != nil {
|
||||
amount, err = parseAlipayAmount(
|
||||
result.TotalAmount,
|
||||
result.ReceiptAmount,
|
||||
result.BuyerPayAmount,
|
||||
result.InvoiceAmount,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("alipay parse amount: %w", err)
|
||||
}
|
||||
return nil, fmt.Errorf("alipay parse amount %q: %w", result.TotalAmount, err)
|
||||
}
|
||||
|
||||
return &payment.QueryOrderResponse{
|
||||
@@ -283,14 +228,7 @@ func (a *Alipay) VerifyNotification(ctx context.Context, rawBody string, _ map[s
|
||||
|
||||
amount, err := strconv.ParseFloat(notification.TotalAmount, 64)
|
||||
if err != nil {
|
||||
amount, err = parseAlipayAmount(
|
||||
notification.TotalAmount,
|
||||
notification.ReceiptAmount,
|
||||
notification.BuyerPayAmount,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("alipay parse notification amount: %w", err)
|
||||
}
|
||||
return nil, fmt.Errorf("alipay parse notification amount %q: %w", notification.TotalAmount, err)
|
||||
}
|
||||
|
||||
metadata := a.MerchantIdentityMetadata()
|
||||
@@ -368,20 +306,6 @@ func isTradeNotExist(err error) bool {
|
||||
return strings.Contains(err.Error(), alipayErrTradeNotExist)
|
||||
}
|
||||
|
||||
func parseAlipayAmount(values ...string) (float64, error) {
|
||||
for _, raw := range values {
|
||||
raw = strings.TrimSpace(raw)
|
||||
if raw == "" {
|
||||
continue
|
||||
}
|
||||
amount, err := strconv.ParseFloat(raw, 64)
|
||||
if err == nil {
|
||||
return amount, nil
|
||||
}
|
||||
}
|
||||
return 0, fmt.Errorf("no valid amount field")
|
||||
}
|
||||
|
||||
// Ensure interface compliance.
|
||||
var (
|
||||
_ payment.Provider = (*Alipay)(nil)
|
||||
|
||||
Reference in New Issue
Block a user