diff --git a/sources/packages/backend/apps/db-migrations/src/migrations/1720568459914-InsertMinistryNotificationProvincialDailyDisbursementReport.ts b/sources/packages/backend/apps/db-migrations/src/migrations/1720568459914-InsertMinistryNotificationProvincialDailyDisbursementReport.ts new file mode 100644 index 0000000000..e8fb925996 --- /dev/null +++ b/sources/packages/backend/apps/db-migrations/src/migrations/1720568459914-InsertMinistryNotificationProvincialDailyDisbursementReport.ts @@ -0,0 +1,24 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; +import { getSQLFileData } from "../utilities/sqlLoader"; + +export class InsertMinistryNotificationProvincialDailyDisbursementReport1720568459914 + implements MigrationInterface +{ + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + getSQLFileData( + "Insert-ministry-notification-provincial-daily-disbursement-report.sql", + "NotificationMessages", + ), + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + getSQLFileData( + "Rollback-insert-ministry-notification-provincial-daily-disbursement-report.sql", + "NotificationMessages", + ), + ); + } +} diff --git a/sources/packages/backend/apps/db-migrations/src/migrations/1720568581752-UpdateDailyDisbursementFile.ts b/sources/packages/backend/apps/db-migrations/src/migrations/1720568581752-UpdateDailyDisbursementFile.ts new file mode 100644 index 0000000000..0460d794e6 --- /dev/null +++ b/sources/packages/backend/apps/db-migrations/src/migrations/1720568581752-UpdateDailyDisbursementFile.ts @@ -0,0 +1,18 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; +import { getSQLFileData } from "../utilities/sqlLoader"; + +export class UpdateDailyDisbursementFile1720568581752 + implements MigrationInterface +{ + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + getSQLFileData("Update-daily-disbursement-file.sql", "Reports"), + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + getSQLFileData("Rollback-update-daily-disbursement-file.sql", "Reports"), + ); + } +} diff --git a/sources/packages/backend/apps/db-migrations/src/sql/NotificationMessages/Insert-ministry-notification-provincial-daily-disbursement-report.sql b/sources/packages/backend/apps/db-migrations/src/sql/NotificationMessages/Insert-ministry-notification-provincial-daily-disbursement-report.sql new file mode 100644 index 0000000000..7ab6a11ad4 --- /dev/null +++ b/sources/packages/backend/apps/db-migrations/src/sql/NotificationMessages/Insert-ministry-notification-provincial-daily-disbursement-report.sql @@ -0,0 +1,8 @@ +INSERT INTO + sims.notification_messages(id, description, template_id) +VALUES + ( + 28, + 'Ministry notification for provincial daily disbursement report.', + '730db0dc-967b-4adb-afa2-38235ad9f051' + ); \ No newline at end of file diff --git a/sources/packages/backend/apps/db-migrations/src/sql/NotificationMessages/Rollback-insert-ministry-notification-provincial-daily-disbursement-report.sql b/sources/packages/backend/apps/db-migrations/src/sql/NotificationMessages/Rollback-insert-ministry-notification-provincial-daily-disbursement-report.sql new file mode 100644 index 0000000000..278db71222 --- /dev/null +++ b/sources/packages/backend/apps/db-migrations/src/sql/NotificationMessages/Rollback-insert-ministry-notification-provincial-daily-disbursement-report.sql @@ -0,0 +1,4 @@ +DELETE FROM + sims.notification_messages +WHERE + ID = 28; \ No newline at end of file diff --git a/sources/packages/backend/apps/db-migrations/src/sql/Reports/Rollback-update-daily-disbursement-file.sql b/sources/packages/backend/apps/db-migrations/src/sql/Reports/Rollback-update-daily-disbursement-file.sql new file mode 100644 index 0000000000..c0543a08b2 --- /dev/null +++ b/sources/packages/backend/apps/db-migrations/src/sql/Reports/Rollback-update-daily-disbursement-file.sql @@ -0,0 +1,20 @@ +UPDATE + sims.report_configs +SET + report_sql = ( + 'select + sum(dr.total_disbursed_amount) as "BC Student Loan", + sum(drv.grant_amount) as "BC Student Grant", + ( + sum(dr.total_disbursed_amount) + sum(drv.grant_amount) + ) as "BC Total", + count(dr.id) as "Total Records" + from + sims.disbursement_receipts dr + inner join sims.disbursement_receipt_values drv on dr.id = drv.disbursement_receipt_id + where + dr.batch_run_date = :batchRunDate + and dr.funding_type = ''BC''' + ) +WHERE + report_name = 'Daily_Disbursement_File'; \ No newline at end of file diff --git a/sources/packages/backend/apps/db-migrations/src/sql/Reports/Update-daily-disbursement-file.sql b/sources/packages/backend/apps/db-migrations/src/sql/Reports/Update-daily-disbursement-file.sql new file mode 100644 index 0000000000..46f4a24200 --- /dev/null +++ b/sources/packages/backend/apps/db-migrations/src/sql/Reports/Update-daily-disbursement-file.sql @@ -0,0 +1,105 @@ +UPDATE + sims.report_configs +SET + report_sql = ( + 'WITH disbursement_receipt_dataset AS ( + SELECT + disbursement_receipts.id, + disbursement_receipts.total_disbursed_amount, + disbursement_receipts.total_disbursed_grant_amount, + disbursement_receipts.funding_type, + disbursement_receipts.file_date, + disbursement_receipts.batch_run_date, + disbursement_receipts.sequence_number + FROM + sims.disbursement_receipts disbursement_receipts + WHERE + disbursement_receipts.funding_type IN (''BC'', ''BP'') + AND disbursement_receipts.file_date = :fileDate + AND disbursement_receipts.sequence_number = :sequenceNumber + ) + SELECT + SUM( + disbursement_receipts."Full Time BC Student Loan" + ) AS "Full Time BC Student Loan", + SUM( + disbursement_receipts."Full Time BC Student Grant" + ) AS "Full Time BC Student Grant", + SUM(disbursement_receipts."Full Time BC Total") AS "Full Time BC Total", + SUM( + disbursement_receipts."Part Time BC Student Grant" + ) AS "Part Time BC Student Grant", + SUM(disbursement_receipts."Part Time BC Total") AS "Part Time BC Total", + SUM(disbursement_receipts."BC Total") as "BC Total", + SUM(disbursement_receipts."Total Records") AS "Total Records", + CAST( + disbursement_receipts."File Date" AS varchar + ) AS "File Date", + CAST( + disbursement_receipts."Batch Run Date" AS varchar + ) AS "Batch Run Date", + disbursement_receipts."Sequence Number" + FROM + ( + SELECT + SUM( + full_time_disbursement_receipts.total_disbursed_amount + ) AS "Full Time BC Student Loan", + SUM( + full_time_disbursement_receipts.total_disbursed_grant_amount + ) AS "Full Time BC Student Grant", + SUM( + full_time_disbursement_receipts.total_disbursed_amount + ) AS "Full Time BC Total", + 0 AS "Part Time BC Student Grant", + 0 AS "Part Time BC Total", + SUM( + full_time_disbursement_receipts.total_disbursed_amount + ) AS "BC Total", + COUNT(full_time_disbursement_receipts.id) AS "Total Records", + full_time_disbursement_receipts.file_date AS "File Date", + full_time_disbursement_receipts.batch_run_date AS "Batch Run Date", + full_time_disbursement_receipts.sequence_number AS "Sequence Number" + FROM + disbursement_receipt_dataset full_time_disbursement_receipts + WHERE + full_time_disbursement_receipts.funding_type = ''BC'' + GROUP BY + "File Date", + "Batch Run Date", + "Sequence Number" + UNION + ALL + SELECT + 0 AS "Full Time BC Student Loan", + 0 AS "Full Time BC Student Grant", + 0 AS "Full Time BC Total", + SUM( + part_time_disbursement_receipts.total_disbursed_grant_amount + ) AS "Part Time BC Student Grant", + SUM( + part_time_disbursement_receipts.total_disbursed_amount + ) AS "Part Time BC Total", + SUM( + part_time_disbursement_receipts.total_disbursed_amount + ) AS "BC Total", + COUNT(part_time_disbursement_receipts.id) AS "Total Records", + part_time_disbursement_receipts.file_date as "File Date", + part_time_disbursement_receipts.batch_run_date as "Batch Run Date", + part_time_disbursement_receipts.sequence_number as "Sequence Number" + FROM + disbursement_receipt_dataset part_time_disbursement_receipts + WHERE + part_time_disbursement_receipts.funding_type = ''BP'' + GROUP BY + "File Date", + "Batch Run Date", + "Sequence Number" + ) AS disbursement_receipts + GROUP BY + disbursement_receipts."File Date", + disbursement_receipts."Batch Run Date", + disbursement_receipts."Sequence Number";' + ) +WHERE + report_name = 'Daily_Disbursement_File'; \ No newline at end of file diff --git a/sources/packages/backend/apps/queue-consumers/src/processors/schedulers/esdc-integration/ecert-integration/_tests_/disbursement-receipts-integration.scheduler.e2e-spec.ts b/sources/packages/backend/apps/queue-consumers/src/processors/schedulers/esdc-integration/ecert-integration/_tests_/disbursement-receipts-integration.scheduler.e2e-spec.ts index 55157c2221..630d500658 100644 --- a/sources/packages/backend/apps/queue-consumers/src/processors/schedulers/esdc-integration/ecert-integration/_tests_/disbursement-receipts-integration.scheduler.e2e-spec.ts +++ b/sources/packages/backend/apps/queue-consumers/src/processors/schedulers/esdc-integration/ecert-integration/_tests_/disbursement-receipts-integration.scheduler.e2e-spec.ts @@ -2,6 +2,7 @@ import { ApplicationStatus, DisbursementReceipt, DisbursementReceiptValue, + NotificationMessageType, OfferingIntensity, RECEIPT_FUNDING_TYPE_FEDERAL, RECEIPT_FUNDING_TYPE_PROVINCIAL_FULL_TIME, @@ -28,6 +29,7 @@ import { DeepMocked } from "@golevelup/ts-jest"; import * as Client from "ssh2-sftp-client"; import { DisbursementReceiptsFileIntegrationScheduler } from "../disbursement-receipts-integration.scheduler"; import * as path from "path"; +import { In, IsNull } from "typeorm"; const FEDERAL_PROVINCIAL_FULL_TIME_FILE = "EDU.PBC.DIS-federal-provincial-full-time.txt"; @@ -35,6 +37,10 @@ const FEDERAL_PROVINCIAL_PART_TIME_FILE = "EDU.PBC.DIS-federal-provincial-part-time.txt"; const FEDERAL_ONLY_FULL_TIME_FILE = "EDU.PBC.DIS-federal-only-full-time.txt"; const SHARED_DOCUMENT_NUMBER = 989898; +const BATCH_RUN_DATE = "2024-01-30"; +const FILE_DATE = "2024-01-31"; +const SEQUENCE_NUMBER = 3228; +const TEST_EMAIL = "dummy@some.domain"; describe( describeQueueProcessorRootTest( @@ -59,6 +65,13 @@ describe( sftpClientMock = sshClientMock; // Processor under test. processor = app.get(DisbursementReceiptsFileIntegrationScheduler); + // Insert fake email contact to send ministry email. + await db.notificationMessage.update( + { + id: NotificationMessageType.MinistryNotificationProvincialDailyDisbursementReceipt, + }, + { emailContacts: [TEST_EMAIL] }, + ); }); beforeEach(async () => { @@ -68,6 +81,45 @@ describe( { documentNumber: SHARED_DOCUMENT_NUMBER }, { documentNumber: 0 }, ); + // Remove disbursement receipt records associated with FILE_DATE + // and related disbursement receipt values records. + const disbursementReceipts = await db.disbursementReceipt.find({ + select: { id: true, disbursementReceiptValues: { id: true } }, + relations: { disbursementReceiptValues: true }, + where: { fileDate: FILE_DATE, sequenceNumber: SEQUENCE_NUMBER }, + }); + const disbursementReceiptValues = await db.disbursementReceiptValue.find({ + select: { id: true, disbursementReceipt: { id: true } }, + relations: { disbursementReceipt: true }, + where: { + disbursementReceipt: { + id: In( + disbursementReceipts.map( + (disbursementReceipt) => disbursementReceipt.id, + ), + ), + }, + }, + }); + await db.disbursementReceiptValue.delete({ + id: In( + disbursementReceiptValues.map( + (disbursementReceiptValue) => disbursementReceiptValue.id, + ), + ), + }); + await db.disbursementReceipt.delete({ + fileDate: FILE_DATE, + }); + // Update dateSent to new Date for notification records. + await db.notification.update( + { + notificationMessage: { + id: NotificationMessageType.MinistryNotificationProvincialDailyDisbursementReceipt, + }, + }, + { dateSent: new Date() }, + ); }); it("Should log 'Invalid file header' error when the header has a record code different than 'F'.", async () => { @@ -189,6 +241,8 @@ describe( `Record with document number ${SHARED_DOCUMENT_NUMBER} at line 2 inserted successfully.`, `Record with document number ${SHARED_DOCUMENT_NUMBER} at line 3 inserted successfully.`, `Processing file ${downloadedFile} completed.`, + `Processing provincial daily disbursement CSV file on ${FILE_DATE}.`, + "Provincial daily disbursement CSV report generated.", ], errorsSummary: [], }, @@ -203,8 +257,8 @@ describe( // Header details. expect(feReceipt).toEqual( expect.objectContaining({ - batchRunDate: "2024-01-30", - fileDate: "2024-01-31", + batchRunDate: BATCH_RUN_DATE, + fileDate: FILE_DATE, sequenceNumber: 3228, }), ); @@ -230,8 +284,8 @@ describe( // Header details. expect(bcReceipt).toEqual( expect.objectContaining({ - batchRunDate: "2024-01-30", - fileDate: "2024-01-31", + batchRunDate: BATCH_RUN_DATE, + fileDate: FILE_DATE, sequenceNumber: 3228, }), ); @@ -248,6 +302,47 @@ describe( expect(bdReceiptAwards).toStrictEqual({ BCSG: 599, }); + // Notification record. + const createdNotification = await db.notification.findOne({ + select: { + id: true, + dateSent: true, + messagePayload: true, + notificationMessage: { id: true, templateId: true }, + }, + relations: { notificationMessage: true }, + where: { + dateSent: IsNull(), + notificationMessage: { + id: NotificationMessageType.MinistryNotificationProvincialDailyDisbursementReceipt, + }, + }, + }); + expect(createdNotification.messagePayload).toStrictEqual({ + template_id: createdNotification.notificationMessage.templateId, + email_address: TEST_EMAIL, + personalisation: { + application_file: { + file: + "RnVsbCBUaW1lIEJDIFN0dWRlbnQgTG9hbixGdWxsIFRpbWUgQkMgU3R1ZGVudCBHcmFudCxGdWxsIFRpbWUgQkMgVG90YWwsUGFydCBUaW1lIEJDIFN0dWRlbnQgR3JhbnQsUGFydCBUaW1lIEJDIFRvdGFsLEJDIFRvdGFsLFRvdGFsIFJlY29yZHMsRmlsZSBEYXR" + + "lLEJhdGNoIFJ1biBEYXRlLFNlcXVlbmNlIE51bWJlcg0KMTIzLjAwLDc2MC4wMCwxMjMuMDAsMCwwLDEyMy4wMCwxLDIwMjQtMDEtMzEsMjAyNC0wMS0zMCwzMjI4", + filename: `Daily_Disbursement_File_${FILE_DATE}_${SEQUENCE_NUMBER}.csv`, + sending_method: "attach", + }, + }, + }); + // Verify the file content as expected. + const file = + createdNotification.messagePayload["personalisation"][ + "application_file" + ]["file"]; + const fileContent = Buffer.from(file, "base64").toString("ascii"); + expect(fileContent).toContain( + "Full Time BC Student Loan,Full Time BC Student Grant,Full Time BC Total,Part Time BC Student Grant,Part Time BC Total,BC Total,Total Records,File Date,Batch Run Date,Sequence Number", + ); + expect(fileContent).toContain( + "123.00,760.00,123.00,0,0,123.00,1,2024-01-31,2024-01-30,3228", + ); }); it("Should import disbursement receipt file and create only federal awards receipt with proper awards code mappings for a full-time application when the file contains only federal receipt.", async () => { @@ -281,6 +376,7 @@ describe( `Processing file ${downloadedFile}.`, `Record with document number ${SHARED_DOCUMENT_NUMBER} at line 2 inserted successfully.`, `Processing file ${downloadedFile} completed.`, + `Processing provincial daily disbursement CSV file on ${FILE_DATE}.`, ], errorsSummary: [], }, @@ -312,6 +408,23 @@ describe( CSGP: 499, XYZ: 444, }); + // Notification record. + const notification = await db.notification.findOne({ + select: { + id: true, + dateSent: true, + messagePayload: true, + notificationMessage: { id: true, templateId: true }, + }, + relations: { notificationMessage: true }, + where: { + dateSent: IsNull(), + notificationMessage: { + id: NotificationMessageType.MinistryNotificationProvincialDailyDisbursementReceipt, + }, + }, + }); + expect(notification).toBe(null); }); it("Should import disbursement receipt file and create federal and provincial awards receipts with proper awards code mappings for a part-time application when the file contains federal and provincial receipts.", async () => { @@ -346,6 +459,8 @@ describe( `Record with document number ${SHARED_DOCUMENT_NUMBER} at line 2 inserted successfully.`, `Record with document number ${SHARED_DOCUMENT_NUMBER} at line 3 inserted successfully.`, `Processing file ${downloadedFile} completed.`, + `Processing provincial daily disbursement CSV file on ${FILE_DATE}.`, + "Provincial daily disbursement CSV report generated.", ], errorsSummary: [], }, @@ -360,8 +475,8 @@ describe( // Header details. expect(feReceipt).toEqual( expect.objectContaining({ - batchRunDate: "2024-01-30", - fileDate: "2024-01-31", + batchRunDate: BATCH_RUN_DATE, + fileDate: FILE_DATE, sequenceNumber: 3228, }), ); @@ -387,8 +502,8 @@ describe( // Header details. expect(bpReceipt).toEqual( expect.objectContaining({ - batchRunDate: "2024-01-30", - fileDate: "2024-01-31", + batchRunDate: BATCH_RUN_DATE, + fileDate: FILE_DATE, sequenceNumber: 3228, }), ); @@ -405,6 +520,57 @@ describe( expect(bdReceiptAwards).toStrictEqual({ BCSG: 600, }); + // Notification record. + const createdNotification = await db.notification.findOne({ + select: { + id: true, + dateSent: true, + messagePayload: true, + notificationMessage: { id: true, templateId: true }, + }, + relations: { notificationMessage: true }, + where: { + dateSent: IsNull(), + notificationMessage: { + id: NotificationMessageType.MinistryNotificationProvincialDailyDisbursementReceipt, + }, + }, + }); + expect(createdNotification.messagePayload).toStrictEqual({ + template_id: createdNotification.notificationMessage.templateId, + email_address: TEST_EMAIL, + personalisation: { + application_file: { + file: + "RnVsbCBUaW1lIEJDIFN0dWRlbnQgTG9hbixGdWxsIFRpbWUgQkMgU3R1ZGVudCBHcmFudCxGdWxsIFRpbWUgQkMgVG90YWwsUGFydCBUaW1lIEJDIFN0dWRlbnQgR3JhbnQsUGFydCBUaW1lIEJDIFRvdGFsLEJDIFRvdGFsLFRvdGFsIFJlY29yZHMsRmlsZSBE" + + "YXRlLEJhdGNoIFJ1biBEYXRlLFNlcXVlbmNlIE51bWJlcg0KMCwwLDAsNzYwLjAwLDEzMi4wMCwxMzIuMDAsMSwyMDI0LTAxLTMxLDIwMjQtMDEtMzAsMzIyOA==", + filename: "Daily_Disbursement_File_2024-01-31_3228.csv", + sending_method: "attach", + }, + }, + }); + // Verify the file content as expected. + const file = + createdNotification.messagePayload["personalisation"][ + "application_file" + ]["file"]; + const fileContent = Buffer.from(file, "base64").toString("ascii"); + expect(fileContent).toContain( + "Full Time BC Student Loan,Full Time BC Student Grant,Full Time BC Total,Part Time BC Student Grant,Part Time BC Total,BC Total,Total Records,File Date,Batch Run Date,Sequence Number", + ); + expect(fileContent).toContain( + "0,0,0,760.00,132.00,132.00,1,2024-01-31,2024-01-30,3228", + ); + }); + + afterAll(async () => { + // Set email contact to null for provincial daily disbursement receipt notification message. + await db.notificationMessage.update( + { + id: NotificationMessageType.MinistryNotificationProvincialDailyDisbursementReceipt, + }, + { emailContacts: null }, + ); }); /** diff --git a/sources/packages/backend/libs/integrations/src/esdc-integration/disbursement-receipt-integration/disbursement-receipt.integration.service.ts b/sources/packages/backend/libs/integrations/src/esdc-integration/disbursement-receipt-integration/disbursement-receipt.integration.service.ts index 62207eca9c..4357e88778 100644 --- a/sources/packages/backend/libs/integrations/src/esdc-integration/disbursement-receipt-integration/disbursement-receipt.integration.service.ts +++ b/sources/packages/backend/libs/integrations/src/esdc-integration/disbursement-receipt-integration/disbursement-receipt.integration.service.ts @@ -1,5 +1,5 @@ import { Injectable } from "@nestjs/common"; -import { ConfigService, ESDCIntegrationConfig } from "@sims/utilities/config"; +import { ConfigService } from "@sims/utilities/config"; import { DisbursementReceiptDownloadResponse, DisbursementReceiptRecordType, @@ -7,15 +7,13 @@ import { import { DisbursementReceiptHeader } from "./disbursement-receipt-files/disbursement-receipt-file-header"; import { DisbursementReceiptFooter } from "./disbursement-receipt-files/disbursement-receipt-file-footer"; import { DisbursementReceiptDetail } from "./disbursement-receipt-files/disbursement-receipt-file-detail"; -import { getFileNameAsCurrentTimestamp } from "@sims/utilities"; +import { getISODateOnlyString } from "@sims/utilities"; import { SFTPIntegrationBase, SshService } from "@sims/integrations/services"; @Injectable() export class DisbursementReceiptIntegrationService extends SFTPIntegrationBase { - private readonly esdcConfig: ESDCIntegrationConfig; constructor(config: ConfigService, sshService: SshService) { super(config.zoneBSFTP, sshService); - this.esdcConfig = config.esdcIntegration; } /** @@ -63,20 +61,19 @@ export class DisbursementReceiptIntegrationService extends SFTPIntegrationBase { + result.processSummary.push( + `Processing provincial daily disbursement CSV file on ${getISODateOnlyString( + fileDate, + )}.`, + ); + + try { + // Populate the reportName and fileDate and sequenceNumber to the reportsFilterMode. + const reportFilterModel: ReportsFilterModel = { + reportName: DAILY_DISBURSEMENT_REPORT_NAME, + params: { + fileDate, + sequenceNumber, + }, + }; + + // Fetch the reports data and convert them into CSV. + const dailyDisbursementsRecordsInCSV = + await this.reportService.getReportDataAsCSV(reportFilterModel); + + if (dailyDisbursementsRecordsInCSV === "") { + return; + } + + // Create the file name for the daily disbursement report. + const disbursementFileName = + this.integrationService.createDisbursementFileName( + DAILY_DISBURSEMENT_REPORT_NAME, + fileDate, + sequenceNumber, + ); + + // Send the Daily Disbursement Report content and file via email. + await this.notificationActionsService.saveProvincialDailyDisbursementReportProcessingNotification( + { + attachmentFileContent: dailyDisbursementsRecordsInCSV, + fileName: disbursementFileName, + }, + ); + result.processSummary.push( + "Provincial daily disbursement CSV report generated.", + ); + this.logger.log( + "Completed provincial daily disbursement report generation.", + ); + } catch (error) { + this.logger.error(error); + result.errorsSummary.push( + "Error while generating provincial daily disbursement CSV report file.", + ); + result.errorsSummary.push(error); + } + } + @InjectLogger() logger: LoggerService; } diff --git a/sources/packages/backend/libs/services/src/notifications/notification/notification-actions.service.ts b/sources/packages/backend/libs/services/src/notifications/notification/notification-actions.service.ts index c9475b6cde..b75a9b9ca8 100644 --- a/sources/packages/backend/libs/services/src/notifications/notification/notification-actions.service.ts +++ b/sources/packages/backend/libs/services/src/notifications/notification/notification-actions.service.ts @@ -29,6 +29,7 @@ import { ApplicationOfferingChangeRequestApprovedByStudentNotification, PartialStudentMatchNotification, ECertFeedbackFileErrorNotification, + DailyDisbursementReportProcessingNotification, } from ".."; import { NotificationService } from "./notification.service"; import { InjectLogger, LoggerService } from "@sims/utilities/logger"; @@ -1157,6 +1158,47 @@ export class NotificationActionsService { ); } + /** + * Creates Provincial Daily Disbursement Report file processing notifications. + * Currently multiple notifications are created as integration contacts + * can be multiple. + * @param notification notification details. + */ + async saveProvincialDailyDisbursementReportProcessingNotification( + notification: DailyDisbursementReportProcessingNotification, + ): Promise { + const auditUser = this.systemUsersService.systemUser; + const { templateId, emailContacts } = + await this.assertNotificationMessageDetails( + NotificationMessageType.MinistryNotificationProvincialDailyDisbursementReceipt, + ); + if (!emailContacts?.length) { + return; + } + + const ministryNotificationsToSend = emailContacts.map((emailContact) => ({ + userId: auditUser.id, + messageType: + NotificationMessageType.MinistryNotificationProvincialDailyDisbursementReceipt, + messagePayload: { + email_address: emailContact, + template_id: templateId, + personalisation: { + application_file: { + file: base64Encode(notification.attachmentFileContent), + filename: notification.fileName, + sending_method: "attach", + }, + }, + } as NotificationEmailMessage, + })); + + await this.notificationService.saveNotifications( + ministryNotificationsToSend, + auditUser.id, + ); + } + /** * Asserts the notification message details of a notification message. * @param notificationMessageTypeId id of the user who will receive the message. diff --git a/sources/packages/backend/libs/services/src/notifications/notification/notification.model.ts b/sources/packages/backend/libs/services/src/notifications/notification/notification.model.ts index 6b3b84ea91..6babbf2516 100644 --- a/sources/packages/backend/libs/services/src/notifications/notification/notification.model.ts +++ b/sources/packages/backend/libs/services/src/notifications/notification/notification.model.ts @@ -171,3 +171,8 @@ export interface InstitutionAddsPendingOfferingNotification { offeringName: string; institutionPrimaryEmail: string; } + +export interface DailyDisbursementReportProcessingNotification { + attachmentFileContent: string; + fileName: string; +} diff --git a/sources/packages/backend/libs/sims-db/src/entities/notification.model.ts b/sources/packages/backend/libs/sims-db/src/entities/notification.model.ts index a677f1ffa9..0d2558158f 100644 --- a/sources/packages/backend/libs/sims-db/src/entities/notification.model.ts +++ b/sources/packages/backend/libs/sims-db/src/entities/notification.model.ts @@ -205,4 +205,8 @@ export enum NotificationMessageType { * eCert Feedback File has errors. */ ECertFeedbackFileErrorNotification = 27, + /** + * Ministry Provincial Daily Disbursement Receipt. + */ + MinistryNotificationProvincialDailyDisbursementReceipt = 28, }