Fix mobile payment launch detection

This commit is contained in:
IanShaw027
2026-04-21 09:22:40 -07:00
parent da1d26001f
commit 906802abe3
5 changed files with 164 additions and 12 deletions

View File

@@ -106,6 +106,35 @@ describe('decidePaymentLaunch', () => {
expect(decision.recovery.resumeToken).toBe('resume-2')
})
it('prefers redirect on mobile when both pay_url and qr_code are present', () => {
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,
})
expect(decision.kind).toBe('redirect_waiting')
expect(decision.paymentState.payUrl).toBe('https://pay.example.com/mobile/session')
expect(decision.paymentState.qrCode).toBe('https://pay.example.com/qr/session')
})
it('keeps QR flow on desktop when both pay_url and qr_code are present', () => {
const decision = decidePaymentLaunch(createOrderResult({
pay_url: 'https://pay.example.com/desktop/session',
qr_code: 'https://pay.example.com/qr/session',
}), {
visibleMethod: 'wxpay',
orderType: 'balance',
isMobile: false,
})
expect(decision.kind).toBe('qr_waiting')
expect(decision.paymentState.qrCode).toBe('https://pay.example.com/qr/session')
})
it('returns wechat oauth launch when backend requires in-app authorization', () => {
const decision = decidePaymentLaunch(createOrderResult({
result_type: 'oauth_required',

View File

@@ -46,6 +46,7 @@ export interface PaymentLaunchContext {
visibleMethod: string
orderType: OrderType
isMobile: boolean
isWechatBrowser?: boolean
now?: number
stripePopupUrl?: string
stripeRouteUrl?: string
@@ -159,7 +160,23 @@ export function decidePaymentLaunch(
return { kind: 'wechat_jsapi', paymentState: baseState, recovery: baseState, jsapi: jsapiPayload }
}
if (baseState.qrCode) {
const normalizedPaymentMode = baseState.paymentMode.trim().toLowerCase()
const prefersRedirect = normalizedPaymentMode === 'redirect'
|| normalizedPaymentMode === 'popup'
|| (context.isMobile && !!baseState.payUrl)
const prefersQr = normalizedPaymentMode === 'qrcode'
|| normalizedPaymentMode === 'native'
|| (!prefersRedirect && !!baseState.qrCode)
if (visibleMethod === 'wxpay' && context.isWechatBrowser && baseState.payUrl && !baseState.qrCode) {
return { kind: 'redirect_waiting', paymentState: baseState, recovery: baseState }
}
if (prefersRedirect && baseState.payUrl) {
return { kind: 'redirect_waiting', paymentState: baseState, recovery: baseState }
}
if (prefersQr && baseState.qrCode) {
return { kind: 'qr_waiting', paymentState: baseState, recovery: baseState }
}