From fe2faaf9f8c1b1629af93cdc8b177a6c5bdb262d Mon Sep 17 00:00:00 2001 From: zainZzKk <51957827+Zainzzkk@users.noreply.github.com> Date: Mon, 27 Jan 2025 12:30:58 +0000 Subject: [PATCH] feat(FN-3691): cron job to delete old record correction transient form data (#4168) --- .env.sample | 2 + .github/workflows/test.yml | 1 + docker-compose.yml | 1 + .../index.test.ts | 92 +++++++++++++++++++ .../index.ts | 23 +++++ .../src/cron-scheduler-jobs/index.ts | 8 +- ...ection-request-transient-form-data.repo.ts | 14 ++- 7 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 dtfs-central-api/src/cron-scheduler-jobs/delete-correction-request-transient-form-data/index.test.ts create mode 100644 dtfs-central-api/src/cron-scheduler-jobs/delete-correction-request-transient-form-data/index.ts diff --git a/.env.sample b/.env.sample index 05a0d97a39..d20ff81e16 100644 --- a/.env.sample +++ b/.env.sample @@ -67,6 +67,8 @@ UTILISATION_REPORT_CREATION_FAILURE_EMAIL_ADDRESS= DEAL_CANCELLATION_SCHEDULE='* 2 * * *' +RECORD_CORRECTION_TRANSIENT_FORM_DATA_DELETE_SCHEDULE='0 2 * * *' + # STORAGE AZURE_PORTAL_STORAGE_ACCOUNT= AZURE_PORTAL_STORAGE_ACCESS_KEY= diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bb0034776a..57c740d3f4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -167,6 +167,7 @@ env: ENTRA_ID_CLIENT_SECRET: ${{ vars.ENTRA_ID_CLIENT_SECRET }} ENTRA_ID_REDIRECT_URL: ${{ vars.ENTRA_ID_REDIRECT_URL }} DEAL_CANCELLATION_SCHEDULE: ${{ vars.DEAL_CANCELLATION_SCHEDULE }} + RECORD_CORRECTION_TRANSIENT_FORM_DATA_DELETE_SCHEDULE: ${{ vars.RECORD_CORRECTION_TRANSIENT_FORM_DATA_DELETE_SCHEDULE }} jobs: # 1. Setup test infrastructure diff --git a/docker-compose.yml b/docker-compose.yml index a7b02f3730..a1c63d95b8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -89,6 +89,7 @@ services: - FF_TFM_DEAL_CANCELLATION_ENABLED - DEAL_CANCELLATION_SCHEDULE - FF_PORTAL_FACILITY_AMENDMENTS_ENABLED + - RECORD_CORRECTION_TRANSIENT_FORM_DATA_DELETE_SCHEDULE trade-finance-manager-ui: build: diff --git a/dtfs-central-api/src/cron-scheduler-jobs/delete-correction-request-transient-form-data/index.test.ts b/dtfs-central-api/src/cron-scheduler-jobs/delete-correction-request-transient-form-data/index.test.ts new file mode 100644 index 0000000000..629cdb99dd --- /dev/null +++ b/dtfs-central-api/src/cron-scheduler-jobs/delete-correction-request-transient-form-data/index.test.ts @@ -0,0 +1,92 @@ +import { LessThan } from 'typeorm'; +import { deleteCorrectionRequestTransientFormData, deleteCorrectionRequestTransientFormDataJob } from '.'; +import { FeeRecordCorrectionRequestTransientFormDataRepo } from '../../repositories/fee-record-correction-request-transient-form-data-repo/fee-record-correction-request-transient-form-data.repo'; + +describe('delete-record-correction-request-transient-form-data', () => { + jest.mock('typeorm', () => ({ + LessThan: jest.fn(), + })); + + const mockDelete = jest.fn(); + console.error = jest.fn(); + + beforeAll(() => { + jest.useFakeTimers(); + }); + + afterAll(() => { + jest.useRealTimers(); + }); + + describe('deleteRecordCorrectionRequestTransientFormData', () => { + beforeEach(() => { + jest.resetAllMocks(); + FeeRecordCorrectionRequestTransientFormDataRepo.delete = mockDelete; + jest.useFakeTimers().setSystemTime(new Date('2025-01-02 12:10:00')); + }); + + it('should delete records older than one day', async () => { + await deleteCorrectionRequestTransientFormData(); + + expect(mockDelete).toHaveBeenCalledTimes(1); + + expect(mockDelete).toHaveBeenCalledWith({ + lastUpdatedAt: LessThan(new Date('2025-01-01:12:10:00')), + }); + }); + + it('should delete records older than one day if it is the first day of the month', async () => { + jest.useFakeTimers().setSystemTime(new Date('2025-01-01 12:10:00')); + + await deleteCorrectionRequestTransientFormData(); + + expect(mockDelete).toHaveBeenCalledTimes(1); + + expect(mockDelete).toHaveBeenCalledWith({ + lastUpdatedAt: LessThan(new Date('2024-12-31:12:10:00')), + }); + }); + + it('should throw an error if deletion fails', async () => { + const errorMessage = 'This is an error'; + const error = new Error(errorMessage); + jest.mocked(mockDelete).mockRejectedValue(error); + + await deleteCorrectionRequestTransientFormData(); + + expect(console.error).toHaveBeenCalledTimes(1); + expect(console.error).toHaveBeenCalledWith( + 'Error deleting old transient record correction requests - deleteCorrectionRequestTransientFormDataJob CRON job: %o', + error, + ); + }); + }); + + describe('deleteRecordCorrectionRequestTransientFormDataJob', () => { + beforeEach(() => { + jest.resetAllMocks(); + FeeRecordCorrectionRequestTransientFormDataRepo.delete = mockDelete; + jest.useFakeTimers().setSystemTime(new Date('2025-01-02 12:10:00')); + }); + + it('should be scheduled to run', () => { + expect(deleteCorrectionRequestTransientFormDataJob.cronExpression).toEqual(process.env.RECORD_CORRECTION_TRANSIENT_FORM_DATA_DELETE_SCHEDULE); + }); + + it('should have the correct description', () => { + expect(deleteCorrectionRequestTransientFormDataJob.description).toEqual('Delete record correction transient form data older than 1 day'); + }); + + it('should call FeeRecordCorrectionRequestTransientFormDataRepo.delete', async () => { + // Act + await deleteCorrectionRequestTransientFormDataJob.task('manual'); + + // Assert + expect(mockDelete).toHaveBeenCalledTimes(1); + + expect(mockDelete).toHaveBeenCalledWith({ + lastUpdatedAt: LessThan(new Date('2025-01-01:12:10:00')), + }); + }); + }); +}); diff --git a/dtfs-central-api/src/cron-scheduler-jobs/delete-correction-request-transient-form-data/index.ts b/dtfs-central-api/src/cron-scheduler-jobs/delete-correction-request-transient-form-data/index.ts new file mode 100644 index 0000000000..6eaf3234b6 --- /dev/null +++ b/dtfs-central-api/src/cron-scheduler-jobs/delete-correction-request-transient-form-data/index.ts @@ -0,0 +1,23 @@ +import { asString, CronSchedulerJob } from '@ukef/dtfs2-common'; +import { FeeRecordCorrectionRequestTransientFormDataRepo } from '../../repositories/fee-record-correction-request-transient-form-data-repo'; + +const { RECORD_CORRECTION_TRANSIENT_FORM_DATA_DELETE_SCHEDULE } = process.env; + +/** + * Deletes record correction request transient form data more than 1 day old + */ +export const deleteCorrectionRequestTransientFormData = async (): Promise => { + try { + console.info('Getting and deleting old transient record correction requests - deleteCorrectionRequestTransientFormDataJob CRON job'); + + await FeeRecordCorrectionRequestTransientFormDataRepo.deleteByLastUpdatedOlderThanOneDayAgo(); + } catch (error) { + console.error('Error deleting old transient record correction requests - deleteCorrectionRequestTransientFormDataJob CRON job: %o', error); + } +}; + +export const deleteCorrectionRequestTransientFormDataJob: CronSchedulerJob = { + cronExpression: asString(RECORD_CORRECTION_TRANSIENT_FORM_DATA_DELETE_SCHEDULE, 'RECORD_CORRECTION_TRANSIENT_FORM_DATA_DELETE_SCHEDULE'), + description: 'Delete record correction transient form data older than 1 day', + task: deleteCorrectionRequestTransientFormData, +}; diff --git a/dtfs-central-api/src/cron-scheduler-jobs/index.ts b/dtfs-central-api/src/cron-scheduler-jobs/index.ts index 1cae86ec69..c6d9de4e43 100644 --- a/dtfs-central-api/src/cron-scheduler-jobs/index.ts +++ b/dtfs-central-api/src/cron-scheduler-jobs/index.ts @@ -2,5 +2,11 @@ import { CronSchedulerJob } from '@ukef/dtfs2-common'; import { createUtilisationReportForBanksJob } from './create-utilisation-reports'; import { deleteCompleteAcbsDurableFunctionLogsJob } from './delete-acbs-durable-function-logs'; import { cancelDealJob } from './deal-cancellation/cancel-deal-job'; +import { deleteCorrectionRequestTransientFormDataJob } from './delete-correction-request-transient-form-data'; -export const cronSchedulerJobs: CronSchedulerJob[] = [createUtilisationReportForBanksJob, deleteCompleteAcbsDurableFunctionLogsJob, cancelDealJob]; +export const cronSchedulerJobs: CronSchedulerJob[] = [ + createUtilisationReportForBanksJob, + deleteCompleteAcbsDurableFunctionLogsJob, + cancelDealJob, + deleteCorrectionRequestTransientFormDataJob, +]; diff --git a/dtfs-central-api/src/repositories/fee-record-correction-request-transient-form-data-repo/fee-record-correction-request-transient-form-data.repo.ts b/dtfs-central-api/src/repositories/fee-record-correction-request-transient-form-data-repo/fee-record-correction-request-transient-form-data.repo.ts index 259a1b16dc..94e5adeee0 100644 --- a/dtfs-central-api/src/repositories/fee-record-correction-request-transient-form-data-repo/fee-record-correction-request-transient-form-data.repo.ts +++ b/dtfs-central-api/src/repositories/fee-record-correction-request-transient-form-data-repo/fee-record-correction-request-transient-form-data.repo.ts @@ -1,6 +1,6 @@ import { SqlDbDataSource } from '@ukef/dtfs2-common/sql-db-connection'; import { FeeRecordCorrectionRequestTransientFormDataEntity } from '@ukef/dtfs2-common'; -import { EntityManager } from 'typeorm'; +import { EntityManager, LessThan } from 'typeorm'; /** * Repository for managing fee record correction request transient form data. @@ -34,6 +34,18 @@ export const FeeRecordCorrectionRequestTransientFormDataRepo = SqlDbDataSource.g }); }, + /** + * deletes the transient form data which is older than a day old + */ + async deleteByLastUpdatedOlderThanOneDayAgo(): Promise { + const today = new Date(); + const oneDayAgo = today.setDate(today.getDate() - 1); + + await this.delete({ + lastUpdatedAt: LessThan(new Date(oneDayAgo)), + }); + }, + withTransaction(transactionEntityManager: EntityManager) { const transactionRepository = transactionEntityManager.getRepository(FeeRecordCorrectionRequestTransientFormDataEntity);