fix: improve h5 payment return flow
This commit is contained in:
@@ -8,9 +8,9 @@ PUBLIC_FILE_BASE_URL=
|
||||
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=anxinyan
|
||||
DB_USERNAME=root
|
||||
DB_PASSWORD=change_me
|
||||
DB_DATABASE=test_anxinyan
|
||||
DB_USERNAME=
|
||||
DB_PASSWORD=
|
||||
DB_CHARSET=utf8mb4
|
||||
DB_PREFIX=
|
||||
|
||||
|
||||
@@ -88,7 +88,11 @@ class ShouqianbaConfigService
|
||||
return '';
|
||||
}
|
||||
|
||||
return $baseUrl . '/#/pages/order/detail?id=' . $orderId;
|
||||
$fallbackQuery = http_build_query([
|
||||
'sqb_return_order_id' => $orderId,
|
||||
], '', '&', PHP_QUERY_RFC3986);
|
||||
|
||||
return $baseUrl . '/?' . $fallbackQuery . '#/pages/order/detail?id=' . $orderId;
|
||||
}
|
||||
|
||||
public function miniProgramCallbackPath(int $orderId): string
|
||||
|
||||
@@ -54,6 +54,11 @@ class ShouqianbaPaymentService
|
||||
|
||||
$latest = $this->latestPayment($orderId);
|
||||
if ($latest && in_array((string)$latest['status'], ['pending', 'created'], true) && (string)$latest['order_token'] !== '') {
|
||||
if ($this->shouldRefreshH5ReturnUrl($latest, $order)) {
|
||||
$replacement = $this->createPayment($order);
|
||||
$this->markPaymentReplaced($latest);
|
||||
return $replacement;
|
||||
}
|
||||
return $this->buildPaymentLaunchPayload($latest, $order);
|
||||
}
|
||||
|
||||
@@ -281,6 +286,44 @@ class ShouqianbaPaymentService
|
||||
return $payload;
|
||||
}
|
||||
|
||||
private function shouldRefreshH5ReturnUrl(array $payment, array $order): bool
|
||||
{
|
||||
if ((string)$order['source_channel'] !== 'h5') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$expectedUrl = $this->configService->h5OrderDetailUrl((int)$order['id']);
|
||||
if ($expectedUrl === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$requestJson = json_decode((string)($payment['request_json'] ?? ''), true);
|
||||
if (!is_array($requestJson)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$body = $requestJson['body'] ?? ($requestJson['request']['body'] ?? null);
|
||||
if (!is_array($body)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (string)($body['return_url'] ?? '') !== $expectedUrl
|
||||
|| (string)($body['back_url'] ?? '') !== $expectedUrl;
|
||||
}
|
||||
|
||||
private function markPaymentReplaced(array $payment): void
|
||||
{
|
||||
$now = date('Y-m-d H:i:s');
|
||||
Db::name('shouqianba_payments')
|
||||
->where('id', (int)$payment['id'])
|
||||
->whereIn('status', ['pending', 'created'])
|
||||
->update([
|
||||
'status' => 'replaced',
|
||||
'cancelled_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
|
||||
private function queryRemotePayment(array $payment): array
|
||||
{
|
||||
$config = $this->configService->assertReady(true);
|
||||
|
||||
@@ -320,6 +320,32 @@ try {
|
||||
assertTrue(($launch['status'] ?? '') === 'pending', 'purchase should create pending payment');
|
||||
assertTrue(($launch['cashier_url'] ?? '') !== '', 'purchase cashier_url missing');
|
||||
$payment = latestPayment($notifyOrderId);
|
||||
$requestJson = json_decode((string)$payment['request_json'], true);
|
||||
$purchaseBody = is_array($requestJson) ? ($requestJson['body'] ?? []) : [];
|
||||
assertTrue(
|
||||
($purchaseBody['return_url'] ?? '') === 'https://m.example.com/?sqb_return_order_id=' . $notifyOrderId . '#/pages/order/detail?id=' . $notifyOrderId,
|
||||
'purchase return_url should include H5 order detail fallback'
|
||||
);
|
||||
assertTrue(($purchaseBody['back_url'] ?? '') === ($purchaseBody['return_url'] ?? ''), 'purchase back_url should match return_url');
|
||||
|
||||
$staleReturnOrderId = createMockOrder($userId, 'STALERETURN');
|
||||
$service->createOrReusePayment($staleReturnOrderId);
|
||||
$stalePayment = latestPayment($staleReturnOrderId);
|
||||
$staleRequestJson = json_decode((string)$stalePayment['request_json'], true);
|
||||
if (is_array($staleRequestJson)) {
|
||||
$staleRequestJson['body']['return_url'] = 'https://m.example.com/#/pages/order/detail?id=' . $staleReturnOrderId;
|
||||
$staleRequestJson['body']['back_url'] = $staleRequestJson['body']['return_url'];
|
||||
Db::name('shouqianba_payments')->where('id', (int)$stalePayment['id'])->update([
|
||||
'request_json' => json_encode($staleRequestJson, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
|
||||
]);
|
||||
}
|
||||
$replacement = $service->createOrReusePayment($staleReturnOrderId);
|
||||
$stalePaymentAfterReplace = Db::name('shouqianba_payments')->where('id', (int)$stalePayment['id'])->find();
|
||||
$latestReplacement = latestPayment($staleReturnOrderId);
|
||||
assertTrue((string)($stalePaymentAfterReplace['status'] ?? '') === 'replaced', 'stale H5 payment should be marked replaced');
|
||||
assertTrue((int)$latestReplacement['id'] !== (int)$stalePayment['id'], 'stale H5 payment should be replaced with a new payment row');
|
||||
assertTrue(($replacement['check_sn'] ?? '') === (string)$latestReplacement['check_sn'], 'replacement launch payload should use the new payment row');
|
||||
|
||||
$notifyPayload = [
|
||||
'check_sn' => $payment['check_sn'],
|
||||
'order_status' => '4',
|
||||
|
||||
Reference in New Issue
Block a user