mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-28 08:08:32 +00:00
feat(payment): 支持强制移动端统一使用二维码支付
This commit is contained in:
@@ -220,6 +220,36 @@ describe('decidePaymentLaunch', () => {
|
||||
expect(decision.jsapi?.appId).toBe('wx123')
|
||||
expect(decision.paymentState.orderType).toBe('subscription')
|
||||
})
|
||||
|
||||
it('forces qr_waiting for mobile alipay when forceQRCode is enabled', () => {
|
||||
const decision = decidePaymentLaunch(createOrderResult({
|
||||
pay_url: 'https://pay.example.com/mobile/session',
|
||||
qr_code: 'https://pay.example.com/qr/session',
|
||||
}), {
|
||||
visibleMethod: 'alipay',
|
||||
orderType: 'balance',
|
||||
isMobile: true,
|
||||
forceQRCode: true,
|
||||
})
|
||||
|
||||
expect(decision.kind).toBe('qr_waiting')
|
||||
expect(decision.paymentState.qrCode).toBe('https://pay.example.com/qr/session')
|
||||
})
|
||||
|
||||
it('does not affect non-alipay methods when forceQRCode is enabled', () => {
|
||||
const decision = decidePaymentLaunch(createOrderResult({
|
||||
pay_url: 'https://pay.example.com/mobile/session',
|
||||
qr_code: 'https://pay.example.com/qr/session',
|
||||
}), {
|
||||
visibleMethod: 'wxpay',
|
||||
orderType: 'balance',
|
||||
isMobile: true,
|
||||
forceQRCode: true,
|
||||
})
|
||||
|
||||
// wxpay mobile with pay_url still redirects
|
||||
expect(decision.kind).toBe('redirect_waiting')
|
||||
})
|
||||
})
|
||||
|
||||
describe('buildCreateOrderPayload', () => {
|
||||
@@ -260,6 +290,34 @@ describe('buildCreateOrderPayload', () => {
|
||||
payment_source: 'wechat_in_app_resume',
|
||||
})
|
||||
})
|
||||
|
||||
it('passes is_mobile: false when forceQRCode is enabled for alipay', () => {
|
||||
expect(buildCreateOrderPayload({
|
||||
amount: 50,
|
||||
paymentType: 'alipay',
|
||||
orderType: 'balance',
|
||||
origin: 'https://app.example.com',
|
||||
isMobile: true,
|
||||
isWechatBrowser: false,
|
||||
forceQRCode: true,
|
||||
})).toMatchObject({
|
||||
is_mobile: false,
|
||||
})
|
||||
})
|
||||
|
||||
it('still passes is_mobile: true when forceQRCode is enabled for non-alipay methods', () => {
|
||||
expect(buildCreateOrderPayload({
|
||||
amount: 50,
|
||||
paymentType: 'wxpay',
|
||||
orderType: 'balance',
|
||||
origin: 'https://app.example.com',
|
||||
isMobile: true,
|
||||
isWechatBrowser: false,
|
||||
forceQRCode: true,
|
||||
})).toMatchObject({
|
||||
is_mobile: true,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('readPaymentRecoverySnapshot', () => {
|
||||
|
||||
@@ -55,6 +55,8 @@ export interface PaymentLaunchContext {
|
||||
orderType: OrderType
|
||||
isMobile: boolean
|
||||
isWechatBrowser?: boolean
|
||||
/** When true, Alipay payments always use QR code regardless of device type */
|
||||
forceQRCode?: boolean
|
||||
now?: number
|
||||
stripePopupUrl?: string
|
||||
stripeRouteUrl?: string
|
||||
@@ -78,6 +80,8 @@ export interface BuildCreateOrderPayloadInput {
|
||||
origin?: string
|
||||
isMobile: boolean
|
||||
isWechatBrowser: boolean
|
||||
/** When true, Alipay payments always use QR code (passes is_mobile: false to backend) */
|
||||
forceQRCode?: boolean
|
||||
}
|
||||
|
||||
type CreateOrderFlowResult = CreateOrderResult & {
|
||||
@@ -111,11 +115,16 @@ export function getVisibleMethods(methods: Record<string, MethodLimit>): Record<
|
||||
export function buildCreateOrderPayload(input: BuildCreateOrderPayloadInput): CreateOrderRequest {
|
||||
const visibleMethod = normalizeVisibleMethod(input.paymentType) || input.paymentType.trim()
|
||||
const normalizedOrigin = (input.origin || '').trim().replace(/\/+$/, '')
|
||||
// When forceQRCode is enabled for alipay, always tell the backend this is not a mobile
|
||||
// request so it generates a QR code instead of a mobile-redirect URL.
|
||||
const effectiveMobile = (input.forceQRCode && visibleMethod === 'alipay')
|
||||
? false
|
||||
: input.isMobile
|
||||
const payload: CreateOrderRequest = {
|
||||
amount: input.amount,
|
||||
payment_type: visibleMethod,
|
||||
order_type: input.orderType,
|
||||
is_mobile: input.isMobile,
|
||||
is_mobile: effectiveMobile,
|
||||
payment_source: visibleMethod === 'wxpay' && input.isWechatBrowser
|
||||
? 'wechat_in_app_resume'
|
||||
: 'hosted_redirect',
|
||||
@@ -190,9 +199,14 @@ export function decidePaymentLaunch(
|
||||
}
|
||||
|
||||
const normalizedPaymentMode = baseState.paymentMode.trim().toLowerCase()
|
||||
// When forceQRCode is on for alipay, treat the device as desktop so the mobile-redirect
|
||||
// branch is bypassed and we fall through to qr_waiting.
|
||||
const effectiveMobile = (context.forceQRCode && visibleMethod === 'alipay')
|
||||
? false
|
||||
: context.isMobile
|
||||
const prefersRedirect = normalizedPaymentMode === 'redirect'
|
||||
|| normalizedPaymentMode === 'popup'
|
||||
|| (context.isMobile && !!baseState.payUrl)
|
||||
|| (effectiveMobile && !!baseState.payUrl)
|
||||
const prefersQr = normalizedPaymentMode === 'qrcode'
|
||||
|| normalizedPaymentMode === 'native'
|
||||
|| (!prefersRedirect && !!baseState.qrCode)
|
||||
|
||||
Reference in New Issue
Block a user