diff --git a/package.json b/package.json index c0ec46b8..d1529382 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "express": "^4.18.2", "fp-ts": "^2.16.1", "jsonwebtoken": "^9.0.0", - "le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.90", + "le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.92", "module-alias": "^2.2.2", "monocle-ts": "^2.3.13", "multer": "^1.4.5-lts.1", diff --git a/src/app/api/admin/CustomersController.ts b/src/app/api/admin/CustomersController.ts index e1badb0d..5f9ed4ec 100644 --- a/src/app/api/admin/CustomersController.ts +++ b/src/app/api/admin/CustomersController.ts @@ -31,9 +31,9 @@ export default class CustomersController extends ApiController { } const officeId: string = req.body.user.office_Id; - if(query.where?.office_folders?.some?.office_uid) delete query.where.office_folders.some.office_uid; - if(query.where?.office_folders?.some?.office?.uid) delete query.where?.office_folders?.some?.office?.uid; - const customerWhereInput: Prisma.CustomersWhereInput = { ...query.where, office_folders: { some: { office_uid: officeId } }}; + if (query.where?.office_folders?.some?.office_uid) delete query.where.office_folders.some.office_uid; + if (query.where?.office_folders?.some?.office?.uid) delete query.where?.office_folders?.some?.office?.uid; + const customerWhereInput: Prisma.CustomersWhereInput = { ...query.where, office_folders: { some: { office_uid: officeId } } }; query.where = customerWhereInput; //call service to get prisma entity @@ -79,7 +79,7 @@ export default class CustomersController extends ApiController { /** * @description Modify a specific customer by uid */ - @Put("/api/v1/admin/customers/:uid", [authHandler, roleHandler, ruleHandler, customerHandler]) + @Put("/api/v1/notary/customers/:uid", [authHandler, ruleHandler, customerHandler]) protected async put(req: Request, response: Response) { try { const uid = req.params["uid"]; @@ -95,22 +95,32 @@ export default class CustomersController extends ApiController { return; } + req.body.contact.uid = userFound.contact_uid; + //init IUser resource with request body values const customerEntity = Customer.hydrate(req.body); - //validate user - await validateOrReject(customerEntity, { groups: ["updateCustomer"], forbidUnknownValues: false }); - + try { + await validateOrReject(customerEntity, { groups: ["updateCustomer"], forbidUnknownValues: false }); + } catch (error) { + this.httpValidationError(response, error); + return; + } //call service to get prisma entity - const customerEntityUpdated = await this.customersService.update(uid, customerEntity); + try { + const customerEntityUpdated = await this.customersService.update(uid, customerEntity); + //Hydrate ressource with prisma entity + const customer = Customer.hydrate(customerEntityUpdated, { + strategy: "excludeAll", + }); - //Hydrate ressource with prisma entity - const customer = Customer.hydrate(customerEntityUpdated, { - strategy: "excludeAll", - }); - - //success - this.httpSuccess(response, customer); + //success + this.httpSuccess(response, customer); + } catch (error) { + console.log(error); + this.httpValidationError(response, error); + return; + } } catch (error) { this.httpInternalError(response, error); return; diff --git a/src/app/api/admin/DeedTypesController.ts b/src/app/api/admin/DeedTypesController.ts index d1273879..3963128e 100644 --- a/src/app/api/admin/DeedTypesController.ts +++ b/src/app/api/admin/DeedTypesController.ts @@ -74,11 +74,6 @@ export default class DeedTypesController extends ApiController { //validate deed type await validateOrReject(deedTypeEntity, { groups: ["createDeedType"], forbidUnknownValues: false }); - const doesExist = await this.deedTypesService.get({ where: { name: deedTypeEntity.name } }); - if (doesExist.length > 0) { - this.httpBadRequest(response, "Deed type name already used"); - return; - } //call service to get prisma entity const deedTypeEntityCreated = await this.deedTypesService.create(deedTypeEntity); diff --git a/src/app/api/admin/OfficeFoldersController.ts b/src/app/api/admin/OfficeFoldersController.ts index bf1c8732..2284ae19 100644 --- a/src/app/api/admin/OfficeFoldersController.ts +++ b/src/app/api/admin/OfficeFoldersController.ts @@ -62,7 +62,7 @@ export default class OfficeFoldersController extends ApiController { if (query.where?.stakeholders) delete query.where.stakeholders; const officeFoldersWhereInput: Prisma.OfficeFoldersWhereInput = { ...query.where, stakeholders: { some: { uid: userId } } }; query.where = officeFoldersWhereInput; - + //call service to get prisma entity const officeFolderEntities: OfficeFolders[] = await this.officeFoldersService.get(query); @@ -89,13 +89,18 @@ export default class OfficeFoldersController extends ApiController { await officeFolderRessource.validateOrReject?.({ groups: ["createFolder"], forbidUnknownValues: false }); //call service to get prisma entity - const officeFolderEntity = await this.officeFoldersService.create(officeFolderRessource); - //Hydrate ressource with prisma entity - const officeFolders = OfficeFolder.hydrate(officeFolderEntity, { - strategy: "excludeAll", - }); - //success - this.httpCreated(response, officeFolders); + try { + const officeFolderEntity = await this.officeFoldersService.create(officeFolderRessource); + //Hydrate ressource with prisma entity + const officeFolders = OfficeFolder.hydrate(officeFolderEntity, { + strategy: "excludeAll", + }); + //success + this.httpCreated(response, officeFolders); + } catch (error) { + this.httpValidationError(response, error); + return; + } } catch (error) { this.httpInternalError(response, error); return; @@ -120,7 +125,7 @@ export default class OfficeFoldersController extends ApiController { this.httpNotFoundRequest(response, "office folder not found"); return; } - + //init OfficeFolder resource with request body values const officeFolderEntity = OfficeFolder.hydrate(req.body); @@ -128,15 +133,20 @@ export default class OfficeFoldersController extends ApiController { await validateOrReject(officeFolderEntity, { groups: ["updateFolder"], forbidUnknownValues: false }); //call service to get prisma entity - const officeFolderEntityUpdated = await this.officeFoldersService.update(uid, officeFolderEntity); + try { + const officeFolderEntityUpdated = await this.officeFoldersService.update(uid, officeFolderEntity); - //Hydrate ressource with prisma entity - const officeFolders = OfficeFolder.hydrate(officeFolderEntityUpdated, { - strategy: "excludeAll", - }); + //Hydrate ressource with prisma entity + const officeFolders = OfficeFolder.hydrate(officeFolderEntityUpdated, { + strategy: "excludeAll", + }); - //success - this.httpSuccess(response, officeFolders); + //success + this.httpSuccess(response, officeFolders); + } catch (error) { + this.httpValidationError(response, error); + return; + } } catch (error) { this.httpInternalError(response, error); return; @@ -160,7 +170,7 @@ export default class OfficeFoldersController extends ApiController { if (req.query["q"]) { query = JSON.parse(req.query["q"] as string); } - + const officeFolderEntity = await this.officeFoldersService.getByUid(uid, query); if (!officeFolderEntity) { diff --git a/src/app/api/notary/CustomersController.ts b/src/app/api/notary/CustomersController.ts index 4415fd34..69b6bb7f 100644 --- a/src/app/api/notary/CustomersController.ts +++ b/src/app/api/notary/CustomersController.ts @@ -30,8 +30,8 @@ export default class CustomersController extends ApiController { } const officeId: string = req.body.user.office_Id; - if(query.where?.office_folders) delete query.where.office_folders; - const customerWhereInput: Prisma.CustomersWhereInput = { ...query.where, office_folders: { some: { office_uid: officeId } }}; + if (query.where?.office_folders) delete query.where.office_folders; + const customerWhereInput: Prisma.CustomersWhereInput = { ...query.where, office_folders: { some: { office_uid: officeId } } }; query.where = customerWhereInput; //call service to get prisma entity @@ -57,8 +57,12 @@ export default class CustomersController extends ApiController { //init IUser resource with request body values const customerEntity = Customer.hydrate(req.body); //validate user - await validateOrReject(customerEntity, { groups: ["createCustomer"], forbidUnknownValues: false }); - + try { + await validateOrReject(customerEntity, { groups: ["createCustomer"], forbidUnknownValues: false }); + } catch (error) { + this.httpValidationError(response, error); + return; + } //call service to get prisma entity const customerEntityCreated = await this.customersService.create(customerEntity); //Hydrate ressource with prisma entity @@ -93,22 +97,32 @@ export default class CustomersController extends ApiController { return; } + req.body.contact.uid = userFound.contact_uid; + //init IUser resource with request body values const customerEntity = Customer.hydrate(req.body); - //validate user - await validateOrReject(customerEntity, { groups: ["updateCustomer"], forbidUnknownValues: false }); - + try { + await validateOrReject(customerEntity, { groups: ["updateCustomer"], forbidUnknownValues: false }); + } catch (error) { + this.httpValidationError(response, error); + return; + } //call service to get prisma entity - const customerEntityUpdated = await this.customersService.update(uid, customerEntity); + try { + const customerEntityUpdated = await this.customersService.update(uid, customerEntity); + //Hydrate ressource with prisma entity + const customer = Customer.hydrate(customerEntityUpdated, { + strategy: "excludeAll", + }); - //Hydrate ressource with prisma entity - const customer = Customer.hydrate(customerEntityUpdated, { - strategy: "excludeAll", - }); - - //success - this.httpSuccess(response, customer); + //success + this.httpSuccess(response, customer); + } catch (error) { + console.log(error); + this.httpValidationError(response, error); + return; + } } catch (error) { this.httpInternalError(response, error); return; diff --git a/src/app/api/notary/DocumentTypesController.ts b/src/app/api/notary/DocumentTypesController.ts index 6a1a81bd..8071a296 100644 --- a/src/app/api/notary/DocumentTypesController.ts +++ b/src/app/api/notary/DocumentTypesController.ts @@ -4,7 +4,6 @@ import ApiController from "@Common/system/controller-pattern/ApiController"; import { Service } from "typedi"; import DocumentTypesService from "@Services/notary/DocumentTypesService/DocumentTypesService"; import { DocumentTypes, Prisma } from "@prisma/client"; -import ObjectHydrate from "@Common/helpers/ObjectHydrate"; import { DocumentType } from "le-coffre-resources/dist/Notary"; import { validateOrReject } from "class-validator"; import authHandler from "@App/middlewares/AuthHandler"; @@ -133,11 +132,15 @@ export default class DocumentTypesController extends ApiController { const documentTypeEntity = await this.documentTypesService.getByUid(uid, query); - //Hydrate ressource with prisma entity - const user = ObjectHydrate.hydrate(new DocumentType(), documentTypeEntity!, { strategy: "excludeAll" }); + if (!documentTypeEntity) { + this.httpNotFoundRequest(response, "document type not found"); + return; + } + + const documentType = DocumentType.hydrate(documentTypeEntity, { strategy: "excludeAll" }); //success - this.httpSuccess(response, user); + this.httpSuccess(response, documentType); } catch (error) { this.httpInternalError(response, error); return; diff --git a/src/app/api/notary/OfficeFoldersController.ts b/src/app/api/notary/OfficeFoldersController.ts index d5a5b115..f8dca5ad 100644 --- a/src/app/api/notary/OfficeFoldersController.ts +++ b/src/app/api/notary/OfficeFoldersController.ts @@ -86,13 +86,18 @@ export default class OfficeFoldersController extends ApiController { await officeFolderRessource.validateOrReject?.({ groups: ["createFolder"], forbidUnknownValues: false }); //call service to get prisma entity - const officeFolderEntity = await this.officeFoldersService.create(officeFolderRessource); - //Hydrate ressource with prisma entity - const officeFolders = OfficeFolder.hydrate(officeFolderEntity, { - strategy: "excludeAll", - }); - //success - this.httpCreated(response, officeFolders); + try { + const officeFolderEntity = await this.officeFoldersService.create(officeFolderRessource); + //Hydrate ressource with prisma entity + const officeFolders = OfficeFolder.hydrate(officeFolderEntity, { + strategy: "excludeAll", + }); + //success + this.httpCreated(response, officeFolders); + } catch (error) { + this.httpValidationError(response, error); + return; + } } catch (error) { this.httpInternalError(response, error); return; @@ -111,9 +116,7 @@ export default class OfficeFoldersController extends ApiController { return; } - const officeFolderFound = await this.officeFoldersService.getByUid(uid, { - folder_anchor: true, - }); + const officeFolderFound = await this.officeFoldersService.getByUid(uid); if (!officeFolderFound) { this.httpNotFoundRequest(response, "office folder not found"); @@ -121,25 +124,26 @@ export default class OfficeFoldersController extends ApiController { } //init OfficeFolder resource with request body values - const officefolderToUpdate = OfficeFolder.hydrate(req.body); - const officeFolderFoundEntity = OfficeFolder.hydrate(officeFolderFound); - //validate folder - await validateOrReject(officefolderToUpdate, { groups: ["updateFolder"], forbidUnknownValues: false }); + const officeFolderEntity = OfficeFolder.hydrate(req.body); - if (officeFolderFoundEntity.folder_anchor?.status === "VERIFIED_ON_CHAIN") { - this.httpBadRequest(response, "Cannot update a verified folder"); + //validate folder + await validateOrReject(officeFolderEntity, { groups: ["updateFolder"], forbidUnknownValues: false }); + + //call service to get prisma entity + try { + const officeFolderEntityUpdated = await this.officeFoldersService.update(uid, officeFolderEntity); + + //Hydrate ressource with prisma entity + const officeFolders = OfficeFolder.hydrate(officeFolderEntityUpdated, { + strategy: "excludeAll", + }); + + //success + this.httpSuccess(response, officeFolders); + } catch (error) { + this.httpValidationError(response, error); return; } - //call service to get prisma entity - const officeFolderEntityUpdated = await this.officeFoldersService.update(uid, officefolderToUpdate); - - //Hydrate ressource with prisma entity - const officeFolders = OfficeFolder.hydrate(officeFolderEntityUpdated, { - strategy: "excludeAll", - }); - - //success - this.httpSuccess(response, officeFolders); } catch (error) { this.httpInternalError(response, error); return; diff --git a/src/app/api/super-admin/CustomersController.ts b/src/app/api/super-admin/CustomersController.ts index 628fa4ed..b3402942 100644 --- a/src/app/api/super-admin/CustomersController.ts +++ b/src/app/api/super-admin/CustomersController.ts @@ -79,7 +79,7 @@ export default class CustomersController extends ApiController { /** * @description Modify a specific customer by uid */ - @Put("/api/v1/super-admin/customers/:uid", [authHandler, roleHandler, ruleHandler, customerHandler]) + @Put("/api/v1/notary/customers/:uid", [authHandler, ruleHandler, customerHandler]) protected async put(req: Request, response: Response) { try { const uid = req.params["uid"]; @@ -94,23 +94,33 @@ export default class CustomersController extends ApiController { this.httpNotFoundRequest(response, "user not found"); return; } - + + req.body.contact.uid = userFound.contact_uid; + //init IUser resource with request body values const customerEntity = Customer.hydrate(req.body); - //validate user - await validateOrReject(customerEntity, { groups: ["updateCustomer"], forbidUnknownValues: false }); - + try { + await validateOrReject(customerEntity, { groups: ["updateCustomer"], forbidUnknownValues: false }); + } catch (error) { + this.httpValidationError(response, error); + return; + } //call service to get prisma entity - const customerEntityUpdated = await this.customersService.update(uid, customerEntity); + try { + const customerEntityUpdated = await this.customersService.update(uid, customerEntity); + //Hydrate ressource with prisma entity + const customer = Customer.hydrate(customerEntityUpdated, { + strategy: "excludeAll", + }); - //Hydrate ressource with prisma entity - const customer = Customer.hydrate(customerEntityUpdated, { - strategy: "excludeAll", - }); - - //success - this.httpSuccess(response, customer); + //success + this.httpSuccess(response, customer); + } catch (error) { + console.log(error); + this.httpValidationError(response, error); + return; + } } catch (error) { this.httpInternalError(response, error); return; diff --git a/src/app/api/super-admin/OfficeFoldersController.ts b/src/app/api/super-admin/OfficeFoldersController.ts index f31d2807..200dc117 100644 --- a/src/app/api/super-admin/OfficeFoldersController.ts +++ b/src/app/api/super-admin/OfficeFoldersController.ts @@ -87,13 +87,18 @@ export default class OfficeFoldersController extends ApiController { await officeFolderRessource.validateOrReject?.({ groups: ["createFolder"], forbidUnknownValues: false }); //call service to get prisma entity - const officeFolderEntity = await this.officeFoldersService.create(officeFolderRessource); - //Hydrate ressource with prisma entity - const officeFolders = OfficeFolder.hydrate(officeFolderEntity, { - strategy: "excludeAll", - }); - //success - this.httpCreated(response, officeFolders); + try { + const officeFolderEntity = await this.officeFoldersService.create(officeFolderRessource); + //Hydrate ressource with prisma entity + const officeFolders = OfficeFolder.hydrate(officeFolderEntity, { + strategy: "excludeAll", + }); + //success + this.httpCreated(response, officeFolders); + } catch (error) { + this.httpValidationError(response, error); + return; + } } catch (error) { this.httpInternalError(response, error); return; @@ -126,15 +131,20 @@ export default class OfficeFoldersController extends ApiController { await validateOrReject(officeFolderEntity, { groups: ["updateFolder"], forbidUnknownValues: false }); //call service to get prisma entity - const officeFolderEntityUpdated = await this.officeFoldersService.update(uid, officeFolderEntity); + try { + const officeFolderEntityUpdated = await this.officeFoldersService.update(uid, officeFolderEntity); - //Hydrate ressource with prisma entity - const officeFolders = OfficeFolder.hydrate(officeFolderEntityUpdated, { - strategy: "excludeAll", - }); + //Hydrate ressource with prisma entity + const officeFolders = OfficeFolder.hydrate(officeFolderEntityUpdated, { + strategy: "excludeAll", + }); - //success - this.httpSuccess(response, officeFolders); + //success + this.httpSuccess(response, officeFolders); + } catch (error) { + this.httpValidationError(response, error); + return; + } } catch (error) { this.httpInternalError(response, error); return; diff --git a/src/app/middlewares/OfficeMembershipHandlers/DeedTypeHandler.ts b/src/app/middlewares/OfficeMembershipHandlers/DeedTypeHandler.ts index f8b8e104..57066861 100644 --- a/src/app/middlewares/OfficeMembershipHandlers/DeedTypeHandler.ts +++ b/src/app/middlewares/OfficeMembershipHandlers/DeedTypeHandler.ts @@ -11,12 +11,24 @@ export default async function deedTypeHandler(req: Request, response: Response, const uid = req.path && req.path.split("/")[5]; const documentTypes: DocumentType[] = req.body.document_types; const office = req.body.office; + const name = req.body.name; if (office && office.uid != officeId) { response.status(HttpCodes.UNAUTHORIZED).send("Unauthorized with this office"); return; } + if (name) { + const deedTypeService = Container.get(DeedTypesService); + const deedType = await deedTypeService.get({ + where: { AND: [{ name: { equals: name, mode: "insensitive" } }, { office: { uid: officeId } }] }, + }); + if (deedType[0] && (!uid || deedType[0].uid != uid)) { + response.status(HttpCodes.VALIDATION_ERROR).send([{ property: "name", constraints: { name: "Nom d'acte déjà utilisé" } }]); + return; + } + } + if (uid) { const deedTypeService = Container.get(DeedTypesService); const deedType = await deedTypeService.getByUidWithOffice(uid!); diff --git a/src/app/middlewares/OfficeMembershipHandlers/DocumentTypeHandler.ts b/src/app/middlewares/OfficeMembershipHandlers/DocumentTypeHandler.ts index 9c8c8071..e5078ba8 100644 --- a/src/app/middlewares/OfficeMembershipHandlers/DocumentTypeHandler.ts +++ b/src/app/middlewares/OfficeMembershipHandlers/DocumentTypeHandler.ts @@ -8,12 +8,24 @@ export default async function documentTypeHandler(req: Request, response: Respon const officeId = req.body.user.office_Id; const uid = req.path && req.path.split("/")[5]; const office = req.body.office; + const name = req.body.name; if (office && office.uid != officeId) { response.status(HttpCodes.UNAUTHORIZED).send("Unauthorized with this office"); return; } + if (name) { + const documentTypeService = Container.get(DocumentTypesService); + const documentType = await documentTypeService.get({ + where: { AND: [{ name: { equals: name, mode: "insensitive" } }, { office: { uid: officeId } }] }, + }); + if (documentType[0] && (!uid || documentType[0].uid != uid)) { + response.status(HttpCodes.VALIDATION_ERROR).send([{ property: "name", constraints: { name: "Nom de document déjà utilisé" } }]); + return; + } + } + if (uid) { const documentTypeService = Container.get(DocumentTypesService); const documentType = await documentTypeService.getByUidWithOffice(uid!); diff --git a/src/app/middlewares/OfficeMembershipHandlers/FolderHandler.ts b/src/app/middlewares/OfficeMembershipHandlers/FolderHandler.ts index 2019b74a..ae447090 100644 --- a/src/app/middlewares/OfficeMembershipHandlers/FolderHandler.ts +++ b/src/app/middlewares/OfficeMembershipHandlers/FolderHandler.ts @@ -10,14 +10,25 @@ export default async function folderHandler(req: Request, response: Response, ne const userId = req.body.user.userId; let uid = req.path && req.path.split("/")[5]; const office = req.body.office; - const officeFolderNumber = req.body.folder_number; const deed = req.body.deed; + const folderNumber = req.body.folder_number; if (office && office.uid != officeId) { response.status(HttpCodes.UNAUTHORIZED).send("Unauthorized with this office"); return; } + if(folderNumber) { + const officeFolderService = Container.get(OfficeFoldersService); + const sameFolderNumber = await officeFolderService.get({ + where: { AND: [{ folder_number: folderNumber }, { office_uid: officeId }] }, + }); + if(sameFolderNumber[0] && (!uid || uid != sameFolderNumber[0]?.uid)) { + response.status(HttpCodes.VALIDATION_ERROR).send([{ property: "folder_number", constraints: { folder_number: "Numéro de dossier déjà utilisé" } }]); + return; + } + } + if (deed && deed.deed_type) { const deedTypeService = Container.get(DeedTypesService); const deedTypeWithOffice = await deedTypeService.getByUidWithOffice(deed.deed_type.uid!); @@ -25,20 +36,12 @@ export default async function folderHandler(req: Request, response: Response, ne response.status(HttpCodes.NOT_FOUND).send("Deed type not found"); return; } - if (deedTypeWithOffice.office.uid != officeId) { - response.status(HttpCodes.UNAUTHORIZED).send("Unauthorized with this deed type"); + if(deedTypeWithOffice.archived_at) { + response.status(HttpCodes.FORBIDDEN).send("Deed type is archived"); return; } - } - - const officeFolderService = Container.get(OfficeFoldersService); - - if (officeFolderNumber && req.method == "POST") { - const officeFoldersWithSameNumber = await officeFolderService.get({ - where: { folder_number: officeFolderNumber, office: { uid: officeId } }, - }); - if (officeFoldersWithSameNumber.length) { - response.status(HttpCodes.BAD_REQUEST).send("Office number already used"); + if (deedTypeWithOffice.office.uid != officeId) { + response.status(HttpCodes.UNAUTHORIZED).send("Unauthorized with this deed type"); return; } } @@ -47,6 +50,8 @@ export default async function folderHandler(req: Request, response: Response, ne if(uid === "download") { uid = req.path && req.path.split("/")[6]; } + const officeFolderService = Container.get(OfficeFoldersService); + const officeFolder = await officeFolderService.getByUidWithStakeholders(uid!); if (!officeFolder) { diff --git a/src/common/emails/EmailBuilder.ts b/src/common/emails/EmailBuilder.ts index 9aec7bc5..7d76d3e0 100644 --- a/src/common/emails/EmailBuilder.ts +++ b/src/common/emails/EmailBuilder.ts @@ -6,10 +6,11 @@ import { Service } from "typedi"; import { ETemplates } from "./Templates/EmailTemplates"; import MailchimpService from "@Services/common/MailchimpService/MailchimpService"; import { BackendVariables } from "@Common/config/variables/Variables"; +import UsersService from "@Services/super-admin/UsersService/UsersService"; @Service() -export default class EmailBuilder { - public constructor(private mailchimpService: MailchimpService ,private documentsService: DocumentsService, protected variables: BackendVariables){} +export default class EmailBuilder{ + public constructor(private mailchimpService: MailchimpService ,private documentsService: DocumentsService, protected variables: BackendVariables, private usersService: UsersService){} public async sendDocumentEmails(documentEntity: Documents){ if(documentEntity.document_status !== "ASKED" && documentEntity.document_status !== "REFUSED") return; @@ -53,9 +54,11 @@ export default class EmailBuilder { }); } - public async sendRecapEmails(usersToEmail: User[]){ + public async sendRecapEmails(){ + const usersToEmail : User[] = await this.usersService.get({ where: { office_folders: { some:{ documents: { some: { document_status: "DEPOSITED" } } }} }, distinct: ["uid"], include: { contact: true } }); + usersToEmail.forEach(user => { - const to = user.contact!.email; + const to = user.contact!.email; const civility = this.getCivility(user.contact!.civility); const templateVariables = { diff --git a/src/common/repositories/ContactRepository.ts b/src/common/repositories/ContactRepository.ts index 8a3861ee..da12d0aa 100644 --- a/src/common/repositories/ContactRepository.ts +++ b/src/common/repositories/ContactRepository.ts @@ -26,4 +26,16 @@ export default class ContactRepository extends BaseRepository { include: { customers: true } }); } + + /** + * @description : Find unique customer by email + */ + public async findOneByPhoneNumber(cell_phone_number: string): Promise<(Contacts & {customers: Customers | null}) | null> { + return this.model.findUnique({ + where: { + cell_phone_number: cell_phone_number, + }, + include: { customers: true } + }); + } } diff --git a/src/common/repositories/EmailRepository.ts b/src/common/repositories/EmailRepository.ts index 82c9fa0f..6f1a7a45 100644 --- a/src/common/repositories/EmailRepository.ts +++ b/src/common/repositories/EmailRepository.ts @@ -26,7 +26,7 @@ export default class EmailRepository extends BaseRepository { /** * @description : Create an email */ - public async create(email: Emails): Promise { + public async create(email: Emails): Promise { const createArgs: Prisma.EmailsCreateArgs = { data: { templateName: email.templateName, diff --git a/src/common/repositories/OfficeFoldersRepository.ts b/src/common/repositories/OfficeFoldersRepository.ts index f918890a..7486b7c7 100644 --- a/src/common/repositories/OfficeFoldersRepository.ts +++ b/src/common/repositories/OfficeFoldersRepository.ts @@ -35,8 +35,12 @@ export default class OfficeFoldersRepository extends BaseRepository { description: officeFolder.description, status: EFolderStatus.LIVE, deed: { - connect: { - uid: officeFolder.deed?.uid, + create: { + deed_type: { + connect: { + uid: officeFolder.deed?.deed_type?.uid, + }, + }, }, }, office: { @@ -121,7 +125,7 @@ export default class OfficeFoldersRepository extends BaseRepository { }, include: { customers: true, - } + }, }); } diff --git a/src/common/system/controller-pattern/BaseController.ts b/src/common/system/controller-pattern/BaseController.ts index b13d997a..7baa9c02 100644 --- a/src/common/system/controller-pattern/BaseController.ts +++ b/src/common/system/controller-pattern/BaseController.ts @@ -45,7 +45,6 @@ export default abstract class BaseController { } protected httpResponse(response: Response, httpCode: HttpCodes, responseData: IResponseData = {}) { - console.log("httpResponse", httpCode, responseData); if (responseData instanceof Error) { throw responseData; } diff --git a/src/services/admin/CustomersService/CustomersService.ts b/src/services/admin/CustomersService/CustomersService.ts index 7656bed2..b4878d7d 100644 --- a/src/services/admin/CustomersService/CustomersService.ts +++ b/src/services/admin/CustomersService/CustomersService.ts @@ -1,12 +1,13 @@ import { Customers, Prisma } from "@prisma/client"; import CustomersRepository from "@Repositories/CustomersRepository"; import BaseService from "@Services/BaseService"; +import ContactsService from "@Services/common/ContactService/ContactService"; import { Customer } from "le-coffre-resources/dist/Admin"; import { Service } from "typedi"; @Service() export default class CustomersService extends BaseService { - constructor(private customerRepository: CustomersRepository) { + constructor(private customerRepository: CustomersRepository, private contactService: ContactsService) { super(); } @@ -23,6 +24,14 @@ export default class CustomersService extends BaseService { * @throws {Error} If customer cannot be created */ public async create(customerEntity: Customer): Promise { + const customers = await this.get({ + where: { + contact: { + OR: [{ email: customerEntity.contact?.email }, { cell_phone_number: customerEntity.contact?.cell_phone_number }], + }, + }, + }); + if(customers[0]) return customers[0]; return this.customerRepository.create(customerEntity); } @@ -31,6 +40,16 @@ export default class CustomersService extends BaseService { * @throws {Error} If customer cannot be modified */ public async update(uid: string, customerEntity: Customer): Promise { + let errors = []; + if(customerEntity.contact?.email) { + const contactWithSameEmail = await this.contactService.getByEmail(customerEntity.contact.email); + if(contactWithSameEmail && contactWithSameEmail.uid != customerEntity.contact.uid) errors.push({property: "email", constraints: {email: "Email déjà utilisé"}}); + } + if(customerEntity.contact?.cell_phone_number) { + const contactWithSamePhoneNumber = await this.contactService.getByPhone(customerEntity.contact.cell_phone_number); + if(contactWithSamePhoneNumber && contactWithSamePhoneNumber.uid != customerEntity.contact.uid) errors.push({property: "cell_phone_number", constraints: {phone: "numéro de téléphone déjà utilisé"}}); + } + if(errors.length != 0) throw errors; return this.customerRepository.update(uid, customerEntity); } diff --git a/src/services/admin/OfficeFoldersService/OfficeFoldersService.ts b/src/services/admin/OfficeFoldersService/OfficeFoldersService.ts index 8d474aef..43953660 100644 --- a/src/services/admin/OfficeFoldersService/OfficeFoldersService.ts +++ b/src/services/admin/OfficeFoldersService/OfficeFoldersService.ts @@ -3,16 +3,12 @@ import OfficeFoldersRepository from "@Repositories/OfficeFoldersRepository"; import BaseService from "@Services/BaseService"; import { OfficeFolder } from "le-coffre-resources/dist/Admin"; import { Service } from "typedi"; -import DeedTypesService from "../DeedTypesService/DeedTypesService"; -import DeedsRepository from "@Repositories/DeedsRepository"; import { Prisma } from "@prisma/client"; @Service() export default class OfficeFoldersService extends BaseService { constructor( private officeFoldersRepository: OfficeFoldersRepository, - private deedTypeService: DeedTypesService, - private deedRepository: DeedsRepository, ) { super(); } @@ -30,11 +26,6 @@ export default class OfficeFoldersService extends BaseService { * @throws {Error} If folder cannot be created */ public async create(officeFolderEntity: OfficeFolder): Promise { - const deedType = await this.deedTypeService.getByUid(officeFolderEntity.deed!.deed_type!.uid!); - if (!deedType) throw new Error("deed type not found"); - if (deedType.archived_at) throw new Error("deed type is archived"); - const deed = await this.deedRepository.create(officeFolderEntity.deed!); - officeFolderEntity.deed!.uid = deed.uid; return this.officeFoldersRepository.create(officeFolderEntity); } diff --git a/src/services/common/ContactService/ContactService.ts b/src/services/common/ContactService/ContactService.ts new file mode 100644 index 00000000..f56f1b83 --- /dev/null +++ b/src/services/common/ContactService/ContactService.ts @@ -0,0 +1,27 @@ +import { Contacts, Customers } from "@prisma/client"; +import ContactsRepository from "@Repositories/ContactRepository"; +import BaseService from "@Services/BaseService"; +import { Service } from "typedi"; + +@Service() +export default class ContactsService extends BaseService { + constructor(private customerRepository: ContactsRepository) { + super(); + } + + /** + * @description : Get all Contacts + * @throws {Error} If Contacts cannot be get + */ + public async getByEmail(email: string): Promise<(Contacts & {customers: Customers | null}) | null> { + return this.customerRepository.findOneByEmail(email); + } + + /** + * @description : Create a new customer + * @throws {Error} If customer cannot be created + */ + public async getByPhone(cell_phone_number: string): Promise<(Contacts & {customers: Customers | null}) | null> { + return this.customerRepository.findOneByPhoneNumber(cell_phone_number); + } +} diff --git a/src/services/common/CronService/CronService.ts b/src/services/common/CronService/CronService.ts index c37c6860..4b46e962 100644 --- a/src/services/common/CronService/CronService.ts +++ b/src/services/common/CronService/CronService.ts @@ -5,6 +5,7 @@ import FilesService from "../FilesService/FilesService"; import IdNotService from "../IdNotService/IdNotService"; import { PrismaClient } from "@prisma/client"; import NotificationBuilder from "@Common/notifications/NotificationBuilder"; +import EmailBuilder from "@Common/emails/EmailBuilder"; // import { PrismaClient } from "@prisma/client"; @Service() @@ -13,7 +14,8 @@ export default class CronService { private mailchimpService: MailchimpService, private filesService: FilesService, private idNotService: IdNotService, - private notificationBuilder: NotificationBuilder + private notificationBuilder: NotificationBuilder, + private emailBuilder: EmailBuilder, ) {} public async sendMails() { @@ -36,7 +38,7 @@ export default class CronService { const cronJob = new CronJob("0 20 * * FRI", async () => { // Every friday at 20:00 try { - await this.mailchimpService.sendRecapEmails(); + await this.emailBuilder.sendRecapEmails(); } catch (e) { console.error(e); } diff --git a/src/services/common/MailchimpService/MailchimpService.ts b/src/services/common/MailchimpService/MailchimpService.ts index 8eb603bf..4e73408c 100644 --- a/src/services/common/MailchimpService/MailchimpService.ts +++ b/src/services/common/MailchimpService/MailchimpService.ts @@ -4,18 +4,14 @@ import { Emails, Prisma } from "@prisma/client"; import { Service } from "typedi"; import MailchimpClient from "@mailchimp/mailchimp_transactional"; import { BackendVariables } from "@Common/config/variables/Variables"; -import UsersService from "@Services/super-admin/UsersService/UsersService"; -import EmailBuilder from "@Common/emails/EmailBuilder"; @Service() export default class MailchimpService extends BaseService { - private static readonly from = "vincent.alamelle@smart-chain.fr"; + private static readonly from = "no-reply@smart-chain.fr"; constructor( private emailRepository: EmailRepository, protected variables: BackendVariables, - private usersService: UsersService, - private emailBuilder: EmailBuilder, ) { super(); } @@ -32,7 +28,7 @@ export default class MailchimpService extends BaseService { * @description : Create a new email * @throws {Error} If email cannot be created */ - public async create(emailEntity: Emails): Promise { + public async create(emailEntity: Emails): Promise { emailEntity.from = MailchimpService.from; return this.emailRepository.create(emailEntity); } @@ -120,10 +116,4 @@ export default class MailchimpService extends BaseService { }; }); } - - public async sendRecapEmails() { - const usersToEmail = await this.usersService.get({ where: { office_folders: { some:{ documents: { some: { document_status: "DEPOSITED" } } }} }, distinct: ["uid"], include: { contact: true } }); - - await this.emailBuilder.sendRecapEmails(usersToEmail); - } } diff --git a/src/services/notary/CustomersService/CustomersService.ts b/src/services/notary/CustomersService/CustomersService.ts index 3202d143..721affd9 100644 --- a/src/services/notary/CustomersService/CustomersService.ts +++ b/src/services/notary/CustomersService/CustomersService.ts @@ -1,12 +1,13 @@ import { Customers, Prisma } from "@prisma/client"; import CustomersRepository from "@Repositories/CustomersRepository"; import BaseService from "@Services/BaseService"; +import ContactsService from "@Services/common/ContactService/ContactService"; import { Customer } from "le-coffre-resources/dist/Notary"; import { Service } from "typedi"; @Service() export default class CustomersService extends BaseService { - constructor(private customerRepository: CustomersRepository) { + constructor(private customerRepository: CustomersRepository, private contactService: ContactsService) { super(); } @@ -39,6 +40,16 @@ export default class CustomersService extends BaseService { * @throws {Error} If customer cannot be modified */ public async update(uid: string, customerEntity: Customer): Promise { + let errors = []; + if(customerEntity.contact?.email) { + const contactWithSameEmail = await this.contactService.getByEmail(customerEntity.contact.email); + if(contactWithSameEmail && contactWithSameEmail.uid != customerEntity.contact.uid) errors.push({property: "email", constraints: {email: "mail déjà utilisé"}}); + } + if(customerEntity.contact?.cell_phone_number) { + const contactWithSamePhoneNumber = await this.contactService.getByPhone(customerEntity.contact.cell_phone_number); + if(contactWithSamePhoneNumber && contactWithSamePhoneNumber.uid != customerEntity.contact.uid) errors.push({property: "cell_phone_number", constraints: {phone: "numéro de téléphone déjà utilisé"}}); + } + if(errors.length != 0) throw errors; return this.customerRepository.update(uid, customerEntity); } diff --git a/src/services/notary/OfficeFoldersService/OfficeFoldersService.ts b/src/services/notary/OfficeFoldersService/OfficeFoldersService.ts index 97fa5680..e2274813 100644 --- a/src/services/notary/OfficeFoldersService/OfficeFoldersService.ts +++ b/src/services/notary/OfficeFoldersService/OfficeFoldersService.ts @@ -3,16 +3,12 @@ import OfficeFoldersRepository from "@Repositories/OfficeFoldersRepository"; import BaseService from "@Services/BaseService"; import { OfficeFolder } from "le-coffre-resources/dist/Notary"; import { Service } from "typedi"; -import DeedTypesService from "../DeedTypesService/DeedTypesService"; -import DeedsRepository from "@Repositories/DeedsRepository"; import { Prisma } from "@prisma/client"; @Service() export default class OfficeFoldersService extends BaseService { constructor( private officeFoldersRepository: OfficeFoldersRepository, - private deedTypeService: DeedTypesService, - private deedRepository: DeedsRepository, ) { super(); } @@ -30,11 +26,6 @@ export default class OfficeFoldersService extends BaseService { * @throws {Error} If folder cannot be created */ public async create(officeFolderEntity: OfficeFolder): Promise { - const deedType = await this.deedTypeService.getByUid(officeFolderEntity.deed!.deed_type!.uid!); - if (!deedType) throw new Error("deed type not found"); - if (deedType.archived_at) throw new Error("deed type is archived"); - const deed = await this.deedRepository.create(officeFolderEntity.deed!); - officeFolderEntity.deed!.uid = deed.uid; return this.officeFoldersRepository.create(officeFolderEntity); } diff --git a/src/services/super-admin/CustomersService/CustomersService.ts b/src/services/super-admin/CustomersService/CustomersService.ts index 5501e1cb..5b8165ee 100644 --- a/src/services/super-admin/CustomersService/CustomersService.ts +++ b/src/services/super-admin/CustomersService/CustomersService.ts @@ -1,12 +1,13 @@ import { Customers, Prisma } from "@prisma/client"; import CustomersRepository from "@Repositories/CustomersRepository"; import BaseService from "@Services/BaseService"; +import ContactsService from "@Services/common/ContactService/ContactService"; import { Customer } from "le-coffre-resources/dist/SuperAdmin"; import { Service } from "typedi"; @Service() export default class CustomersService extends BaseService { - constructor(private customerRepository: CustomersRepository) { + constructor(private customerRepository: CustomersRepository, private contactService: ContactsService) { super(); } @@ -23,6 +24,14 @@ export default class CustomersService extends BaseService { * @throws {Error} If customer cannot be created */ public async create(customerEntity: Customer): Promise { + const customers = await this.get({ + where: { + contact: { + OR: [{ email: customerEntity.contact?.email }, { cell_phone_number: customerEntity.contact?.cell_phone_number }], + }, + }, + }); + if(customers[0]) return customers[0]; return this.customerRepository.create(customerEntity); } @@ -31,6 +40,16 @@ export default class CustomersService extends BaseService { * @throws {Error} If customer cannot be modified */ public async update(uid: string, customerEntity: Customer): Promise { + let errors = []; + if(customerEntity.contact?.email) { + const contactWithSameEmail = await this.contactService.getByEmail(customerEntity.contact.email); + if(contactWithSameEmail && contactWithSameEmail.uid != customerEntity.contact.uid) errors.push({property: "email", constraints: {email: "mail déjà utilisé"}}); + } + if(customerEntity.contact?.cell_phone_number) { + const contactWithSamePhoneNumber = await this.contactService.getByPhone(customerEntity.contact.cell_phone_number); + if(contactWithSamePhoneNumber && contactWithSamePhoneNumber.uid != customerEntity.contact.uid) errors.push({property: "cell_phone_number", constraints: {phone: "numéro de téléphone déjà utilisé"}}); + } + if(errors.length != 0) throw errors; return this.customerRepository.update(uid, customerEntity); } diff --git a/src/services/super-admin/OfficeFoldersService/OfficeFoldersService.ts b/src/services/super-admin/OfficeFoldersService/OfficeFoldersService.ts index 73e72808..ead0f2bb 100644 --- a/src/services/super-admin/OfficeFoldersService/OfficeFoldersService.ts +++ b/src/services/super-admin/OfficeFoldersService/OfficeFoldersService.ts @@ -3,16 +3,12 @@ import OfficeFoldersRepository from "@Repositories/OfficeFoldersRepository"; import BaseService from "@Services/BaseService"; import { OfficeFolder } from "le-coffre-resources/dist/SuperAdmin"; import { Service } from "typedi"; -import DeedTypesService from "../DeedTypesService/DeedTypesService"; -import DeedsRepository from "@Repositories/DeedsRepository"; import { Prisma } from "@prisma/client"; @Service() export default class OfficeFoldersService extends BaseService { constructor( private officeFoldersRepository: OfficeFoldersRepository, - private deedTypeService: DeedTypesService, - private deedRepository: DeedsRepository, ) { super(); } @@ -30,11 +26,6 @@ export default class OfficeFoldersService extends BaseService { * @throws {Error} If folder cannot be created */ public async create(officeFolderEntity: OfficeFolder): Promise { - const deedType = await this.deedTypeService.getByUid(officeFolderEntity.deed!.deed_type!.uid!); - if (!deedType) throw new Error("deed type not found"); - if (deedType.archived_at) throw new Error("deed type is archived"); - const deed = await this.deedRepository.create(officeFolderEntity.deed!); - officeFolderEntity.deed!.uid = deed.uid; return this.officeFoldersRepository.create(officeFolderEntity); } diff --git a/src/test/services/super-admin/CustomersService.test.ts b/src/test/services/super-admin/CustomersService.test.ts index 4b3f383e..01a540cd 100644 --- a/src/test/services/super-admin/CustomersService.test.ts +++ b/src/test/services/super-admin/CustomersService.test.ts @@ -6,10 +6,11 @@ import { PrismaClient } from "@prisma/client"; import { customer, customerContact, customerContact_, customer_ } from "@Test/config/MockedData"; import Container from "typedi"; import CustomersRepository from "@Repositories/CustomersRepository"; +import ContactService from "@Services/common/ContactService/ContactService"; const prisma = new PrismaClient(); -const CustomersServiceTest = new CustomersService(Container.get(CustomersRepository)); +const CustomersServiceTest = new CustomersService(Container.get(CustomersRepository), Container.get(ContactService)); afterAll(async () => { /* diff --git a/src/test/services/super-admin/OfficeFolderService.test.ts b/src/test/services/super-admin/OfficeFolderService.test.ts index 909a6ddd..579d0c7c 100644 --- a/src/test/services/super-admin/OfficeFolderService.test.ts +++ b/src/test/services/super-admin/OfficeFolderService.test.ts @@ -18,15 +18,11 @@ import OfficeFoldersRepository from "@Repositories/OfficeFoldersRepository"; import OfficeFolderService from "@Services/super-admin/OfficeFoldersService/OfficeFoldersService"; import { initCustomers, initDeedType, initDocumentType, initOffice, initUsers } from "@Test/config/Init"; import { OfficeFolder } from "le-coffre-resources/dist/SuperAdmin"; -import DeedTypesService from "@Services/super-admin/DeedTypesService/DeedTypesService"; -import DeedsRepository from "@Repositories/DeedsRepository"; const prisma = new PrismaClient(); const OfficeFolderServiceTest = new OfficeFolderService( - Container.get(OfficeFoldersRepository), - Container.get(DeedTypesService), - Container.get(DeedsRepository), + Container.get(OfficeFoldersRepository) ); beforeAll(async () => {