diff --git a/dops/src/app.service.ts b/dops/src/app.service.ts
index 2675df541..bd3e60b8e 100644
--- a/dops/src/app.service.ts
+++ b/dops/src/app.service.ts
@@ -109,6 +109,22 @@ export class AppService {
),
);
+ await addToCache(
+ this.cacheManager,
+ CacheKey.EMAIL_TEMPLATE_APPLICATION_APPROVED,
+ this.convertFileToString(
+ assetsPath + 'templates/application-approved.email.hbs',
+ ),
+ );
+
+ await addToCache(
+ this.cacheManager,
+ CacheKey.EMAIL_TEMPLATE_APPLICATION_REJECTED,
+ this.convertFileToString(
+ assetsPath + 'templates/application-rejected.email.hbs',
+ ),
+ );
+
const featureFlags = await this.featureFlagsService.findAll();
await addToCache(
this.cacheManager,
diff --git a/dops/src/assets/templates/application-approved.email.hbs b/dops/src/assets/templates/application-approved.email.hbs
new file mode 100644
index 000000000..95945e9da
--- /dev/null
+++ b/dops/src/assets/templates/application-approved.email.hbs
@@ -0,0 +1,138 @@
+
+
+
+
+ Application Approved
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Application {{ applicationNumber }} for plate {{ plate }} has been
+ approved and is now ready for purchase in the {{ companyName }} shopping
+ cart.
+
+
+
+
+
+
+
+
+ THIS EMAIL BOX IS NOT MONITORED AND ANY EMAILS SENT TO IT WILL NOT BE
+ ANSWERED. IF YOU HAVE ANY QUESTIONS, REQUESTS, PLEASE EMAIL:
+
+ ppcpermit@gov.bc.ca. If you have received this message in error, then please contact
+ ppcpermit@gov.bc.ca
+ and then immediately delete/discard this transmission, including all
+ attachments, without copying, distributing or disclosing same.
+
+
+
+
+
+
+
+
diff --git a/dops/src/assets/templates/application-rejected.email.hbs b/dops/src/assets/templates/application-rejected.email.hbs
new file mode 100644
index 000000000..d6675b516
--- /dev/null
+++ b/dops/src/assets/templates/application-rejected.email.hbs
@@ -0,0 +1,179 @@
+
+
+
+
+ Application Rejected
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Reason for rejection:
+
+
+
+ {{ rejectedDateTime }}
+
+
+ {{ rejectedReason }}
+
+
+
+
+
+
+
+
+
+ THIS EMAIL BOX IS NOT MONITORED AND ANY EMAILS SENT TO IT WILL NOT BE
+ ANSWERED. IF YOU HAVE ANY QUESTIONS, REQUESTS, PLEASE EMAIL:
+
+ ppcpermit@gov.bc.ca. If you have received this message in error, then please contact
+ ppcpermit@gov.bc.ca
+ and then immediately delete/discard this transmission, including all
+ attachments, without copying, distributing or disclosing same.
+
+
+
+
+
+
+
+
diff --git a/dops/src/enum/cache-key.enum.ts b/dops/src/enum/cache-key.enum.ts
index ab7cf9901..7897b590e 100644
--- a/dops/src/enum/cache-key.enum.ts
+++ b/dops/src/enum/cache-key.enum.ts
@@ -10,6 +10,8 @@ export enum CacheKey {
EMAIL_TEMPLATE_PAYMENT_RECEIPT = 'EMAIL_TEMPLATE_PAYMENT_RECEIPT',
EMAIL_TEMPLATE_COMPANY_SUSPEND = 'EMAIL_TEMPLATE_COMPANY_SUSPEND',
EMAIL_TEMPLATE_COMPANY_UNSUSPEND = 'EMAIL_TEMPLATE_COMPANY_UNSUSPEND',
+ EMAIL_TEMPLATE_APPLICATION_APPROVED = 'EMAIL_TEMPLATE_APPLICATION_APPROVED',
+ EMAIL_TEMPLATE_APPLICATION_REJECTED = 'EMAIL_TEMPLATE_APPLICATION_REJECTED',
EMAIL_TEMPLATE_ORBC_STYLE = 'EMAIL_TEMPLATE_ORBC_STYLE',
CHES_ACCESS_TOKEN = 'CHES_ACCESS_TOKEN',
CDOGS_ACCESS_TOKEN = 'CDOGS_ACCESS_TOKEN',
diff --git a/dops/src/enum/notification-template.enum.ts b/dops/src/enum/notification-template.enum.ts
index 304f130a4..40439dfa9 100644
--- a/dops/src/enum/notification-template.enum.ts
+++ b/dops/src/enum/notification-template.enum.ts
@@ -4,4 +4,6 @@ export enum NotificationTemplate {
PAYMENT_RECEIPT = 'PAYMENT_RECEIPT',
COMPANY_SUSPEND = 'COMPANY_SUSPEND',
COMPANY_UNSUSPEND = 'COMPANY_UNSUSPEND',
+ APPLICATION_APPROVED = 'APPLICATION_APPROVED',
+ APPLICATION_REJECTED = 'APPLICATION_REJECTED',
}
diff --git a/dops/src/helper/notification.helper.ts b/dops/src/helper/notification.helper.ts
index 4ce435793..5be42710d 100644
--- a/dops/src/helper/notification.helper.ts
+++ b/dops/src/helper/notification.helper.ts
@@ -39,6 +39,10 @@ export const getCacheKeyforEmailTemplate = (
return CacheKey.EMAIL_TEMPLATE_COMPANY_SUSPEND;
case NotificationTemplate.COMPANY_UNSUSPEND:
return CacheKey.EMAIL_TEMPLATE_COMPANY_UNSUSPEND;
+ case NotificationTemplate.APPLICATION_APPROVED:
+ return CacheKey.EMAIL_TEMPLATE_APPLICATION_APPROVED;
+ case NotificationTemplate.APPLICATION_REJECTED:
+ return CacheKey.EMAIL_TEMPLATE_APPLICATION_REJECTED;
default:
throw new Error('Invalid template name');
}
diff --git a/vehicles/src/common/enum/notification-template.enum.ts b/vehicles/src/common/enum/notification-template.enum.ts
index 304f130a4..40439dfa9 100644
--- a/vehicles/src/common/enum/notification-template.enum.ts
+++ b/vehicles/src/common/enum/notification-template.enum.ts
@@ -4,4 +4,6 @@ export enum NotificationTemplate {
PAYMENT_RECEIPT = 'PAYMENT_RECEIPT',
COMPANY_SUSPEND = 'COMPANY_SUSPEND',
COMPANY_UNSUSPEND = 'COMPANY_UNSUSPEND',
+ APPLICATION_APPROVED = 'APPLICATION_APPROVED',
+ APPLICATION_REJECTED = 'APPLICATION_REJECTED',
}
diff --git a/vehicles/src/common/interface/application-approved.notification.interface.ts b/vehicles/src/common/interface/application-approved.notification.interface.ts
new file mode 100644
index 000000000..114692a1b
--- /dev/null
+++ b/vehicles/src/common/interface/application-approved.notification.interface.ts
@@ -0,0 +1,5 @@
+export interface ApplicationApprovedNotification {
+ applicationNumber: string;
+ plate: string;
+ companyName: string;
+}
diff --git a/vehicles/src/common/interface/application-rejected.notification.interface.ts b/vehicles/src/common/interface/application-rejected.notification.interface.ts
new file mode 100644
index 000000000..24d1fb3d9
--- /dev/null
+++ b/vehicles/src/common/interface/application-rejected.notification.interface.ts
@@ -0,0 +1,4 @@
+export interface ApplicationRejectedNotification {
+ rejectedDateTime: string;
+ rejectedReason: string;
+}
diff --git a/vehicles/src/common/interface/notification.interface.ts b/vehicles/src/common/interface/notification.interface.ts
index 62f69c0ad..3af464c72 100644
--- a/vehicles/src/common/interface/notification.interface.ts
+++ b/vehicles/src/common/interface/notification.interface.ts
@@ -1,4 +1,6 @@
import { NotificationTemplate } from '../enum/notification-template.enum';
+import { ApplicationApprovedNotification } from './application-approved.notification.interface';
+import { ApplicationRejectedNotification } from './application-rejected.notification.interface';
import { CompanyDataNotification } from './company-data.notification.interface';
import { ProfileRegistrationDataNotification } from './profile-registration-data.notification.interface';
@@ -9,5 +11,9 @@ export interface INotification {
bcc?: string[];
fax?: string[];
templateName: NotificationTemplate;
- data?: CompanyDataNotification | ProfileRegistrationDataNotification;
+ data?:
+ | CompanyDataNotification
+ | ProfileRegistrationDataNotification
+ | ApplicationApprovedNotification
+ | ApplicationRejectedNotification;
}
diff --git a/vehicles/src/modules/case-management/case-management.service.ts b/vehicles/src/modules/case-management/case-management.service.ts
index 66b21ecc2..12fb49d88 100644
--- a/vehicles/src/modules/case-management/case-management.service.ts
+++ b/vehicles/src/modules/case-management/case-management.service.ts
@@ -764,4 +764,73 @@ export class CaseManagementService {
}
}
}
+
+ /**
+ * The method creates a notification event.
+ *
+ * @param currentUser - The current user executing the withdrawal action.
+ * @param queryRunner - Optional, existing QueryRunner instance used in the transaction process.
+ * @param caseId - Optional, the ID of the case to be withdrawn. Can be used to retrieve the existing case.
+ * @param originalCaseId - Optional, the original ID of the case to be withdrawn. Useful in lookup scenarios.
+ * @param applicationId - Optional, the ID of the permit application associated with the case.
+ * @param existingCase - Optional, the pre-loaded `Case` entity, if
+ */
+ @LogAsyncMethodExecution()
+ async createNotificationEvent({
+ currentUser,
+ queryRunner,
+ caseId,
+ originalCaseId,
+ applicationId,
+ existingCase,
+ }: {
+ currentUser: IUserJWT;
+ queryRunner?: Nullable;
+ caseId?: Nullable;
+ originalCaseId?: Nullable;
+ applicationId?: Nullable;
+ existingCase?: Nullable;
+ }): Promise {
+ let localQueryRunner = true;
+ ({ localQueryRunner, queryRunner } = await getQueryRunner({
+ queryRunner,
+ dataSource: this.dataSource,
+ }));
+ try {
+ if (!existingCase) {
+ existingCase = await this.findLatest({
+ queryRunner,
+ caseId,
+ originalCaseId,
+ applicationId,
+ });
+ }
+
+ let newEvent = this.createEvent(
+ existingCase,
+ CaseEventType.NOTIFICATION,
+ currentUser,
+ );
+ newEvent = await queryRunner.manager.save(newEvent);
+
+ if (localQueryRunner) {
+ await queryRunner.commitTransaction();
+ }
+ return await this.classMapper.mapAsync(
+ newEvent,
+ CaseEvent,
+ ReadCaseEvenDto,
+ );
+ } catch (error) {
+ if (localQueryRunner) {
+ await queryRunner.rollbackTransaction();
+ }
+ this.logger.error(error);
+ throw error;
+ } finally {
+ if (localQueryRunner) {
+ await queryRunner.release();
+ }
+ }
+ }
}
diff --git a/vehicles/src/modules/permit-application-payment/application/application.service.ts b/vehicles/src/modules/permit-application-payment/application/application.service.ts
index aeaa42f16..552abcaea 100644
--- a/vehicles/src/modules/permit-application-payment/application/application.service.ts
+++ b/vehicles/src/modules/permit-application-payment/application/application.service.ts
@@ -65,6 +65,13 @@ import { throwUnprocessableEntityException } from '../../../common/helper/except
import { ApplicationSearch } from '../../../common/enum/application-search.enum';
import { CaseStatusType } from '../../../common/enum/case-status-type.enum';
+import { INotificationDocument } from '../../../common/interface/notification-document.interface';
+import { validateEmailandFaxList } from '../../../common/helper/notification.helper';
+import { NotificationTemplate } from '../../../common/enum/notification-template.enum';
+import { PermitData } from '../../../common/interface/permit.template.interface';
+import { ApplicationApprovedNotification } from '../../../common/interface/application-approved.notification.interface';
+import { ApplicationRejectedNotification } from '../../../common/interface/application-rejected.notification.interface';
+import { convertUtcToPt } from '../../../common/helper/date-time.helper';
@Injectable()
export class ApplicationService {
@@ -1012,6 +1019,72 @@ export class ApplicationService {
},
);
await queryRunner.commitTransaction();
+ try {
+ if (
+ caseActivityType === CaseActivityType.APPROVED ||
+ caseActivityType === CaseActivityType.REJECTED
+ ) {
+ let notificationTemplate: NotificationTemplate;
+ let subject: string;
+ let notificationData:
+ | ApplicationApprovedNotification
+ | ApplicationRejectedNotification;
+
+ const permitData = JSON.parse(
+ application.permitData.permitData,
+ ) as PermitData;
+
+ if (caseActivityType === CaseActivityType.APPROVED) {
+ notificationTemplate = NotificationTemplate.APPLICATION_APPROVED;
+ subject = `onRouteBC Permit Application ${application?.applicationNumber} for Plate ${permitData?.vehicleDetails?.plate} Approved`;
+ notificationData = {
+ applicationNumber: application?.applicationNumber,
+ companyName: application?.company?.legalName,
+ plate: permitData?.vehicleDetails?.plate,
+ } as ApplicationApprovedNotification;
+ } else {
+ notificationTemplate = NotificationTemplate.APPLICATION_REJECTED;
+ subject = `onRouteBC Permit Application ${application?.applicationNumber} for Plate ${permitData?.vehicleDetails?.plate} Rejected`;
+ notificationData = {
+ rejectedDateTime: convertUtcToPt(
+ new Date(),
+ 'MMM. D, YYYY, hh:mm a Z',
+ ),
+ rejectedReason: comment,
+ } as ApplicationRejectedNotification;
+ }
+
+ const emailList = [
+ permitData?.contactDetails?.email,
+ permitData?.contactDetails?.additionalEmail,
+ application?.company?.email,
+ ];
+ const notificationDocument: INotificationDocument = {
+ templateName: notificationTemplate,
+ to: validateEmailandFaxList(emailList),
+ subject: subject,
+ data: notificationData,
+ };
+
+ await this.dopsService.notificationWithDocumentsFromDops(
+ currentUser,
+ notificationDocument,
+ false,
+ );
+
+ await this.caseManagementService.createNotificationEvent({
+ currentUser,
+ applicationId,
+ queryRunner,
+ });
+
+ await queryRunner.commitTransaction();
+ }
+ } catch (error) {
+ await queryRunner.rollbackTransaction();
+ this.logger.error(error); //Swallow Notification error
+ }
+
return result;
} catch (error) {
await queryRunner.rollbackTransaction();