Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add: account not found and insufficient errors with their unit tests #49

Merged
merged 6 commits into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion packages/marupay/src/handlers/edahab/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@ export interface PurchasePaymentRes {
StatusCode: number;
RequestId: number;
StatusDescription: string;
ValidationErrors?: string;
ValidationErrors?: ValidationError[];
}

export interface ValidationError {
Property: string;
ErrorMessage: string;
}

export interface CreditPaymentReq {
Expand Down
49 changes: 48 additions & 1 deletion packages/marupay/src/handlers/edahab/edahab.spec.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import axios from 'axios';
import { EdahabHandler, createEdahabHandler } from './edahab'; // Import your EdahabHandler
import { Currency } from '../../handlers/enums';
import { VendorErrorException } from '../../handlers/exeptions';
import { VendorAccountNotFound, VendorErrorException, VendorInsufficientBalance } from '../../handlers/exeptions';

jest.mock('axios');

Check warning on line 6 in packages/marupay/src/handlers/edahab/edahab.spec.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

'jest' is not defined

const mockedAxios = axios as jest.Mocked<typeof axios>;

Check warning on line 8 in packages/marupay/src/handlers/edahab/edahab.spec.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

'jest' is not defined

describe('Edahab Handler', () => {

Check warning on line 10 in packages/marupay/src/handlers/edahab/edahab.spec.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

'describe' is not defined
let handler: EdahabHandler;
let options: any;

beforeAll(() => {

Check warning on line 14 in packages/marupay/src/handlers/edahab/edahab.spec.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

'beforeAll' is not defined
handler = createEdahabHandler({
apiKey: 'yourApiKey',
secretKey: 'yourSecretKey',
Expand All @@ -25,7 +25,7 @@
}
});

it('returns the success payment response for purchase', async () => {

Check warning on line 28 in packages/marupay/src/handlers/edahab/edahab.spec.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

'it' is not defined
const serverResponse = {
InvoiceStatus: "Paid",
TransactionId: "MP2234219.2220.A91111",
Expand All @@ -36,10 +36,10 @@

const result = await handler.purchase(options);

expect(result.paymentStatus).toBe('Paid');

Check warning on line 39 in packages/marupay/src/handlers/edahab/edahab.spec.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

'expect' is not defined
});

it('throws vendor errors for purchase accordingly', async () => {

Check warning on line 42 in packages/marupay/src/handlers/edahab/edahab.spec.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

'it' is not defined
const serverResponse = {
InvoiceStatus: "Unpaid",
TransactionId: "MP2234219.2220.A91111",
Expand All @@ -48,7 +48,7 @@

mockedAxios.post.mockResolvedValueOnce({ data: serverResponse });

await expect(handler.purchase(options)).rejects.toThrow(new VendorErrorException('1', 'Unpaid'));

Check warning on line 51 in packages/marupay/src/handlers/edahab/edahab.spec.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

'expect' is not defined
});

it('returns the success payment response for credit', async () => {
Expand Down Expand Up @@ -76,4 +76,51 @@
await expect(handler.credit(options)).rejects.toThrow(new VendorErrorException('Failed', 'EDAHAB-CREDIT-ERROR'));
});

it('throws vendor errors for purchase when account not found', async () => {
const serverResponse = {
StatusCode: 3,
RequestId: 2142,
StatusDescription: "Validation Error",
ValidationErrors: [
{
Property: "EDahabNumber",
ErrorMessage: "Must be 9 digits and start with 65 or 66 or 62 or 64"
}
]
}

mockedAxios.post.mockResolvedValueOnce({ data: serverResponse });

await expect(handler.purchase(options)).rejects.toThrow(
new VendorAccountNotFound(serverResponse.ValidationErrors[0].ErrorMessage)
);
});

it('throws vendor errors for purchase when customer insufficient balanace', async () => {
const serverResponse = {
StatusCode: 5,
RequestId: 2142,
StatusDescription: "Insufficient Customer Balance"
}

mockedAxios.post.mockResolvedValueOnce({ data: serverResponse });

await expect(handler.purchase(options)).rejects.toThrow(
new VendorInsufficientBalance(serverResponse.StatusDescription)
);
});

it('throws vendor errors for credit when insufficient balanace', async () => {
const serverResponse = {
TransactionStatus:"Rejected",
TransactionMesage: "You do not have sufficient balance."
}

mockedAxios.post.mockResolvedValueOnce({ data: serverResponse });

await expect(handler.credit(options)).rejects.toThrow(
new VendorInsufficientBalance(serverResponse.TransactionMesage)
);
});

});
35 changes: 23 additions & 12 deletions packages/marupay/src/handlers/edahab/edahab.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import axios from 'axios';
import { ZodString, z } from 'zod';
import { z } from 'zod';
import { generateUuid } from '../../utils/generateUuid';
import { defineHandler } from '../../handler';
import * as API from './api';
import { hashSecretKey } from './hash';
import { PaymentCtx, PaymentOptions } from '../types';
import { prepareRequest } from './prepareRequest';
import { SO_ACCOUNT_NUMBER, soPurchaseNumber } from '../constants'
import { safeParse } from '../../utils/safeParser';
import { VendorErrorException } from '../../handlers/exeptions';
import { VendorAccountNotFound, VendorErrorException, VendorInsufficientBalance } from '../../handlers/exeptions';

const edahabPurchase = z.object({
accountNumber: soPurchaseNumber,
Expand All @@ -25,11 +24,21 @@ const edahabPurchase = z.object({
*/
const purchaseFn = async (url: string, data: API.PurchasePaymentData, referenceId: string) => {
const response = await axios.post<API.PurchasePaymentReq, { data: API.PurchasePaymentRes }>(url, data);
const { TransactionId, InvoiceStatus } = response.data;
const responseCode = `${InvoiceStatus}`;
if (responseCode !== 'Paid') {
console.log(`${InvoiceStatus}`);
throw new VendorErrorException(responseCode, InvoiceStatus);
const { TransactionId, InvoiceStatus, StatusCode, StatusDescription } = response.data;
console.log(`response: ${JSON.stringify(response.data)}`);
if (response.data.ValidationErrors) {
const { ErrorMessage, Property } = response.data.ValidationErrors[0];
if (Property === 'EDahabNumber') {
throw new VendorAccountNotFound(ErrorMessage);
}
}

if (StatusCode === 5) {
throw new VendorInsufficientBalance(StatusDescription);
}

if (InvoiceStatus !== 'Paid') {
throw new VendorErrorException(`${StatusCode}`, InvoiceStatus);
}
return {
transactionId: TransactionId,
Expand All @@ -51,11 +60,13 @@ const creditFn = async (url: string, data: API.CreditPaymentData, referenceId: s
const response = await axios.post<API.CreditPaymentReq, { data: API.CreditPaymentRes }>(url, data);

const { TransactionId, TransactionMesage, TransactionStatus } = response.data;
const responseCode = `${TransactionStatus}`;

if (responseCode !== 'Approved') {
console.log(`credit error: ${TransactionMesage}`);
throw new VendorErrorException(responseCode, 'EDAHAB-CREDIT-ERROR');
if (TransactionMesage === 'You do not have sufficient balance.') {
throw new VendorInsufficientBalance(TransactionMesage);
}

if (TransactionStatus !== 'Approved') {
throw new VendorErrorException(TransactionStatus, 'EDAHAB-CREDIT-ERROR');
}

return {
Expand Down
16 changes: 15 additions & 1 deletion packages/marupay/src/handlers/exeptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,18 @@ class VendorErrorException extends MaruPayException {
}
}

export { MaruPayException, VendorErrorException };
class VendorAccountNotFound extends VendorErrorException {
constructor(public message: string) {
super('ACCOUNT-NOT-FOUND', message || 'Vendor account not found');
this.name = 'VendorAccountNotFound';
}
}

class VendorInsufficientBalance extends VendorErrorException {
constructor(public message: string) {
super('INSUFFICIENT-BALANCE', message || 'Vendor insufficient balance');
this.name = 'VendorInsufficientBalance';
}
}

export { MaruPayException, VendorErrorException, VendorAccountNotFound, VendorInsufficientBalance };
25 changes: 21 additions & 4 deletions packages/marupay/src/handlers/waafi/waafi.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import axios from 'axios';
import { WaafiHandler, createWaafiHandler } from './waafi'; // Import your WaafiHandler
import { Currency } from '../../handlers/enums';
import { VendorErrorException } from '../../handlers/exeptions';
import { VendorAccountNotFound, VendorErrorException, VendorInsufficientBalance } from '../../handlers/exeptions';

jest.mock('axios');

Expand Down Expand Up @@ -75,7 +75,7 @@ describe('Waafi Handler', () => {
expect(result.paymentStatus).toBe('APPROVED');
});

it('throws vendor errors for credit when account not found', async () => {
it('throws vendor errors for when account not found', async () => {
const serverResponse = {
responseCode: '5001',
responseMsg: 'RCS_NO_ROUTE_FOUND',
Expand All @@ -85,8 +85,25 @@ describe('Waafi Handler', () => {

mockedAxios.post.mockResolvedValueOnce({ data: serverResponse });

await expect(handler.credit(options)).rejects.toThrow(
new VendorErrorException('5001', 'RCS_NO_ROUTE_FOUND')
await expect(handler.purchase(options)).rejects.toThrow(
new VendorAccountNotFound('Must be a valid phone number')
);
});

it('throws vendor errors when insufficient balance', async () => {
const serverResponse = {
responseCode: '5001',
responseMsg: 'There are not enough funds in your account to complete this transaction.',
errorCode: 'E101073',
params: null,
};

mockedAxios.post.mockResolvedValueOnce({ data: serverResponse });

await expect(handler.purchase(options)).rejects.toThrow(
new VendorInsufficientBalance(serverResponse.responseMsg)
);
});


});
11 changes: 9 additions & 2 deletions packages/marupay/src/handlers/waafi/waafi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import * as API from './api';
import { prepareRequest } from './prepareRequest';
import { safeParse } from '../../utils/safeParser';
import { soPurchaseNumber } from '../../handlers/constants';
import { VendorErrorException } from '../../handlers/exeptions';
import { VendorAccountNotFound, VendorErrorException, VendorInsufficientBalance } from '../../handlers/exeptions';

const waafiPurchase = z.object({
accountNumber: soPurchaseNumber,
Expand All @@ -22,9 +22,16 @@ const waafiPurchase = z.object({
async function sendRequest(url: string, data: API.PurchaseData) {
const response = await axios.post<API.PurchasePaymentReq, { data: API.PurchasePaymentRes }>(url, data);
const { responseCode, responseMsg, errorCode, params } = response.data;

if (responseMsg === 'RCS_NO_ROUTE_FOUND') {
throw new VendorAccountNotFound('Must be a valid phone number');
}

if (errorCode === 'E101073') {
throw new VendorInsufficientBalance(responseMsg);
}

if (responseCode !== '2001' || params == null) {
console.log(`WAAFI: API-RES: ${responseMsg} ERROR-CODE: ${errorCode}`);
throw new VendorErrorException(errorCode, responseMsg);
}

Expand Down
Loading