Notif cron

This commit is contained in:
Vins 2023-09-26 11:39:21 +02:00
parent 6e811d1b03
commit 29a8e23c43
4 changed files with 178 additions and 85 deletions

View File

@ -1,85 +1,140 @@
import DocumentsService from "@Services/super-admin/DocumentsService/DocumentsService"; import DocumentsService from "@Services/super-admin/DocumentsService/DocumentsService";
import { Documents } from "@prisma/client"; 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 { Service } from "typedi";
import NotificationsService from "@Services/common/NotificationsService/NotificationsService"; import NotificationsService from "@Services/common/NotificationsService/NotificationsService";
import UsersService from "@Services/super-admin/UsersService/UsersService"; import UsersService from "@Services/super-admin/UsersService/UsersService";
import OfficeFoldersService from "@Services/super-admin/OfficeFoldersService/OfficeFoldersService";
@Service() @Service()
export default class NotificationBuilder { 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){ public async sendDocumentDepositedNotification(documentEntity: Documents) {
if(documentEntity.document_status !== "DEPOSITED") return; 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<Document>(documentPrisma);
this.notificationsService.create({ const documentPrisma = await this.documentsService.getByUid(documentEntity.uid, {
message: "Votre client " + document.depositor?.contact?.first_name + " " + document.depositor?.contact?.last_name + " vous a envoyé un document à valider", depositor: { include: { contact: true } },
redirection_url: "", folder: { include: { office: true, stakeholders: true } },
created_at: new Date(), });
updated_at: new Date(), if (!documentPrisma) throw new Error("Document not found");
user : document.folder!.stakeholders || [], const document = Document.hydrate<Document>(documentPrisma);
});
}
public async sendDocumentAnchoredNotification(documentEntity: Documents){ this.notificationsService.create({
message:
const documentPrisma = await this.documentsService.getByUid(documentEntity.uid, { depositor: {include: {contact: true}}, folder:{include:{ folder_anchor : true ,office: true, stakeholders: true}} }); "Votre client " +
if(!documentPrisma) throw new Error("Document not found"); document.depositor?.contact?.first_name +
const document = Document.hydrate<Document>(documentPrisma); " " +
if(document.folder?.anchor?.status !== "VERIFIED_ON_CHAIN") return; 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({ public async sendDocumentAnchoredNotification(documentEntity: Documents) {
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.", const documentPrisma = await this.documentsService.getByUid(documentEntity.uid, {
redirection_url: "", depositor: { include: { contact: true } },
created_at: new Date(), folder: { include: { folder_anchor: true, office: true, stakeholders: true } },
updated_at: new Date(), });
user : document.folder!.stakeholders || [], if (!documentPrisma) throw new Error("Document not found");
}); const document = Document.hydrate<Document>(documentPrisma);
} if (document.folder?.anchor?.status !== "VERIFIED_ON_CHAIN") return;
public async sendVoteNotification(vote: Vote){ this.notificationsService.create({
if(vote.appointment.status !== "OPEN") return; message:
const superAdminList = await this.usersService.get({where: {role : {label : "super-admin"}}}); "Le dossier " +
let message = ""; document.folder?.folder_number +
if(vote.appointment.choice === "NOMINATE"){ " - " +
message = "Un collaborateur souhaite attribuer le titre de Super Administrateur à " + vote.appointment.targeted_user + ". Cliquez ici pour voter." 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.",
else if(vote.appointment.choice === "DISMISS"){ redirection_url: "",
message = "Un collaborateur souhaite retirer le titre de Super Administrateur à " + vote.appointment.targeted_user + ". Cliquez ici pour voter." created_at: new Date(),
} updated_at: new Date(),
user: document.folder!.stakeholders || [],
});
}
this.notificationsService.create({ public async sendVoteNotification(vote: Vote) {
message: message, if (vote.appointment.status !== "OPEN") return;
redirection_url: "", const superAdminList = await this.usersService.get({ where: { role: { label: "super-admin" } } });
created_at: new Date(), let message = "";
updated_at: new Date(), if (vote.appointment.choice === "NOMINATE") {
user : superAdminList || [], 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({
this.notificationsService.create({ message: message,
message: "Vous n'avez désormais plus le rôle de Super Administrateur de la plateforme.", redirection_url: "",
redirection_url: "", created_at: new Date(),
created_at: new Date(), updated_at: new Date(),
updated_at: new Date(), user: superAdminList || [],
user : [user] || [], });
}); }
}
public async sendNominateNotification(user: User){ public async sendDismissNotification(user: User) {
this.notificationsService.create({ this.notificationsService.create({
message: "Vous avez désormais le rôle de Super Administrateur de la plateforme.", message: "Vous n'avez désormais plus le rôle de Super Administrateur de la plateforme.",
redirection_url: "", redirection_url: "",
created_at: new Date(), created_at: new Date(),
updated_at: new Date(), updated_at: new Date(),
user : [user] || [], 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<OfficeFolder>(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 || [],
});
}
} }

View File

@ -12,6 +12,7 @@ import CronService from "@Services/common/CronService/CronService";
const variables = await Container.get(BackendVariables).validate(); const variables = await Container.get(BackendVariables).validate();
Container.get(CronService).archiveFiles(); Container.get(CronService).archiveFiles();
await Container.get(CronService).updateUsers(); await Container.get(CronService).updateUsers();
Container.get(CronService).checkDocumentsExpiration();
if(variables.ENV !== "dev"){ if(variables.ENV !== "dev"){
Container.get(CronService).sendMails(); Container.get(CronService).sendMails();
Container.get(CronService).sendRecapMails(); Container.get(CronService).sendRecapMails();

View File

@ -3,15 +3,23 @@ import { CronJob } from "cron";
import MailchimpService from "../MailchimpService/MailchimpService"; import MailchimpService from "../MailchimpService/MailchimpService";
import FilesService from "../FilesService/FilesService"; import FilesService from "../FilesService/FilesService";
import IdNotService from "../IdNotService/IdNotService"; import IdNotService from "../IdNotService/IdNotService";
import { PrismaClient } from "@prisma/client";
import NotificationBuilder from "@Common/notifications/NotificationBuilder";
// import { PrismaClient } from "@prisma/client";
@Service() @Service()
export default class CronService { 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() { public async sendMails() {
const cronJob = new CronJob("*/15 * * * * *", async () => { // Every 15 seconds const cronJob = new CronJob("*/15 * * * * *", async () => {
try { // Every 15 seconds
try {
await this.mailchimpService.sendEmails(); await this.mailchimpService.sendEmails();
} catch (e) { } catch (e) {
console.error(e); console.error(e);
@ -25,8 +33,9 @@ export default class CronService {
} }
public async sendRecapMails() { public async sendRecapMails() {
const cronJob = new CronJob("0 20 * * FRI", async () => { // Every friday at 20:00 const cronJob = new CronJob("0 20 * * FRI", async () => {
try { // Every friday at 20:00
try {
await this.mailchimpService.sendRecapEmails(); await this.mailchimpService.sendRecapEmails();
} catch (e) { } catch (e) {
console.error(e); console.error(e);
@ -40,8 +49,9 @@ export default class CronService {
} }
public async archiveFiles() { public async archiveFiles() {
const cronJob = new CronJob("0 0 * * MON", async () => { // Every monday at midnight const cronJob = new CronJob("0 0 * * MON", async () => {
try { // Every monday at midnight
try {
await this.filesService.archiveOldFiles(); await this.filesService.archiveOldFiles();
} catch (e) { } catch (e) {
console.error(e); console.error(e);
@ -54,7 +64,8 @@ export default class CronService {
} }
} }
public async updateUsers() { 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 { try {
await this.idNotService.updateOffices(); await this.idNotService.updateOffices();
await this.idNotService.updateUsers(); await this.idNotService.updateUsers();
@ -67,4 +78,33 @@ export default class CronService {
cronJob.start(); 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();
}
}
} }

View File

@ -4,13 +4,14 @@ import { Emails, PrismaClient } from "@prisma/client";
import { Service } from "typedi"; import { Service } from "typedi";
import MailchimpClient from "@mailchimp/mailchimp_transactional"; import MailchimpClient from "@mailchimp/mailchimp_transactional";
import { BackendVariables } from "@Common/config/variables/Variables"; import { BackendVariables } from "@Common/config/variables/Variables";
import EmailBuilder from "@Common/emails/EmailBuilder";
// import DocumentsService from "@Services/super-admin/DocumentsService/DocumentsService"; // import DocumentsService from "@Services/super-admin/DocumentsService/DocumentsService";
@Service() @Service()
export default class MailchimpService extends BaseService { export default class MailchimpService extends BaseService {
private static readonly from = "vincent.alamelle@smart-chain.fr"; 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(); super();
} }
@ -84,12 +85,8 @@ export default class MailchimpService extends BaseService {
} }
} }
private async sendEmail(email: Emails) { private async sendEmail(email: Emails) {
console.log("sendEmail"); const apiKey = this.variables.MAILCHIMP_API_KEY;
const apiKey = this.variables.MAILCHIMP_API_KEY;
console.log(apiKey);
const mailchimpApiClient = MailchimpClient(apiKey!); const mailchimpApiClient = MailchimpClient(apiKey!);
await mailchimpApiClient.messages.sendTemplate({ await mailchimpApiClient.messages.sendTemplate({
@ -121,7 +118,7 @@ export default class MailchimpService extends BaseService {
public async sendRecapEmails() { public async sendRecapEmails() {
const prisma = new PrismaClient(); 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 `SELECT DISTINCT c.email, c.civility, c.last_name
FROM Contacts c FROM Contacts c
JOIN Users u ON c.uid = u.contact_uid 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 JOIN Documents d ON of.uid = d.folder_uid
WHERE d.document_status = 'DEPOSITED';` WHERE d.document_status = 'DEPOSITED';`
console.log(usersToEmail); await this.emailBuilder.sendRecapEmails(usersToEmail);
} }
} }