Skip to content

Commit

Permalink
nedbank comments
Browse files Browse the repository at this point in the history
Signed-off-by: Ruben <[email protected]>
  • Loading branch information
Ruben committed Feb 5, 2025
1 parent 600a671 commit 0ca0744
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,13 @@ To enable loading certificate files via environment variables in the Azure App S
```dotenv
NEDBANK_CERTIFICATE_PATH=/var/ssl/private/<thumbprint>.p12
```
4. **Error Handling**:
- When making a payment to Nedbank, if the certificate is not set up correctly, you will encounter transactions with the following error:
```json
{ "errno": -71, "code": "EPROTO", "syscall": "write" }
```
- Ensure that the certificate is correctly uploaded and the path is correctly set in the environment variables to avoid this error.
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ exports[`NedbankService createVoucher should throw an error if phone number does

exports[`NedbankService createVoucher should throw an error if phone number length is not 11 1`] = `"Phone number must be 11 numbers long (including 27 as country code)"`;

exports[`NedbankService retrieveVoucherInfo should not return a voucher status and specific error code and message on a NBApimTooManyRequestsError api error 1`] = `"Too many requests"`;

exports[`NedbankService retrieveVoucherInfo should return a voucher status and specific error code and message on a NBApimResourceNotFound api error 1`] = `"Resource not found"`;
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,26 @@ describe('NedbankService', () => {
);
});

it('should not return a voucher status and specific error code and message on a NBApimTooManyRequestsError api error', async () => {
const error = new NedbankApiError('Too many requests');
error.code = NedbankApiErrorCode.NBApimTooManyRequestsError;

jest
.spyOn(apiService, 'getOrderByOrderCreateReference')
.mockRejectedValue(error);

const result = await service.retrieveVoucherInfo(orderCreateReference);

expect(result.errorCode).toBe(
NedbankErrorCode.tooManyRequestsForThisVoucher,
);
expect(result.status).toBeUndefined();
expect(result.errorMessage).toMatchSnapshot();
expect(apiService.getOrderByOrderCreateReference).toHaveBeenCalledWith(
orderCreateReference,
);
});

it('should return the error message and a generic error code on a Nedbank Api error that is not specifically handled', async () => {
const error = new NedbankApiError('General error');
error.code = 'SomeOtherErrorCode';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { NedbankApiError } from '@121-service/src/payments/fsp-integration/nedba
import { NedbankApiHelperService } from '@121-service/src/payments/fsp-integration/nedbank/services/nedbank-api.helper.service';
import { NedbankApiClientService } from '@121-service/src/payments/fsp-integration/nedbank/services/nedbank-api-client.service';
import { CustomHttpService } from '@121-service/src/shared/services/custom-http.service';

jest.mock('@121-service/src/shared/services/custom-http.service');

describe('NedbankApiClientService', () => {
Expand Down Expand Up @@ -42,8 +43,10 @@ describe('NedbankApiClientService', () => {
apiHelperService = module.get<NedbankApiHelperService>(
NedbankApiHelperService,
);
// Mock the httpsAgent
service.httpsAgent = {} as https.Agent;
});

afterEach(() => {
jest.resetModules();
});

describe('makeApiRequestOrThrow', () => {
Expand All @@ -70,6 +73,12 @@ describe('NedbankApiClientService', () => {
jest
.spyOn(apiHelperService, 'isNedbankErrorResponse')
.mockReturnValue(false);
jest
.spyOn(httpService, 'createHttpsAgentWithCertificate')
.mockReturnValue({} as https.Agent);

// Reinitialize the service to set httpsAgent
service = new NedbankApiClientService(httpService, apiHelperService);

// Act
const result = await service.makeApiRequestOrThrow({
Expand All @@ -86,7 +95,13 @@ describe('NedbankApiClientService', () => {
});

it('should throw an error if httpsAgent is not defined', async () => {
service.httpsAgent = undefined;
jest
.spyOn(httpService, 'createHttpsAgentWithCertificate')
.mockReturnValue(undefined as any);

// Reinitialize the service to set httpsAgent to undefined
service = new NedbankApiClientService(httpService, apiHelperService);

await expect(
service.makeApiRequestOrThrow({
endpoint: 'https://example.com',
Expand Down Expand Up @@ -115,6 +130,12 @@ describe('NedbankApiClientService', () => {
.spyOn(apiHelperService, 'isNedbankErrorResponse')
.mockReturnValue(true);
jest.spyOn(httpService, 'request').mockResolvedValue(errorResponse);
jest
.spyOn(httpService, 'createHttpsAgentWithCertificate')
.mockReturnValue({} as https.Agent);

// Reinitialize the service to set httpsAgent
service = new NedbankApiClientService(httpService, apiHelperService);

await expect(
service.makeApiRequestOrThrow({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const nedbankApiUrl = process.env.MOCK_NEDBANK

@Injectable()
export class NedbankApiClientService {
public httpsAgent: https.Agent | undefined;
private httpsAgent: https.Agent | undefined;

public constructor(
private readonly httpService: CustomHttpService,
Expand Down Expand Up @@ -75,7 +75,7 @@ export class NedbankApiClientService {
}
return this.httpService.createHttpsAgentWithCertificate(
process.env.NEDBANK_CERTIFICATE_PATH!,
process.env.NEDBANK_CERTIFICATE_PASSWORD!,
process.env.NEDBANK_CERTIFICATE_PASSWORD,
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export class NedbankReconciliationService {
) {}

public async doNedbankReconciliation(): Promise<void> {
const vouchers = await this.nedbankVoucherScopedRepository.find({
const voucherReferences = await this.nedbankVoucherScopedRepository.find({
select: ['orderCreateReference', 'transactionId'],
where: [
{ status: IsNull() },
Expand All @@ -33,12 +33,12 @@ export class NedbankReconciliationService {
],
});

for (const voucher of vouchers) {
await this.reconciliateVoucherAndTransaction(voucher);
for (const voucherReference of voucherReferences) {
await this.reconcileVoucherAndTransaction(voucherReference);
}
}

private async reconciliateVoucherAndTransaction({
private async reconcileVoucherAndTransaction({
orderCreateReference,
transactionId,
}: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,9 +298,9 @@ export class TransactionJobProcessorsService {
},
)) as string; // This must be a string. If it is undefined the validation in payment service should have caught it. If a user set it as an array string you should get an internal server error here, this seems like an edge case;
const sanitizedPaymentReferencePrefix = paymentReferencePrefix.replace(
/[^a-zA-Z0-9]/g,
/[^a-zA-Z0-9-]/g,
'',
); // All non-alphanumeric characters are removed because the nedbank API does not accept them
); // All non-alphanumeric characters (except hyphens) are removed because the nedbank API does not accept them
const paymentReference = `${sanitizedPaymentReferencePrefix.slice(0, 18)}-${transactionJob.phoneNumber}`;

// 3. Check if there is an existing voucher/orderCreateReference without status if not create orderCreateReference, the nedbank voucher and the related transaction
Expand Down

0 comments on commit 0ca0744

Please sign in to comment.