Files
CBS-Mobile-App/src/modules/payments/services/paymentsApi.ts
T

125 lines
4.5 KiB
TypeScript

import { apiClient } from '../../../services/api/apiClient';
import { baseApi } from '../../../services/api/baseApi';
import { endpoints } from '../../../services/api/endpoints';
import { resolveLive, resolveWithMock } from '../../../services/api/serviceHelpers';
import type { Beneficiary } from '../../../types/app';
import type {
BeneficiarySaveRequest,
BeneficiaryValidateRequest,
BeneficiaryValidateResult,
CbsBeneficiary,
} from '../../../types/cbs';
import { favoriteStore, toBeneficiary } from '../utils/beneficiaryMapper';
/**
* TEMPORARY — fixed payer account for payee validation.
*
* Every validate call goes out with this as the payer, overriding whichever
* account the customer selected on screen. The development CBS only recognises
* this account as a payer; the profile's own accounts come back
* `ACCOUNT_NOT_FOUND`, which reads on screen as the *payee* being unverifiable.
*
* Delete this and pass `request` through untouched once the backend accepts
* the profile's accounts. It must not ship: in production it would validate
* every payee against an account that is not the customer's.
*/
const HARDCODED_PAYER_ACCOUNT = '002002000100019';
export interface BankTransferRequest {
beneficiaryId: string;
amount: number;
transferType: 'IMPS' | 'NEFT' | 'RTGS' | 'Internal';
remarks?: string;
sourceAccountId: string;
}
export interface BankTransferResponse {
referenceId: string;
status: 'Process_Success' | 'Process_Pending';
}
export const paymentsApi = baseApi.injectEndpoints({
endpoints: (builder) => ({
/** The customer's saved payees, newest first. */
getBeneficiaries: builder.query<Beneficiary[], void>({
queryFn: () =>
resolveLive(async () => {
const [response, favorites] = await Promise.all([
apiClient.get<CbsBeneficiary[]>(endpoints.beneficiaries.list),
favoriteStore.read(),
]);
const favoriteSet = new Set(favorites);
return (response.data ?? []).map((payee) => toBeneficiary(payee, favoriteSet));
}),
providesTags: ['Beneficiaries'],
}),
/**
* Asks IMPS whether this payee exists, and who they are. Saves nothing.
*
* This is what the confirmation step shows, because a mistyped account
* number is the most common way money reaches the wrong person. Read
* `result` rather than the status code: the switch answers 200 whether or
* not it recognised the payee.
*/
validateBeneficiary: builder.mutation<BeneficiaryValidateResult, BeneficiaryValidateRequest>({
queryFn: (request) =>
resolveLive(async () => {
const response = await apiClient.post<BeneficiaryValidateResult>(
endpoints.beneficiaries.validate,
// See HARDCODED_PAYER_ACCOUNT — the caller's payer is discarded.
{ ...request, payer: { accountNumber: HARDCODED_PAYER_ACCOUNT } },
);
return response.data;
}),
}),
/**
* Saves the payee, resolved through the bank's CBS lookup.
*
* A different body and a different lookup from validate, which goes to
* IMPS — so the two can disagree, and this one's answer is what gets
* stored. Validate first regardless: the server does not enforce the
* order, which means nothing but the app stops a customer saving a payee
* nobody has confirmed.
*/
saveBeneficiary: builder.mutation<Beneficiary, BeneficiarySaveRequest>({
queryFn: (request) =>
resolveLive(async () => {
const response = await apiClient.post<CbsBeneficiary>(
endpoints.beneficiaries.save,
request,
);
return toBeneficiary(response.data);
}),
invalidatesTags: ['Beneficiaries'],
}),
/** No transfer endpoint exists yet, so this stays on fixtures. */
submitBankTransfer: builder.mutation<BankTransferResponse, BankTransferRequest>({
queryFn: (req) =>
resolveWithMock({
mockData: () => ({
referenceId: `${req.transferType}${Date.now()}`,
status: req.transferType === 'NEFT' ? 'Process_Pending' : 'Process_Success',
}),
request: async () => {
throw new Error('Transfer submission is not implemented by the CBS API yet');
},
}),
invalidatesTags: ['Payments', 'Transactions'],
}),
}),
});
export const {
useGetBeneficiariesQuery,
useValidateBeneficiaryMutation,
useSaveBeneficiaryMutation,
useSubmitBankTransferMutation,
} = paymentsApi;