From 3ac870cfcf3af8d550f11f6335a50071404d96f5 Mon Sep 17 00:00:00 2001 From: Sam Plackett <60177449+samplackett@users.noreply.github.com> Date: Mon, 16 Dec 2024 17:02:59 +0000 Subject: [PATCH] amend return file amounts, prevent duplicate files (#38) --- app/alerting/generate-return-file.js | 4 +- app/alerting/get-return-file-content.js | 5 +- package.json | 2 +- .../alerting/generate-return-file.test.js | 52 +++++++++++++++---- .../alerting/get-return-file-content.test.js | 28 +++++++++- 5 files changed, 77 insertions(+), 14 deletions(-) diff --git a/app/alerting/generate-return-file.js b/app/alerting/generate-return-file.js index f3602fd..df982e6 100644 --- a/app/alerting/generate-return-file.js +++ b/app/alerting/generate-return-file.js @@ -1,6 +1,7 @@ const moment = require('moment') const { getInboundBlobClient } = require('../storage') const { getReturnFileContent } = require('./get-return-file-content') +const { UNKNOWN } = require('../constants/unknown') const publishReturnFile = async (returnFilename, returnFileContent) => { const blobClient = await getInboundBlobClient(returnFilename) @@ -12,7 +13,8 @@ const generateReturnFile = async (event) => { const currentDate = moment() // hard coded sequence because it will be correctly generated in pay responses service const sequenceString = 'XXXX' - const returnFilename = `FCAP_${sequenceString}_RPA_${currentDate.format('YYMMDDHHmmss')}_NO_RETURN_MESSAGE.dat` + const frn = event.data?.frn ?? UNKNOWN + const returnFilename = `FCAP_${sequenceString}_RPA_${currentDate.format('YYMMDDHHmmss')}_${frn}_NO_RETURN_MESSAGE.dat` const content = getReturnFileContent(event) return publishReturnFile(returnFilename, content) } diff --git a/app/alerting/get-return-file-content.js b/app/alerting/get-return-file-content.js index ca99098..acb77aa 100644 --- a/app/alerting/get-return-file-content.js +++ b/app/alerting/get-return-file-content.js @@ -14,7 +14,10 @@ const getInboundFileNumber = (batch) => { const getReturnFileContent = (event) => { const batch = event.data?.batch || '' const inboundFileNumber = getInboundFileNumber(batch) - const amount = event.data?.value || '' + let amount = event.data?.value || '' + if (typeof amount === 'number' && Number.isInteger(amount)) { + amount = amount / 100 + } const content = getCSVString({ sbi: event.data?.sbi ?? '', frn: event.data?.frn ?? '', diff --git a/package.json b/package.json index 7cf26c0..bc3093c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ffc-pay-alerting", - "version": "1.3.14", + "version": "1.3.15", "description": "Publish alerts from Payment Hub warnings", "homepage": "https://github.com/DEFRA/ffc-pay-alerting", "main": "app/index.js", diff --git a/test/unit/alerting/generate-return-file.test.js b/test/unit/alerting/generate-return-file.test.js index 1da9939..e6445c5 100644 --- a/test/unit/alerting/generate-return-file.test.js +++ b/test/unit/alerting/generate-return-file.test.js @@ -1,33 +1,66 @@ const moment = require('moment') const { getInboundBlobClient } = require('../../../app/storage') +const { getReturnFileContent } = require('../../../app/alerting/get-return-file-content') const { generateReturnFile } = require('../../../app/alerting/generate-return-file') +const { UNKNOWN } = require('../../../app/constants/unknown') jest.mock('moment') jest.mock('../../../app/storage') +jest.mock('../../../app/alerting/get-return-file-content') describe('generateReturnFile', () => { - beforeAll(() => { + beforeEach(() => { + jest.clearAllMocks() console.info = jest.fn() }) - afterAll(() => { - console.info.mockRestore() + test('should generate and publish return file with correct content', async () => { + const mockEvent = { + data: { + frn: 'frnTest', + sbi: 'sbiTest', + agreementNumber: 'agreementNumberTest', + contractNumber: 'claimNumberTest', + claimDate: 'claimDateTest', + value: 'amountTest', + batch: 'FCAP_1234_567890123456.dat', + errorCode: 'F', + errorMessage: 'errorMessageTest' + } + } + const expectedContent = 'sbiTest,frnTest,agreementNumberTest,claimNumberTest,claimDateTest,amountTest,,,1234,F,"errorMessageTest"' + const mockBlobClient = { + upload: jest.fn().mockResolvedValue() + } + const mockMoment = { + format: jest.fn().mockReturnValue('240101010101') + } + + moment.mockReturnValue(mockMoment) + getInboundBlobClient.mockResolvedValue(mockBlobClient) + getReturnFileContent.mockReturnValue(expectedContent) + + await generateReturnFile(mockEvent) + + expect(getInboundBlobClient).toHaveBeenCalledWith('FCAP_XXXX_RPA_240101010101_frnTest_NO_RETURN_MESSAGE.dat') + expect(mockBlobClient.upload).toHaveBeenCalledWith(expectedContent, expectedContent.length) + expect(console.info).toHaveBeenCalledWith('Published FCAP_XXXX_RPA_240101010101_frnTest_NO_RETURN_MESSAGE.dat') }) - test('should generate return file and publish it', async () => { + test('should handle missing frn and use UNKNOWN constant', async () => { const mockEvent = { data: { sbi: 'sbiTest', - frn: 'frnTest', agreementNumber: 'agreementNumberTest', contractNumber: 'claimNumberTest', claimDate: 'claimDateTest', value: 'amountTest', batch: 'FCAP_1234_567890123456.dat', - message: 'errorMessageTest' + errorCode: 'F', + errorMessage: 'errorMessageTest' } } - const expectedContent = 'XXXX\r\n1\r\namountTest\r\nsbiTest,frnTest,agreementNumberTest,claimNumberTest,claimDateTest,amountTest,,,1234,F,"errorMessageTest"' + const expectedContent = 'sbiTest,frnTest,agreementNumberTest,claimNumberTest,claimDateTest,amountTest,,,1234,F,"errorMessageTest"' const mockBlobClient = { upload: jest.fn().mockResolvedValue() } @@ -37,11 +70,12 @@ describe('generateReturnFile', () => { moment.mockReturnValue(mockMoment) getInboundBlobClient.mockResolvedValue(mockBlobClient) + getReturnFileContent.mockReturnValue(expectedContent) await generateReturnFile(mockEvent) - expect(getInboundBlobClient).toHaveBeenCalledWith('FCAP_XXXX_RPA_240101010101_NO_RETURN_MESSAGE.dat') + expect(getInboundBlobClient).toHaveBeenCalledWith(`FCAP_XXXX_RPA_240101010101_${UNKNOWN}_NO_RETURN_MESSAGE.dat`) expect(mockBlobClient.upload).toHaveBeenCalledWith(expectedContent, expectedContent.length) - expect(console.info).toHaveBeenCalledWith('Published FCAP_XXXX_RPA_240101010101_NO_RETURN_MESSAGE.dat') + expect(console.info).toHaveBeenCalledWith(`Published FCAP_XXXX_RPA_240101010101_${UNKNOWN}_NO_RETURN_MESSAGE.dat`) }) }) diff --git a/test/unit/alerting/get-return-file-content.test.js b/test/unit/alerting/get-return-file-content.test.js index b2c7431..2a44da3 100644 --- a/test/unit/alerting/get-return-file-content.test.js +++ b/test/unit/alerting/get-return-file-content.test.js @@ -9,14 +9,14 @@ describe('getReturnFileContent', () => { agreementNumber: 'CASE123', contractNumber: 'CLAIM456', claimDate: '01/02/2003', - value: '1000', + value: 1000, batch: 'FCAP_5678_1234555.dat', errorCode: 'ERR001', message: 'Error message' } } - const expectedCSV = 'XXXX\r\n1\r\n1000\r\n123456,654321,CASE123,CLAIM456,01/02/2003,1000,,,5678,F,"Error message"' + const expectedCSV = 'XXXX\r\n1\r\n10\r\n123456,654321,CASE123,CLAIM456,01/02/2003,10,,,5678,F,"Error message"' const result = getReturnFileContent(event) expect(result).toBe(expectedCSV) }) @@ -30,4 +30,28 @@ describe('getReturnFileContent', () => { const result = getReturnFileContent(event) expect(result).toBe(expectedCSV) }) + + test('should handle non-integer amount correctly', () => { + const event = { + data: { + value: '1000.50' + } + } + + const expectedCSV = 'XXXX\r\n1\r\n1000.50\r\n,,,,,1000.50,,,,F,""' + const result = getReturnFileContent(event) + expect(result).toBe(expectedCSV) + }) + + test('should handle integer amount correctly', () => { + const event = { + data: { + value: 1000 + } + } + + const expectedCSV = 'XXXX\r\n1\r\n10\r\n,,,,,10,,,,F,""' + const result = getReturnFileContent(event) + expect(result).toBe(expectedCSV) + }) })