UNPKG

tuain-ecosystem-lib

Version:

Servicio de gestión mensajería instantanea de la plataforma Tuain

1,051 lines (1,000 loc) 51.9 kB
const { ObjectId } = require('mongodb'); const { dbQueries: { thirdParties: thirdpartyQueries }, collections: { thirdParties: thirdPartiesColl, thirdPartyGroups: thirdPartyGroupsColl, thirdPartyGroupMembers: thirdPartyGroupMembersColl, ecosystemRoles: ecosystemRolesColl, roleRelations: roleRelationsColl, thirdPartyRelations: thirdPartyRelationsColl, userRelations: userRelationsColl, products: productsColl, subproducts: subproductsColl, enabledProducts: enabledProductsColl, }, } = require('../../config'); const THIRD_PARTY_ID_FIELDS = ['shortName']; const THIRD_PARTY_NAME_FIELDS = ['shortName', 'fullName']; const modErrs = { findThird: { notFound: ['01', 'No se encontraron terceros que se ajusten a la búsqueda'], roleNotFound: ['02', 'Rol para el tercero no encontrado'], missingData: ['03', 'Información insuficiente para localizar un tercero'], existingThird: ['04', 'Ya existe un tercero con la identificación solicitada'], }, findRole: { notFound: ['01', 'No se encontraron roles que se ajusten a la búsqueda'], }, createThird: { alreadyExist: ['01', 'Tercero ya existe'], }, modifyThird: { alreadyActive: ['01', 'Tercero ya está activo'], alreadyInactive: ['02', 'Tercero ya está inactivo'], }, addRoleThirdParty: { roleExist: ['01', 'Tercero ya cuenta con el rol solicitado'], roleNotExist: ['02', 'Tercero no cuenta con el rol especificdo'], }, findingGroup: { notFound: ['01', 'No se encontraron grupos que se ajusten a la búsqueda'], alreadyActive: ['02', 'Grupo ya está activo'], alreadyInactive: ['03', 'Grupo ya está inactivo'], emptyGroup: ['04', 'Grupo no tiene miembros'], }, createGroup: { alreadyExist: ['01', 'Tercero ya existe'], }, findRelation: { notFound: ['01', 'Relación no existe'], }, thirdPartyToGroup: { alreadyExist: ['01', 'Tercero ya vinculado al grupo'], notFound: ['02', 'Tercero no vinculado al grupo'], }, relateThirdParties: { alreadyExist: ['01', 'Ya existe una relación con iguales características'], notFound: ['02', 'Relación entre terceros no encontrada'], }, createEnableProduct: { alreadyExist: ['01', 'Habilitación de producto ya existe'], }, findEnableProduct: { notFound: ['01', 'Habilitación de producto no existe'], missingThirdParty: ['02', 'Debe especificar un tercero para la búsqueda'], alreadyExist: ['03', 'Habilitación de producto ya existe'], multipleGroupsAssigned: ['04', 'Asignación del producto en múltiples grupos'], missingProduct: ['05', 'Debe especificar un producto para la búsqueda'], multipleSubProductsAssigned: ['06', 'Asignación del producto en múltiples subproductos'], notHandled: ['07', 'Error no identificado'], }, enableThirdPartyProduct: { enableMissmatch: ['01', 'Asignación inadecuada de producto a tercero'], }, modifyEnableProduct: { alreadyActive: ['01', 'Habilitación de producto ya está activo'], alreadyInactive: ['02', 'Habilitación de producto no está activo'], }, }; class ThirdPartyManager { constructor(getDb, logger, errMgr, options) { this.options = options; this.getDb = getDb; this.logger = logger; this.errMgr = errMgr; this.errMgr.addModuleSet('lib-thirdparties', modErrs); this.thirdPartyIdFields = this.options?.thirdPartyIdFields ?? THIRD_PARTY_ID_FIELDS; this.thirdPartyNameFields = this.options?.thirdPartyNameFields ?? THIRD_PARTY_NAME_FIELDS; } async getRole(reqData) { const { roleId } = reqData; const rolesCol = this.getDb().collection(ecosystemRolesColl); const roleDetail = await rolesCol.findOne(thirdpartyQueries.findById(roleId)); if (!roleDetail) { const errorDetail = `Rol con Id ${roleId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findRole.notFound, errorDetail); return [errorObj, null]; } return [null, roleDetail]; } async getRoleRelation(reqData) { const { roleRelationId } = reqData; const rolesCol = this.getDb().collection(roleRelationsColl); const roleDetail = await rolesCol.findOne(thirdpartyQueries.findById(roleRelationId)); if (!roleDetail) { const errorDetail = `Relación de roles con Id ${roleRelationId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findRole.notFound, errorDetail); return [errorObj, null]; } return [null, roleDetail]; } async getThirdParties(reqData = null, constraints = null) { const { thirdPartyIds } = reqData; const pageNumber = constraints?.requestedPage; const recordsPerPage = constraints?.recordsPerPage || 0; // const currentFilter = constraints.currentFilter; const thirdsCol = this.getDb().collection(thirdPartiesColl); const thirdParties = await thirdsCol.find(thirdpartyQueries.findThirdparties(thirdPartyIds)) .skip(recordsPerPage * (pageNumber - 1)) .limit(recordsPerPage) .sort({ creation: -1 }) .toArray(); return [null, thirdParties]; } async getRoleThirdParties(reqData, constraints = {}) { const { roleId } = reqData; const { sortField, sortDir } = constraints; const thirdsCol = this.getDb().collection(thirdPartiesColl); const thirdPartiesCursor = await thirdsCol.find(thirdpartyQueries.findRoleThirdParties(roleId)); const thirdParties = (sortField && sortDir) ? await thirdPartiesCursor.sort({ [sortField]: sortDir }).toArray() : await thirdPartiesCursor.toArray(); return [null, thirdParties]; } async getThirdParty(reqData) { const { thirdPartyId, idDocType, idDocNumber } = reqData; const thirdsCol = this.getDb().collection(thirdPartiesColl); let thirdDetail; if (thirdPartyId) { thirdDetail = await thirdsCol.findOne(thirdpartyQueries.findById(thirdPartyId)); } else if (!idDocType || !idDocNumber) { const errorObj = this.errMgr.get(modErrs.findThird.missingData); return [errorObj, null]; } else { thirdDetail = await thirdsCol.findOne(thirdpartyQueries.findThirdParty(idDocType, idDocNumber)); } if (!thirdDetail) { const errorDetail = 'Tercero no encontrado'; const errorObj = this.errMgr.get(modErrs.findThird.notFound, errorDetail); return [errorObj, null]; } return [null, thirdDetail]; } async createThirdParty(thirdPartyData) { const thirdsCol = this.getDb().collection(thirdPartiesColl); const findThirdPartyQuery = {}; this.thirdPartyIdFields.forEach((fieldName) => { if (thirdPartyData[fieldName]) { findThirdPartyQuery[fieldName] = thirdPartyData[fieldName]; } }); const existingThirdParty = await thirdsCol.findOne(findThirdPartyQuery); if (existingThirdParty) { const errorObj = this.errMgr.get(modErrs.findThird.existingThird); return [errorObj, null]; } const newThirdPartyData = { ...thirdPartyData, enabled: false, creation: new Date() }; const actionResult = await thirdsCol.insertOne(newThirdPartyData); const thirdPartyId = actionResult?.insertedId; this.logger.debug(`Creación de un nuevo tercero ${newThirdPartyData} con inserción ${thirdPartyId}`); return [null, { thirdPartyId }]; } async modifyThirdParty(reqData) { const { thirdPartyId } = reqData; const thirdsCol = this.getDb().collection(thirdPartiesColl); const thirdDetail = await thirdsCol.findOne(thirdpartyQueries.findById(thirdPartyId)); if (!thirdDetail) { const errorDetail = `Tercero con Id ${thirdPartyId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findThird.notFound, errorDetail); return [errorObj, null]; } const thirdPartyData = { ...reqData }; delete thirdPartyData.thirdPartyId; const actionResult = await thirdsCol.updateOne(thirdpartyQueries.findById(thirdPartyId), thirdpartyQueries.updateObj(thirdPartyData)); const result = actionResult?.result?.nModified > 0; this.logger.debug(`Modificación del tercero ${thirdPartyData} con resultado ${result}`); return [null, { result }]; } async modifyThirdParties(reqData) { const { thirdPartyIds } = reqData; const thirdsCol = this.getDb().collection(thirdPartiesColl); const thirdPartyData = { ...reqData }; delete thirdPartyData.thirdPartyIds; const actionResult = await thirdsCol.updateMany(thirdpartyQueries.findThirdparties(thirdPartyIds), thirdpartyQueries.updateObj(thirdPartyData)); const result = actionResult?.result?.nModified > 0; this.logger.debug(`Modificación de terceros con resultado ${result}`); return [null, { result }]; } async addExternalRefThirdParty(reqData) { const { thirdPartyId, externalSource, externalCode } = reqData; const thirdsCol = this.getDb().collection(thirdPartiesColl); const thirdDetail = await thirdsCol.findOne(thirdpartyQueries.findById(thirdPartyId)); if (!thirdDetail) { const errorDetail = `Tercero con Id ${thirdPartyId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findThird.notFound, errorDetail); return [errorObj, null]; } const currentCoding = thirdDetail.externalCoding?.find(item => item.externalSource === externalSource); if (currentCoding) { await thirdsCol.updateOne(thirdpartyQueries.findById(thirdPartyId), thirdpartyQueries.removeExternalRef(externalSource)); } const externalRefData = { externalSource, externalCode }; const actionResult = await thirdsCol.updateOne(thirdpartyQueries.findById(thirdPartyId), thirdpartyQueries.addExternalRef(externalRefData)); const result = actionResult?.result?.nModified > 0; this.logger.debug(`Adición de una referencia externa a un tercero ${externalRefData} con resultado ${result}`); return [null, { result }]; } async findThirdPartyExternalRef(reqData) { const { externalSource, externalCode } = reqData; const thirdCol = this.getDb().collection(thirdPartiesColl); const thirdDetail = await thirdCol.findOne(thirdpartyQueries .findByExternalRef(externalSource, externalCode)); if (!thirdDetail) { const errorDetail = `Tercero con codigo externo ${externalCode} no encontrado`; const errorObj = this.errMgr.get(modErrs.findThird.notFound, errorDetail); return [errorObj, null]; } if (!thirdDetail.enabled) { const errorDetail = `Tercero con Id ${thirdDetail._id.toString()} actualmente inactivo`; const errorObj = this.errMgr.get(modErrs.modifyThird.alreadyInactive, errorDetail); return [errorObj, null]; } return [null, thirdDetail]; } async activateThirdParty(reqData) { const { thirdPartyId } = reqData; const thirdsCol = this.getDb().collection(thirdPartiesColl); const thirdDetail = await thirdsCol.findOne(thirdpartyQueries.findById(thirdPartyId)); if (!thirdDetail) { const errorDetail = `Tercero con Id ${thirdPartyId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findThird.notFound, errorDetail); return [errorObj, null]; } if (thirdDetail.enabled) { const errorDetail = `Tercero con Id ${thirdPartyId} actualmente activo`; const errorObj = this.errMgr.get(modErrs.modifyThird.alreadyActive, errorDetail); return [errorObj, null]; } const actionResult = await thirdsCol.updateOne(thirdpartyQueries.findById(thirdPartyId), thirdpartyQueries.updateObj({ enabled: true })); const result = actionResult?.result?.nModified > 0; this.logger.debug(`Activación del tercero ${thirdPartyId} con resultado ${result}`); return [null, { result }]; } async inativateThirdParty(reqData) { const { thirdPartyId } = reqData; const thirdsCol = this.getDb().collection(thirdPartiesColl); const thirdDetail = await thirdsCol.findOne(thirdpartyQueries.findById(thirdPartyId)); if (!thirdDetail) { const errorDetail = `Tercero con Id ${thirdPartyId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findThird.notFound, errorDetail); return [errorObj, null]; } if (!thirdDetail.enabled) { const errorDetail = `Tercero con Id ${thirdPartyId} actualmente inactivo`; const errorObj = this.errMgr.get(modErrs.modifyThird.alreadyInactive, errorDetail); return [errorObj, null]; } const actionResult = await thirdsCol.updateOne(thirdpartyQueries.findById(thirdPartyId), thirdpartyQueries.updateObj({ enabled: false })); const result = actionResult?.result?.nModified > 0; this.logger.debug(`Inactivación del tercero ${thirdPartyId} con resultado ${result}`); return [null, { result }]; } async deleteThirdParty(reqData) { const { thirdPartyId } = reqData; const thirdsCol = this.getDb().collection(thirdPartiesColl); const thirdDetail = await thirdsCol.findOne(thirdpartyQueries.findById(thirdPartyId)); if (!thirdDetail) { const errorDetail = `Tercero con Id ${thirdPartyId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findThird.notFound, errorDetail); return [errorObj, null]; } if (thirdDetail.enabled) { const errorDetail = `Tercero con Id ${thirdPartyId} actualmente activo`; const errorObj = this.errMgr.get(modErrs.modifyThird.alreadyActive, errorDetail); return [errorObj, null]; } const actionResult = await thirdsCol.deleteOne(thirdpartyQueries.findById(thirdPartyId)); const result = actionResult?.result?.n > 0; this.logger.debug(`Eliminación del tercero ${thirdPartyId} con resultado ${result}`); return [null, { result }]; } async addRoleThirdParty(reqData) { const { thirdPartyId, roleId } = reqData; const thirdsCol = this.getDb().collection(thirdPartiesColl); const thirdDetail = await thirdsCol.findOne(thirdpartyQueries.findById(thirdPartyId)); if (!thirdDetail) { const errorDetail = `Tercero con Id ${thirdPartyId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findThird.notFound, errorDetail); return [errorObj, null]; } const [getRoleErr, roleDetail] = await this.getRole({ roleId }); if (getRoleErr || !roleDetail) { const errorDetail = `Rol con Id ${roleId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findThird.roleNotFound, errorDetail); return [errorObj, null]; } const existingThirdRole = (thirdDetail.roles && thirdDetail.roles.length > 0) ? thirdDetail.roles.find(item => item.roleId === roleId) : null; if (existingThirdRole) { const errorDetail = `Role con Id ${roleId} ya existe en el tercerop con Id ${thirdPartyId}`; const errorObj = this.errMgr.get(modErrs.addRoleThirdParty.roleExist, errorDetail); return [errorObj, null]; } const roleData = { roleId, enabled: false, creation: new Date() }; delete roleData.thirdPartyId; const actionResult = await thirdsCol.updateOne(thirdpartyQueries.findById(thirdPartyId), thirdpartyQueries.addRole(roleData)); const result = actionResult?.result?.nModified > 0; this.logger.debug(`Adición de un rol a un tercero ${roleData} con resultado ${result}`); return [null, { result }]; } async activateRoleThirdParty(reqData) { const { thirdPartyId, roleId } = reqData; const thirdsCol = this.getDb().collection(thirdPartiesColl); const thirdDetail = await thirdsCol.findOne(thirdpartyQueries.findById(thirdPartyId)); if (!thirdDetail) { const errorDetail = `Tercero con Id ${thirdPartyId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findThird.notFound, errorDetail); return [errorObj, null]; } const existingThirdRole = (thirdDetail.roles && thirdDetail.roles.length > 0) ? thirdDetail.roles.find(item => item.roleId === roleId) : null; if (!existingThirdRole) { const errorDetail = `Role con Id ${roleId} no existe en el tercerop con Id ${thirdPartyId}`; const errorObj = this.errMgr.get(modErrs.addRoleThirdParty.roleNotExist, errorDetail); return [errorObj, null]; } const roleData = { roleId, enabled: true, creation: existingThirdRole.creation }; delete roleData.thirdPartyId; await thirdsCol.updateOne(thirdpartyQueries.findById(thirdPartyId), thirdpartyQueries.removeRole(roleId)); const actionResult = await thirdsCol.updateOne(thirdpartyQueries.findById(thirdPartyId), thirdpartyQueries.addRole(roleData)); const result = actionResult?.result?.nModified > 0; this.logger.debug(`Activación de un rol a un tercero ${roleData} con resultado ${result}`); return [null, { result }]; } async inactivateRoleThirdParty(reqData) { const { thirdPartyId, roleId } = reqData; const thirdsCol = this.getDb().collection(thirdPartiesColl); const thirdDetail = await thirdsCol.findOne(thirdpartyQueries.findById(thirdPartyId)); if (!thirdDetail) { const errorDetail = `Tercero con Id ${thirdPartyId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findThird.notFound, errorDetail); return [errorObj, null]; } const existingThirdRole = (thirdDetail.roles && thirdDetail.roles.length > 0) ? thirdDetail.roles.find(item => item.roleId === roleId) : null; if (!existingThirdRole) { const errorDetail = `Role con Id ${roleId} no existe en el tercerop con Id ${thirdPartyId}`; const errorObj = this.errMgr.get(modErrs.addRoleThirdParty.roleNotExist, errorDetail); return [errorObj, null]; } const roleData = { roleId, enabled: false, creation: existingThirdRole.creation }; delete roleData.thirdPartyId; await thirdsCol.updateOne(thirdpartyQueries.findById(thirdPartyId), thirdpartyQueries.removeRole(roleId)); const actionResult = await thirdsCol.updateOne(thirdpartyQueries.findById(thirdPartyId), thirdpartyQueries.addRole(roleData)); const result = actionResult?.result?.nModified > 0; this.logger.debug(`Inactivación de un rol a un tercero ${roleData} con resultado ${result}`); return [null, { result }]; } /** * Grupos de terceros */ async findGroups(groupData, constraints) { const pageNumber = constraints?.requestedPage || 1; const recordsPerPage = constraints?.recordsPerPage || 50; // const currentFilter = constraints.currentFilter; const thirdsCol = this.getDb().collection(thirdPartyGroupsColl); const thirdParties = await thirdsCol.find() .skip(recordsPerPage * (pageNumber - 1)) .limit(recordsPerPage) .toArray(); return [null, thirdParties]; } async findGroup(reqData) { const { groupId } = reqData; const groupsCol = this.getDb().collection(thirdPartyGroupsColl); const groupDetail = await groupsCol.findOne(thirdpartyQueries.findById(groupId)); if (!groupDetail) { const errorDetail = `Grupo ${groupId} no fue encontrado`; const errorObj = this.errMgr.get(modErrs.createGroup.alreadyExist, errorDetail); return [errorObj, null]; } return [null, groupDetail]; } async createGroup(groupData) { const { ownerId, name } = groupData; const groupsCol = this.getDb().collection(thirdPartyGroupsColl); const groupDetail = await groupsCol.findOne(thirdpartyQueries.findGroup(ownerId, name)); if (groupDetail) { const errorDetail = `Grupo ${name} ya existe para el tercero ${ownerId}`; const errorObj = this.errMgr.get(modErrs.createGroup.alreadyExist, errorDetail); return [errorObj, null]; } const actionResult = await groupsCol.insertOne(thirdpartyQueries.saveGroup(groupData)); this.logger.debug(`Creación de un nuevo grupo ${groupData} con resultado ${actionResult?.insertedId}`); return [null, { groupId: actionResult?.insertedId }]; } async modifyGroup(reqData) { const { groupId } = reqData; const groupsCol = this.getDb().collection(thirdPartyGroupsColl); const groupDetail = await groupsCol.findOne(thirdpartyQueries.findById(groupId)); if (!groupDetail) { const errorDetail = `Grupo con Id ${groupId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findingGroup.notFound, errorDetail); return [errorObj, null]; } const updateData = { ...reqData }; delete updateData.groupId; const actionResult = await groupsCol.updateOne(thirdpartyQueries.findById(groupId), thirdpartyQueries.updateGroup(updateData)); const result = actionResult?.result?.nModified > 0; this.logger.debug(`Modificación de grupo ${groupId} con resultado ${result}`); return [null, { result }]; } async activateGroup(reqData) { const { groupId } = reqData; const groupsCol = this.getDb().collection(thirdPartyGroupsColl); const groupDetail = await groupsCol.findOne(thirdpartyQueries.findById(groupId)); if (!groupDetail) { const errorDetail = `Grupo con Id ${groupId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findingGroup.notFound, errorDetail); return [errorObj, null]; } if (groupDetail.enabled) { const errorDetail = `Grupo con Id ${groupId} actualmente activo`; const errorObj = this.errMgr.get(modErrs.findingGroup.alreadyActive, errorDetail); return [errorObj, null]; } const actionResult = await groupsCol.updateOne(thirdpartyQueries.findById(groupId), thirdpartyQueries.updateObj({ enabled: true })); const result = actionResult?.result?.nModified > 0; this.logger.debug(`Activación del grupo ${groupId} con reultado ${result}`); return [null, { result }]; } async getThirdsGroupByOwner(groupData) { const { ownerId, name, groupType } = groupData; const groupsCol = this.getDb().collection(thirdPartyGroupsColl); const groupDetail = await groupsCol.findOne(thirdpartyQueries .findGroup(ownerId, name, groupType)); if (!groupDetail) { const errorDetail = `No se encontró grupo con ese dueño y nombre ${name}`; const errorObj = this.errMgr.get(modErrs.findingGroup.notFound, errorDetail); return [errorObj, null]; } return [null, groupDetail]; } async getThirdsGroupsByOwner(groupData) { const { ownerId, groupType } = groupData; const groupsCol = this.getDb().collection(thirdPartyGroupsColl); const groups = await groupsCol.find(thirdpartyQueries.findOwnerGroups(ownerId, groupType)).toArray(); if (!groups || groups.length < 1) { const errorDetail = `No se encontraron grupos con dueño ${ownerId}`; const errorObj = this.errMgr.get(modErrs.findingGroup.notFound, errorDetail); return [errorObj, null]; } return [null, groups]; } async getThirdsGroupsByType(groupData) { const { groupType } = groupData; const groupsCol = this.getDb().collection(thirdPartyGroupsColl); const groups = await groupsCol.find({ groupType }).toArray(); if (!groups || groups.length < 1) { const errorDetail = `No se encontraron grupos de tipo ${groupType}`; const errorObj = this.errMgr.get(modErrs.findingGroup.notFound, errorDetail); return [errorObj, null]; } return [null, groups]; } async findThirdPartyGroups(groupData) { const { thirdPartyId } = groupData; const groupMembersCol = this.getDb().collection(thirdPartyGroupMembersColl); const groups = await groupMembersCol.aggregate(thirdpartyQueries .findThirdPartyGroups(thirdPartyId)).toArray(); if (!groups || groups.length === 0) { const errorDetail = `No se encontraon grupos con ${thirdPartyId} en los miembros`; const errorObj = this.errMgr.get(modErrs.findingGroup.notFound, errorDetail); return [errorObj, null]; } return [null, groups]; } async inactivateGroup(reqData) { const { groupId } = reqData; const groupsCol = this.getDb().collection(thirdPartyGroupsColl); const groupDetail = await groupsCol.findOne(thirdpartyQueries.findById(groupId)); if (!groupDetail) { const errorDetail = `Grupo con Id ${groupId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findingGroup.notFound, errorDetail); return [errorObj, null]; } if (!groupDetail.enabled) { const errorDetail = `Grupo con Id ${groupId} actualmente inactivo`; const errorObj = this.errMgr.get(modErrs.findingGroup.alreadyInactive, errorDetail); return [errorObj, null]; } const actionResult = await groupsCol.updateOne(thirdpartyQueries.findById(groupId), thirdpartyQueries.updateObj({ enabled: false })); const result = actionResult?.result?.nModified > 0; this.logger.debug(`Activación del grupo ${groupId} con reultado ${result}`); return [null, { result }]; } async deleteGroup(reqData) { const { groupId } = reqData; const groupsCol = this.getDb().collection(thirdPartyGroupsColl); const groupDetail = await groupsCol.findOne(thirdpartyQueries.findById(groupId)); if (!groupDetail) { const errorDetail = `Grupo con Id ${groupId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findingGroup.notFound, errorDetail); return [errorObj, null]; } if (groupDetail.enabled) { const errorDetail = `Grupo con Id ${groupId} actualmente activo`; const errorObj = this.errMgr.get(modErrs.findingGroup.alreadyActive, errorDetail); return [errorObj, null]; } const actionResult = await groupsCol.deleteOne(thirdpartyQueries.findById(groupId)); const result = actionResult?.result?.n > 0; this.logger.debug(`Eliminación del grupo ${groupId} con resultado ${result}`); return [null, { result }]; } async existThirdGroup(thirdPartyId, groupId) { const membersCol = this.getDb().collection(thirdPartyGroupMembersColl); const memberDetail = await membersCol .findOne(thirdpartyQueries.findThirdGroup(thirdPartyId, groupId)); return memberDetail !== null && memberDetail !== undefined; } async addThirdPartyToGroup(reqData) { const { groupId, thirdPartyId } = reqData; const groupsCol = this.getDb().collection(thirdPartyGroupsColl); const groupDetail = await groupsCol.findOne(thirdpartyQueries.findById(groupId)); if (!groupDetail) { const errorDetail = `Grupo con Id ${groupId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findingGroup.notFound, errorDetail); return [errorObj, null]; } const thirdsCol = this.getDb().collection(thirdPartiesColl); const thirdDetail = await thirdsCol.findOne(thirdpartyQueries.findById(thirdPartyId)); if (!thirdDetail) { const errorDetail = `Tercero con Id ${thirdPartyId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findThird.notFound, errorDetail); return [errorObj, null]; } const existingThirdGroup = await this.existThirdGroup(thirdPartyId, groupId); if (existingThirdGroup) { const errorDetail = `Tercero con Id ${thirdPartyId} ya existe en el grupo con Id ${groupId}`; const errorObj = this.errMgr.get(modErrs.thirdPartyToGroup.alreadyExist, errorDetail); return [errorObj, null]; } const membersCol = this.getDb().collection(thirdPartyGroupMembersColl); const newMemberData = { ...reqData, enabled: false, groupId: ObjectId(groupId), thirdPartyId: ObjectId(thirdPartyId), creation: new Date(), }; const actionResult = await membersCol.insertOne(newMemberData); this.logger.debug(`Adición de un tercero a un grupo ${newMemberData} con resultado ${actionResult?.insertedId}`); return [null, { membershipId: actionResult?.insertedId }]; } async addThirdPartiesToGroup(reqData) { const { groupId, thirdPartyIds } = reqData; const groupsCol = this.getDb().collection(thirdPartyGroupsColl); const groupDetail = await groupsCol.findOne(thirdpartyQueries.findById(groupId)); if (!groupDetail) { const errorDetail = `Grupo con Id ${groupId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findingGroup.notFound, errorDetail); return [errorObj, null]; } const thirdPartObjectId = thirdPartyIds.map(id => ObjectId(id)); const thirdsCol = this.getDb().collection(thirdPartiesColl); const actualThirdParties = await thirdsCol.find({ _id: { $in: thirdPartObjectId } }, { _id: 1 }).toArray(); let actualThirdPartiesIds = actualThirdParties.map(thirdParty => thirdParty._id); const membersCol = this.getDb().collection(thirdPartyGroupMembersColl); const alreadyMembers = await membersCol.find(thirdpartyQueries .findThirdPartiesInGroup(groupId, thirdPartyIds), { _id: 1 }).toArray(); const alreadyMembersIds = alreadyMembers.map(thirdParty => thirdParty._id); actualThirdPartiesIds = actualThirdPartiesIds.filter(thrd => !alreadyMembersIds.includes(thrd)); const creation = new Date(); const groupIdToAdd = ObjectId(groupId); const recordsToAdd = actualThirdPartiesIds.map(thirdPartyId => ({ groupId: groupIdToAdd, thirdPartyId, enabled: true, creation, })); await membersCol.insertMany(recordsToAdd); return [null, { storesAdded: actualThirdPartiesIds.length }]; } async cleanThirdPartyGroup(reqData) { const { groupId } = reqData; const groupsCol = this.getDb().collection(thirdPartyGroupsColl); const groupDetail = await groupsCol.findOne(thirdpartyQueries.findById(groupId)); if (!groupDetail) { const errorDetail = `Grupo con Id ${groupId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findingGroup.notFound, errorDetail); return [errorObj, null]; } const membersCol = this.getDb().collection(thirdPartyGroupMembersColl); await membersCol.deleteMany({ groupId: ObjectId(groupId) }); return [null, null]; } async getThirdPartyGroupMembers(reqData) { const { groupId } = reqData; const groupsCol = this.getDb().collection(thirdPartyGroupsColl); const groupDetail = await groupsCol.findOne(thirdpartyQueries.findById(groupId)); if (!groupDetail) { const errorDetail = `Grupo con Id ${groupId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findingGroup.notFound, errorDetail); return [errorObj, null]; } const membersCol = this.getDb().collection(thirdPartyGroupMembersColl); const groupMembers = await membersCol.find(thirdpartyQueries.findGroupMembers(groupId)).toArray(); if (!groupMembers || groupMembers?.length === 0) { const errorDetail = `Grupo con Id ${groupId} vacío`; const errorObj = this.errMgr.get(modErrs.findingGroup.emptyGroup, errorDetail); return [errorObj, null]; } return [null, groupMembers]; } async getThirdPartyGroupMembersDetail(reqData) { const { groupId } = reqData; const groupsCol = this.getDb().collection(thirdPartyGroupsColl); const groupDetail = await groupsCol.findOne(thirdpartyQueries.findById(groupId)); if (!groupDetail) { const errorDetail = `Grupo con Id ${groupId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findingGroup.notFound, errorDetail); return [errorObj, null]; } const membersCol = this.getDb().collection(thirdPartyGroupMembersColl); const groupMembersDetail = await membersCol .aggregate(thirdpartyQueries.findGroupMembersDetail(groupId)).toArray(); if (!groupMembersDetail || groupMembersDetail?.length === 0) { const errorDetail = `Grupo con Id ${groupId} vacío`; const errorObj = this.errMgr.get(modErrs.findingGroup.emptyGroup, errorDetail); return [errorObj, null]; } return [null, groupMembersDetail]; } async deleteThirdPartyFromGroup(reqData) { const { membershipId, groupId, thirdPartyId } = reqData; const membersCol = this.getDb().collection(thirdPartyGroupMembersColl); const membershipQuery = (membershipId) ? thirdpartyQueries.findById(membershipId) : { groupId: ObjectId(groupId), thirdPartyId: ObjectId(thirdPartyId) }; const membershipDetail = await membersCol.findOne(membershipQuery); if (!membershipDetail) { const errorDetail = (membershipId) ? `No existe membresía a grupo con Id ${membershipId}` : `No existe membresía al grupo ${groupId} para ${thirdPartyId}`; const errorObj = this.errMgr.get(modErrs.thirdPartyToGroup.notFound, errorDetail); return [errorObj, null]; } const membershipIdFound = membershipDetail?._id; const actionResult = await membersCol.deleteOne(thirdpartyQueries.findById(membershipIdFound)); const result = actionResult?.result?.n > 0; this.logger.debug(`Eliminación de membreía ${membershipId} con resultado ${result}`); return [null, { result }]; } async deleteThirdPartiesFromGroup(reqData) { const { groupId, thirdPartyIds } = reqData; if (!groupId || !thirdPartyIds || thirdPartyIds.length === 0) { const errorDetail = `Información insuficuente para eliminar terceros del grupo ${groupId}`; const errorObj = this.errMgr.get(modErrs.findingGroup.notFound, errorDetail); return [errorObj, null]; } const membersCol = this.getDb().collection(thirdPartyGroupMembersColl); const actionResult = await membersCol.deleteMany(thirdpartyQueries .findThirdPartiesInGroup(groupId, thirdPartyIds)); const result = actionResult?.result?.n > 0; return [null, { result }]; } async moveGroupMembers(reqData) { const { sourceGroupId, destinationGroupId } = reqData; const groupsCol = this.getDb().collection(thirdPartyGroupsColl); const sourceGroupDetailPrms = groupsCol.findOne(thirdpartyQueries.findById(sourceGroupId)); const destGroupDetailPrms = groupsCol.findOne(thirdpartyQueries.findById(destinationGroupId)); const [sourceGroupDetail, destGroupDetail] = await Promise .all([sourceGroupDetailPrms, destGroupDetailPrms]); if (!sourceGroupDetail) { const errorDetail = `Grupo con Id ${sourceGroupDetail} no encontrado`; const errorObj = this.errMgr.get(modErrs.findingGroup.notFound, errorDetail); return [errorObj, null]; } if (!destGroupDetail) { const errorDetail = `Grupo con Id ${destGroupDetail} no encontrado`; const errorObj = this.errMgr.get(modErrs.findingGroup.notFound, errorDetail); return [errorObj, null]; } const membersCol = this.getDb().collection(thirdPartyGroupMembersColl); const actionResult = await membersCol.update(thirdpartyQueries.findMembers(sourceGroupId), thirdpartyQueries.updateObj({ groupId: destinationGroupId })); const result = actionResult?.result?.nModified > 0; this.logger.debug(`Movimiento de miembros de grupo ${sourceGroupId} hacia ${destinationGroupId} con resultado ${result}`); return [null, { result }]; } /** * Relacionamiento de terceros */ async relateThirdParties(reqData) { const { primaryThirdParty, secondaryThirdParty, roleRelationId } = reqData; const thirdRelationsCol = this.getDb().collection(thirdPartyRelationsColl); const thirdRelationDetail = await thirdRelationsCol.findOne(thirdpartyQueries .findThirdRelation(primaryThirdParty, secondaryThirdParty, roleRelationId)); if (thirdRelationDetail) { const errorDetail = `Relación existente entre ${firstThirdDetail} y ${secondThirdDetail} de tipo ${roleRelationId}`; const errorObj = this.errMgr.get(modErrs.relateThirdParties.alreadyExist, errorDetail); return [errorObj, null]; } const thirdsCol = this.getDb().collection(thirdPartiesColl); const roleRelationsCol = this.getDb().collection(roleRelationsColl); const relationDetailPrms = roleRelationsCol.findOne(thirdpartyQueries.findById(roleRelationId)); const firstThirdDetailPrms = thirdsCol.findOne(thirdpartyQueries.findById(primaryThirdParty)); const secondThirdDetailPrms = thirdsCol.findOne(thirdpartyQueries.findById(secondaryThirdParty)); const [firstThirdDetail, secondThirdDetail, relationDetail] = await Promise .all([firstThirdDetailPrms, secondThirdDetailPrms, relationDetailPrms]); if (!relationDetail || !relationDetail.primaryRoleId || !relationDetail.secondaryRoleId) { const errorDetail = `Relación entre roles con Id ${roleRelationId} no encontrada`; const errorObj = this.errMgr.get(modErrs.findRelation.notFound, errorDetail); return [errorObj, null]; } if (!firstThirdDetail) { const errorDetail = `Tercero con Id ${primaryThirdParty} no encontrado`; const errorObj = this.errMgr.get(modErrs.findThird.notFound, errorDetail); return [errorObj, null]; } const firstHasRole = firstThirdDetail.roles && firstThirdDetail.roles .find(item => item.roleId === relationDetail.primaryRoleId); if (!firstHasRole) { const errorDetail = `Tercero con Id ${primaryThirdParty} no tiene el rol ${relationDetail.primaryRoleId}`; const errorObj = this.errMgr.get(modErrs.findThird.roleNotFound, errorDetail); return [errorObj, null]; } if (!secondThirdDetail) { const errorDetail = `Tercero con Id ${secondaryThirdParty} no encontrado`; const errorObj = this.errMgr.get(modErrs.findThird.notFound, errorDetail); return [errorObj, null]; } const secondHasRole = secondThirdDetail.roles && secondThirdDetail.roles .find(item => item.roleId === relationDetail.secondaryRoleId); if (!secondHasRole) { const errorDetail = `Tercero con Id ${secondaryThirdParty} no tiene el rol ${relationDetail.secondaryRoleId}`; const errorObj = this.errMgr.get(modErrs.findThird.roleNotFound, errorDetail); return [errorObj, null]; } const newRelationData = { primaryThirdParty: ObjectId(primaryThirdParty), secondaryThirdParty: ObjectId(secondaryThirdParty), roleRelationId, enabled: true, creation: new Date(), }; const actionResult = await thirdRelationsCol.insertOne(newRelationData); this.logger.debug(`Creación de relación ${newRelationData} con resultado ${actionResult?.insertedId}`); return [null, { thirdPartyRelationId: actionResult?.insertedId }]; } async deleteThirdPartiesRelation(reqData) { const { thirdPartyRelationId } = reqData; const thirdRelationsCol = this.getDb().collection(thirdPartyRelationsColl); const thirdRelationDetail = await thirdRelationsCol .findOne(thirdpartyQueries.findById(thirdPartyRelationId)); if (!thirdRelationDetail) { const errorObj = this.errMgr.get(modErrs.relateThirdParties.notFound); return [errorObj, null]; } const actionResult = await thirdRelationsCol .deleteOne(thirdpartyQueries.findById(thirdPartyRelationId)); const result = actionResult?.result?.n > 0; this.logger.debug(`Eliminación de la relación ${thirdPartyRelationId} con resultado ${result}`); return [null, { result }]; } async unrelateThirdParties(reqData) { const { primaryThirdParty, secondaryThirdParty, roleRelationId } = reqData; const thirdRelationsCol = this.getDb().collection(thirdPartyRelationsColl); const thirdRelationDetail = await thirdRelationsCol.findOne(thirdpartyQueries .findThirdRelation(primaryThirdParty, secondaryThirdParty, roleRelationId)); if (!thirdRelationDetail) { const errorObj = this.errMgr.get(modErrs.relateThirdParties.alreadyExist); return [errorObj, null]; } const thirdPartyRelationId = thirdRelationDetail._id; const actionResult = await thirdRelationsCol .deleteOne(thirdpartyQueries.findById(thirdPartyRelationId)); const result = actionResult?.result?.n > 0; this.logger.debug(`Eliminación de la relación ${thirdPartyRelationId} entre ${primaryThirdParty}, ${secondaryThirdParty} de tipo ${roleRelationId} resultado ${result}`); return [null, { result }]; } async getRelatedThirdParties(reqData) { const { primaryThirdParty, secondaryThirdParty, roleRelationId, primaryFields } = reqData; const thirdRelationsCol = this.getDb().collection(thirdPartyRelationsColl); const thirdsCol = this.getDb().collection(thirdPartiesColl); let thirdParties; if (primaryThirdParty) { const firstThirdDetail = await thirdsCol.findOne(thirdpartyQueries.findById(primaryThirdParty)); if (!firstThirdDetail) { const errorDetail = `Tercero con Id ${firstThirdDetail} no encontrado`; const errorObj = this.errMgr.get(modErrs.findThird.notFound, errorDetail); return [errorObj, null]; } thirdParties = await thirdRelationsCol.aggregate(thirdpartyQueries .findThirdsByPrimary(primaryThirdParty, roleRelationId)).toArray(); } else if (secondaryThirdParty) { const secondaryThirdDetail = await thirdsCol.findOne(thirdpartyQueries.findById(secondaryThirdParty)); if (!secondaryThirdDetail) { const errorDetail = `Tercero con Id ${secondaryThirdDetail} no encontrado`; const errorObj = this.errMgr.get(modErrs.findThird.notFound, errorDetail); return [errorObj, null]; } thirdParties = await thirdRelationsCol.aggregate(thirdpartyQueries .findThirdsBySecondary(secondaryThirdParty, roleRelationId)).toArray(); } else { thirdParties = await thirdRelationsCol.aggregate(thirdpartyQueries .findRelatedThirdParties(roleRelationId, primaryFields)).toArray(); } return [null, thirdParties]; } async findThirdPartyByUser(reqData) { const { userId } = reqData; const userRelationsCol = this.getDb().collection(userRelationsColl); const userThirdPartyInfo = await userRelationsCol.findOne(thirdpartyQueries .findThirdPartyByUserId(userId)); if (!userThirdPartyInfo) { const errorDetail = `No se encontró tercero con usuario ${userId}`; const errorObj = this.errMgr.get(modErrs.findThird.notFound, errorDetail); return [errorObj, null]; } const thirdCol = this.getDb().collection(thirdPartiesColl); const thirdParty = await thirdCol.findOne(thirdpartyQueries .findById(userThirdPartyInfo?.thirdPartyId)); if (!thirdParty) { const errorDetail = `Tercero con usuario ${userId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findThird.notFound, errorDetail); return [errorObj, null]; } return [null, thirdParty]; } /** * Thirdparty Products */ async getThirdPartyProducts(reqData) { const { thirdPartyId, productId, subproductId, groupId } = reqData; let message; if (!thirdPartyId) { const errorObj = this.errMgr.get(modErrs.findEnableProduct.missingThirdParty); return [errorObj, null]; } const enableProdCol = this.getDb().collection(enabledProductsColl); const productMatch = await enableProdCol.find(thirdpartyQueries .findEnabledProducts(thirdPartyId, productId, subproductId, groupId)).toArray(); if (!productMatch || productMatch?.length === 0) { message = `El producto ${subproductId ?? productId} no ha sido habilitado para el tercero ${thirdPartyId}`; const errorObj = this.errMgr.get(modErrs.findEnableProduct.notFound, message); return [errorObj, null]; } return [null, productMatch]; } async getThirdPartyProduct(reqData) { const { productId, subproductId, thirdPartyId, groupId } = reqData; let message; if (!thirdPartyId) { const errorObj = this.errMgr.get(modErrs.findEnableProduct.missingThirdParty); return [errorObj, null]; } if (!productId) { const errorObj = this.errMgr.get(modErrs.findEnableProduct.missingProduct); return [errorObj, null]; } const [, thirdPartyInfo] = await this.getThirdParty({ thirdPartyId }); let thirdPartyName = `${thirdPartyId}`; for (let index = 0; index < this.thirdPartyNameFields.length; index++) { const nameField = this.thirdPartyNameFields[index]; if (thirdPartyInfo[nameField]) { thirdPartyName = thirdPartyInfo[nameField]; break; } } if (!thirdPartyInfo) { message = `Tercero ${thirdPartyId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findEnableProduct.missingThirdParty); return [errorObj, null]; } const productCol = this.getDb().collection(productsColl); const { name: productName } = await productCol.findOne(thirdpartyQueries.findById(productId)); if (!productName) { message = `Producto ${productId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findEnableProduct.missingProduct); return [errorObj, null]; } const subprodCol = this.getDb().collection(subproductsColl); const subproductInfo = subproductId ? (await subprodCol.findOne(thirdpartyQueries.findById(subproductId))) : null; const subproductName = subproductInfo?.name ?? null; if (subproductId && !productName) { message = `Subproducto ${subproductId} de ${productName} no encontrado`; const errorObj = this.errMgr.get(modErrs.findEnableProduct.missingProduct); return [errorObj, null]; } // Se localiza la habilitación del producto/subproducto para el tercero (y grupo) const enableProdCol = this.getDb().collection(enabledProductsColl); const productMatch = await enableProdCol.find(thirdpartyQueries .findEnabledProducts(thirdPartyId, productId, subproductId, groupId)).toArray(); if (!productMatch || !Array.isArray(productMatch) || productMatch?.length === 0) { message = `El producto ${productName} ${subproductName ? ' / ' + subproductName : ''} no ha sido habilitado para el tercero ${thirdPartyName}`; message += (groupId) ? ` en el grupo ${groupId}` : ''; const errorObj = this.errMgr.get(modErrs.findEnableProduct.notFound, message); return [errorObj, null]; } if (productMatch?.length === 1) { return [null, productMatch?.[0]]; } // Se identifica la causa de múltiples match de producto const subProductsInvolved = [...new Set(productMatch.filter(item => item.subproductId) .map(item => item.subproductId))]; const goupsInvolved = [...new Set(productMatch.filter(item => item.groupId).map(item => item.groupId))]; if (!groupId && goupsInvolved.length > 1) { message = `Existen múltiples asignaciones para el tercero ${thirdPartyName} en múltiples grupos, debe especificar el grupo`; const errorObj = this.errMgr.get(modErrs.findEnableProduct.multipleGroupsAssigned, message); return [errorObj, null]; } if (!subproductId && subProductsInvolved.length > 1) { message = `Existen múltiples asignaciones para el tercero ${thirdPartyName} en múltiples subproductos de ${productName}, debe especificar el subproducto`; const errorObj = this.errMgr.get(modErrs.findEnableProduct.multipleSubProductsAssigned, message); return [errorObj, null]; } message = `Error obteniendo información del producto ${productId} ${subproductId ? ' / ' + subproductId : ''} para el tercero ${thirdPartyId} ${groupId ? ' en el grupo ' + groupId : ''}`; const errorObj = this.errMgr.get(modErrs.findEnableProduct.notHandled, message); return [errorObj, null]; } async enableThirdPartyProduct(reqData) { const { productId, subproductId, thirdPartyId, groupId } = reqData; let enabledProductId = reqData?.enabledProductId; let message; if (!thirdPartyId) { const errorObj = this.errMgr.get(modErrs.findEnableProduct.missingThirdParty); return [errorObj, null]; } if (!productId) { const errorObj = this.errMgr.get(modErrs.findEnableProduct.missingProduct); return [errorObj, null]; } const [, thirdPartyInfo] = await this.getThirdParty({ thirdPartyId }); let thirdPartyName = `${thirdPartyId}`; for (let index = 0; index < this.thirdPartyNameFields.length; index++) { const nameField = this.thirdPartyNameFields[index]; if (thirdPartyInfo[nameField]) { thirdPartyName = thirdPartyInfo[nameField]; break; } } if (!thirdPartyName) { message = `Tercero ${thirdPartyId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findEnableProduct.missingThirdParty); return [errorObj, null]; } const productCol = this.getDb().collection(productsColl); const { name: productName } = await productCol.findOne(thirdpartyQueries.findById(productId)) ?? {}; if (!productName) { message = `Producto ${productId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findEnableProduct.missingProduct); return [errorObj, null]; } const enableProdCol = this.getDb().collection(enabledProductsColl); if (!enabledProductId) { const productMatch = await enableProdCol.find(thirdpartyQueries .findEnabledProducts(thirdPartyId, productId, subproductId, groupId)).toArray(); if (productMatch?.length > 0) { // Se identifica la causa de match de producto const goupsInvolved = [...new Set(productMatch.filter(item => item.groupId).map(item => item.groupId))]; const subProductsInvolved = [...new Set(productMatch.filter(item => item.subproductId) .map(item => item.subproductId))]; if (!subproductId && subProductsInvolved.length > 0) { message = `Asignación del Producto ${productName} a ${thirdPartyName} debe contener subproducto`; const errorObj = this.errMgr.get(modErrs.enableThirdPartyProduct.enableMissmatch); return [errorObj, null]; } if (!groupId && goupsInvolved.length > 0) { message = `Asignación del Producto ${productName} a ${thirdPartyName} debe contener grupo`; const errorObj = this.errMgr.get(modErrs.enableThirdPartyProduct.enableMissmatch, message); return [errorObj, null]; } message = 'Habilitación de producto ya existente'; const errorObj = this.errMgr.get(modErrs.findEnableProduct.alreadyExist, message); return [errorObj, null]; } const newThirdProduct = { ...reqData, thirdPartyId: ObjectId(thirdPartyId), productId: ObjectId(produ