From 29a8e23c4349f4aabd8c09cfd637c797d6ef5848 Mon Sep 17 00:00:00 2001 From: Vins Date: Tue, 26 Sep 2023 11:39:21 +0200 Subject: [PATCH] Notif cron --- .../notifications/NotificationBuilder.ts | 189 +++++++++++------- src/entries/Cron.ts | 1 + .../common/CronService/CronService.ts | 58 +++++- .../MailchimpService/MailchimpService.ts | 15 +- 4 files changed, 178 insertions(+), 85 deletions(-) diff --git a/src/common/notifications/NotificationBuilder.ts b/src/common/notifications/NotificationBuilder.ts index e9a86877..8b807657 100644 --- a/src/common/notifications/NotificationBuilder.ts +++ b/src/common/notifications/NotificationBuilder.ts @@ -1,85 +1,140 @@ - import DocumentsService from "@Services/super-admin/DocumentsService/DocumentsService"; import { Documents } from "@prisma/client"; -import User, { Document, Vote } from "le-coffre-resources/dist/SuperAdmin"; +import User, { Document, OfficeFolder, Vote } from "le-coffre-resources/dist/SuperAdmin"; import { Service } from "typedi"; import NotificationsService from "@Services/common/NotificationsService/NotificationsService"; import UsersService from "@Services/super-admin/UsersService/UsersService"; +import OfficeFoldersService from "@Services/super-admin/OfficeFoldersService/OfficeFoldersService"; @Service() export default class NotificationBuilder { - public constructor(private notificationsService : NotificationsService, private documentsService: DocumentsService, private usersService: UsersService){} + public constructor( + private notificationsService: NotificationsService, + private documentsService: DocumentsService, + private usersService: UsersService, + private foldersService: OfficeFoldersService, + ) {} - public async sendDocumentDepositedNotification(documentEntity: Documents){ - if(documentEntity.document_status !== "DEPOSITED") return; - - const documentPrisma = await this.documentsService.getByUid(documentEntity.uid, { depositor: {include: {contact: true}}, folder:{include:{ office: true, stakeholders: true}} }); - if(!documentPrisma) throw new Error("Document not found"); - const document = Document.hydrate(documentPrisma); + public async sendDocumentDepositedNotification(documentEntity: Documents) { + if (documentEntity.document_status !== "DEPOSITED") return; - this.notificationsService.create({ - message: "Votre client " + document.depositor?.contact?.first_name + " " + document.depositor?.contact?.last_name + " vous a envoyé un document à valider", - redirection_url: "", - created_at: new Date(), - updated_at: new Date(), - user : document.folder!.stakeholders || [], - }); - } + const documentPrisma = await this.documentsService.getByUid(documentEntity.uid, { + depositor: { include: { contact: true } }, + folder: { include: { office: true, stakeholders: true } }, + }); + if (!documentPrisma) throw new Error("Document not found"); + const document = Document.hydrate(documentPrisma); - public async sendDocumentAnchoredNotification(documentEntity: Documents){ - - const documentPrisma = await this.documentsService.getByUid(documentEntity.uid, { depositor: {include: {contact: true}}, folder:{include:{ folder_anchor : true ,office: true, stakeholders: true}} }); - if(!documentPrisma) throw new Error("Document not found"); - const document = Document.hydrate(documentPrisma); - if(document.folder?.anchor?.status !== "VERIFIED_ON_CHAIN") return; + this.notificationsService.create({ + message: + "Votre client " + + document.depositor?.contact?.first_name + + " " + + document.depositor?.contact?.last_name + + " vous a envoyé un document à valider", + redirection_url: "", + created_at: new Date(), + updated_at: new Date(), + user: document.folder!.stakeholders || [], + }); + } - this.notificationsService.create({ - message: "Le dossier " + document.folder?.folder_number + " - " + document.folder?.name + " a été certifié. Vous pouvez désormais télécharger le certificat de dépôt pour le mettre dans la GED de votre logiciel de rédaction d'acte.", - redirection_url: "", - created_at: new Date(), - updated_at: new Date(), - user : document.folder!.stakeholders || [], - }); - } + public async sendDocumentAnchoredNotification(documentEntity: Documents) { + const documentPrisma = await this.documentsService.getByUid(documentEntity.uid, { + depositor: { include: { contact: true } }, + folder: { include: { folder_anchor: true, office: true, stakeholders: true } }, + }); + if (!documentPrisma) throw new Error("Document not found"); + const document = Document.hydrate(documentPrisma); + if (document.folder?.anchor?.status !== "VERIFIED_ON_CHAIN") return; - public async sendVoteNotification(vote: Vote){ - if(vote.appointment.status !== "OPEN") return; - const superAdminList = await this.usersService.get({where: {role : {label : "super-admin"}}}); - let message = ""; - if(vote.appointment.choice === "NOMINATE"){ - message = "Un collaborateur souhaite attribuer le titre de Super Administrateur à " + vote.appointment.targeted_user + ". Cliquez ici pour voter." - } - else if(vote.appointment.choice === "DISMISS"){ - message = "Un collaborateur souhaite retirer le titre de Super Administrateur à " + vote.appointment.targeted_user + ". Cliquez ici pour voter." - } + this.notificationsService.create({ + message: + "Le dossier " + + document.folder?.folder_number + + " - " + + document.folder?.name + + " a été certifié. Vous pouvez désormais télécharger le certificat de dépôt pour le mettre dans la GED de votre logiciel de rédaction d'acte.", + redirection_url: "", + created_at: new Date(), + updated_at: new Date(), + user: document.folder!.stakeholders || [], + }); + } - this.notificationsService.create({ - message: message, - redirection_url: "", - created_at: new Date(), - updated_at: new Date(), - user : superAdminList || [], - }); - } + public async sendVoteNotification(vote: Vote) { + if (vote.appointment.status !== "OPEN") return; + const superAdminList = await this.usersService.get({ where: { role: { label: "super-admin" } } }); + let message = ""; + if (vote.appointment.choice === "NOMINATE") { + message = + "Un collaborateur souhaite attribuer le titre de Super Administrateur à " + + vote.appointment.targeted_user + + ". Cliquez ici pour voter."; + } else if (vote.appointment.choice === "DISMISS") { + message = + "Un collaborateur souhaite retirer le titre de Super Administrateur à " + + vote.appointment.targeted_user + + ". Cliquez ici pour voter."; + } - public async sendDismissNotification(user: User){ - this.notificationsService.create({ - message: "Vous n'avez désormais plus le rôle de Super Administrateur de la plateforme.", - redirection_url: "", - created_at: new Date(), - updated_at: new Date(), - user : [user] || [], - }); - } + this.notificationsService.create({ + message: message, + redirection_url: "", + created_at: new Date(), + updated_at: new Date(), + user: superAdminList || [], + }); + } - public async sendNominateNotification(user: User){ - this.notificationsService.create({ - message: "Vous avez désormais le rôle de Super Administrateur de la plateforme.", - redirection_url: "", - created_at: new Date(), - updated_at: new Date(), - user : [user] || [], - }); - } + public async sendDismissNotification(user: User) { + this.notificationsService.create({ + message: "Vous n'avez désormais plus le rôle de Super Administrateur de la plateforme.", + redirection_url: "", + created_at: new Date(), + updated_at: new Date(), + user: [user] || [], + }); + } + public async sendNominateNotification(user: User) { + this.notificationsService.create({ + message: "Vous avez désormais le rôle de Super Administrateur de la plateforme.", + redirection_url: "", + created_at: new Date(), + updated_at: new Date(), + user: [user] || [], + }); + } + + public async sendDocumentExpiringSoonNotification(folderUid: string, expirationDate: Date) { + const day = expirationDate.getDate(); + const month = expirationDate.getMonth() + 1; // Months are 0-based, so add 1 + const year = expirationDate.getFullYear(); + + // Ensure that the day and month have two digits (e.g., 01, 02, 11) + const formattedDay = day < 10 ? `0${day}` : `${day}`; + const formattedMonth = month < 10 ? `0${month}` : `${month}`; + + const formattedDate = `${formattedDay}/${formattedMonth}/${year}`; + + const folderPrisma = await this.foldersService.getByUid(folderUid, { stakeholders: true, office: true }); + if (!folderPrisma) throw new Error("Document not found"); + const folder = OfficeFolder.hydrate(folderPrisma); + + this.notificationsService.create({ + message: + "Vous devez valider le dossier " + + folder.folder_number + + " - " + + folder.name + + " avant le " + + formattedDate + + " (date limite d'expiration des documents).", + redirection_url: "", + created_at: new Date(), + updated_at: new Date(), + user: folder.stakeholders || [], + }); + } } diff --git a/src/entries/Cron.ts b/src/entries/Cron.ts index a34cee31..0b17f5b4 100644 --- a/src/entries/Cron.ts +++ b/src/entries/Cron.ts @@ -12,6 +12,7 @@ import CronService from "@Services/common/CronService/CronService"; const variables = await Container.get(BackendVariables).validate(); Container.get(CronService).archiveFiles(); await Container.get(CronService).updateUsers(); + Container.get(CronService).checkDocumentsExpiration(); if(variables.ENV !== "dev"){ Container.get(CronService).sendMails(); Container.get(CronService).sendRecapMails(); diff --git a/src/services/common/CronService/CronService.ts b/src/services/common/CronService/CronService.ts index 79cb9a87..f184d6e0 100644 --- a/src/services/common/CronService/CronService.ts +++ b/src/services/common/CronService/CronService.ts @@ -3,15 +3,23 @@ import { CronJob } from "cron"; import MailchimpService from "../MailchimpService/MailchimpService"; import FilesService from "../FilesService/FilesService"; import IdNotService from "../IdNotService/IdNotService"; - +import { PrismaClient } from "@prisma/client"; +import NotificationBuilder from "@Common/notifications/NotificationBuilder"; +// import { PrismaClient } from "@prisma/client"; @Service() export default class CronService { - constructor(private mailchimpService: MailchimpService, private filesService: FilesService, private idNotService: IdNotService) {} + constructor( + private mailchimpService: MailchimpService, + private filesService: FilesService, + private idNotService: IdNotService, + private notificationBuilder: NotificationBuilder + ) {} public async sendMails() { - const cronJob = new CronJob("*/15 * * * * *", async () => { // Every 15 seconds - try { + const cronJob = new CronJob("*/15 * * * * *", async () => { + // Every 15 seconds + try { await this.mailchimpService.sendEmails(); } catch (e) { console.error(e); @@ -25,8 +33,9 @@ export default class CronService { } public async sendRecapMails() { - const cronJob = new CronJob("0 20 * * FRI", async () => { // Every friday at 20:00 - try { + const cronJob = new CronJob("0 20 * * FRI", async () => { + // Every friday at 20:00 + try { await this.mailchimpService.sendRecapEmails(); } catch (e) { console.error(e); @@ -40,8 +49,9 @@ export default class CronService { } public async archiveFiles() { - const cronJob = new CronJob("0 0 * * MON", async () => { // Every monday at midnight - try { + const cronJob = new CronJob("0 0 * * MON", async () => { + // Every monday at midnight + try { await this.filesService.archiveOldFiles(); } catch (e) { console.error(e); @@ -54,7 +64,8 @@ export default class CronService { } } public async updateUsers() { - const cronJob = new CronJob("0 0 * * *", async () => { // Once a day at midnight + const cronJob = new CronJob("0 0 * * *", async () => { + // Once a day at midnight try { await this.idNotService.updateOffices(); await this.idNotService.updateUsers(); @@ -67,4 +78,33 @@ export default class CronService { cronJob.start(); } } + + public async checkDocumentsExpiration() { + const cronJob = new CronJob("*/10 * * * * *", async () => { + // Once a day at midnight + try { + const prisma = new PrismaClient(); + const expiringDocuments15Days: [{uid: string, expiration_date: Date}] = await prisma.$queryRaw + `SELECT distinct o.uid, f.created_at as expiration_date + FROM documents d + JOIN files f ON d.uid=f.document_uid + JOIN office_folders o ON o.uid=d.folder_uid + WHERE o.folder_anchor_uid IS null + AND d.document_status = 'DEPOSITED' + AND current_date = (DATE(f.created_at) + interval '3 months' - interval '2 days');`; + + expiringDocuments15Days.forEach(expiringFolder => { + this.notificationBuilder.sendDocumentExpiringSoonNotification(expiringFolder.uid, expiringFolder.expiration_date); + }); + + + } catch (e) { + console.error(e); + } + }); + // Start job + if (!cronJob.running) { + cronJob.start(); + } + } } diff --git a/src/services/common/MailchimpService/MailchimpService.ts b/src/services/common/MailchimpService/MailchimpService.ts index 5225b41e..1b9833be 100644 --- a/src/services/common/MailchimpService/MailchimpService.ts +++ b/src/services/common/MailchimpService/MailchimpService.ts @@ -4,13 +4,14 @@ import { Emails, PrismaClient } from "@prisma/client"; import { Service } from "typedi"; import MailchimpClient from "@mailchimp/mailchimp_transactional"; import { BackendVariables } from "@Common/config/variables/Variables"; +import EmailBuilder from "@Common/emails/EmailBuilder"; // import DocumentsService from "@Services/super-admin/DocumentsService/DocumentsService"; @Service() export default class MailchimpService extends BaseService { private static readonly from = "vincent.alamelle@smart-chain.fr"; - constructor(private emailRepository: EmailRepository, protected variables: BackendVariables) { + constructor(private emailRepository: EmailRepository, protected variables: BackendVariables, private emailBuilder: EmailBuilder) { super(); } @@ -84,12 +85,8 @@ export default class MailchimpService extends BaseService { } } - private async sendEmail(email: Emails) { - console.log("sendEmail"); - - const apiKey = this.variables.MAILCHIMP_API_KEY; - console.log(apiKey); - + private async sendEmail(email: Emails) { + const apiKey = this.variables.MAILCHIMP_API_KEY; const mailchimpApiClient = MailchimpClient(apiKey!); await mailchimpApiClient.messages.sendTemplate({ @@ -121,7 +118,7 @@ export default class MailchimpService extends BaseService { public async sendRecapEmails() { const prisma = new PrismaClient(); - const usersToEmail = await prisma.$queryRaw + const usersToEmail: [{email: string, civility: string, last_name: string}] = await prisma.$queryRaw `SELECT DISTINCT c.email, c.civility, c.last_name FROM Contacts c JOIN Users u ON c.uid = u.contact_uid @@ -129,6 +126,6 @@ export default class MailchimpService extends BaseService { JOIN Documents d ON of.uid = d.folder_uid WHERE d.document_status = 'DEPOSITED';` - console.log(usersToEmail); + await this.emailBuilder.sendRecapEmails(usersToEmail); } }