Implement IMPS fund transfer via initiate and verify-otp
Initiate runs the IMPS name inquiry and sends an OTP; verify-otp sends ReqPay. The result screen now distinguishes success, failure and pending reconciliation. The payer is temporarily fixed to the test account 002002000100019, and the to-mobile form no longer blocks on mobile/MMID format. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
473f9d7415
commit
abb14d5768
@@ -9,9 +9,9 @@ import {
|
||||
} from './cbsErrors';
|
||||
|
||||
describe('error code catalogue', () => {
|
||||
it('covers all 46 documented codes, with no duplicates', () => {
|
||||
expect(CBS_ERROR_CODES).toHaveLength(46);
|
||||
expect(new Set(CBS_ERROR_CODES).size).toBe(46);
|
||||
it('covers all 48 documented codes, with no duplicates', () => {
|
||||
expect(CBS_ERROR_CODES).toHaveLength(48);
|
||||
expect(new Set(CBS_ERROR_CODES).size).toBe(48);
|
||||
});
|
||||
|
||||
it('does not invite a retry when the bank withholds a balance', () => {
|
||||
|
||||
@@ -51,6 +51,8 @@ export const CBS_ERROR_CODES = [
|
||||
'SMS_DELIVERY_FAILED',
|
||||
'OTP_PROVIDER_UNAVAILABLE',
|
||||
'CONNECTOR_UNAVAILABLE',
|
||||
'IMPS_REQUEST_REJECTED',
|
||||
'TRANSFER_NOT_AWAITING_OTP',
|
||||
] as const;
|
||||
|
||||
export type CbsErrorCode = (typeof CBS_ERROR_CODES)[number];
|
||||
@@ -256,7 +258,7 @@ const ERROR_COPY: Record<AnyErrorCode, ErrorCopy> = {
|
||||
},
|
||||
OTP_ATTEMPTS_EXCEEDED: {
|
||||
title: 'Too many wrong codes',
|
||||
description: 'Start registration again to get a new code.',
|
||||
description: 'Start again to get a new code.',
|
||||
},
|
||||
INTERNAL_ERROR: {
|
||||
title: 'Something went wrong at the bank',
|
||||
@@ -282,6 +284,15 @@ const ERROR_COPY: Record<AnyErrorCode, ErrorCopy> = {
|
||||
title: 'Payee checks are unavailable',
|
||||
description: 'This is a server configuration issue, not a problem with the details you entered.',
|
||||
},
|
||||
IMPS_REQUEST_REJECTED: {
|
||||
title: 'The payment network refused the request',
|
||||
description: 'Nothing was sent. Please try again in a moment.',
|
||||
retryable: true,
|
||||
},
|
||||
TRANSFER_NOT_AWAITING_OTP: {
|
||||
title: 'This transfer is already finished',
|
||||
description: 'It is no longer waiting for a code, so nothing was sent again. Check your transactions for its outcome.',
|
||||
},
|
||||
MMID_ALLOCATION_FAILED: {
|
||||
title: 'We could not finish setting up your accounts',
|
||||
description: 'Please try again shortly.',
|
||||
|
||||
@@ -69,6 +69,15 @@ export const endpoints = {
|
||||
save: '/beneficiaries',
|
||||
validate: '/beneficiaries/validate',
|
||||
},
|
||||
/**
|
||||
* IMPS transfers, in two steps. `initiate` runs the name inquiry and sends an
|
||||
* OTP but moves no money; `verifyOtp` consumes the OTP and sends ReqPay. The
|
||||
* server never sends ReqPay before a verified OTP, and never retries it.
|
||||
*/
|
||||
fundTransfers: {
|
||||
initiate: '/fund-transfers/initiate',
|
||||
verifyOtp: (transferId: string) => `/fund-transfers/${transferId}/verify-otp`,
|
||||
},
|
||||
dashboard: {
|
||||
summary: '/dashboard/summary',
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user