From 2686249cc90dbbdab0e1be506d3bb8d8fd00f3b1 Mon Sep 17 00:00:00 2001 From: vchikalkin Date: Fri, 11 Jul 2025 13:38:42 +0300 Subject: [PATCH] feat: enhance order creation validation with additional checks for client, slot, and service --- .../order/content-types/order/lifecycles.ts | 81 ++++++++++++++----- 1 file changed, 59 insertions(+), 22 deletions(-) diff --git a/src/api/order/content-types/order/lifecycles.ts b/src/api/order/content-types/order/lifecycles.ts index e424a9d..8845921 100644 --- a/src/api/order/content-types/order/lifecycles.ts +++ b/src/api/order/content-types/order/lifecycles.ts @@ -2,6 +2,12 @@ const ERR_INVALID_TIME = 'Некорректное время'; const ERR_OVERLAPPING_TIME = 'Время пересекается с другими заказами'; const ERR_INACTIVE_CLIENT = 'Клиент не активен'; const ERR_INACTIVE_MASTER = 'Мастер не активен'; +const ERR_SLOT_CLOSED = 'Слот закрыт'; +const ERR_INVALID_CLIENT = 'Некорректный клиент'; +const ERR_INVALID_MASTER = 'Некорректный мастер'; +const ERR_MISSING_CLIENT = 'Не указан клиент'; +const ERR_MISSING_SLOT = 'Не указан слот'; +const ERR_MISSING_SERVICE = 'Не указан сервис'; function timeToDate(time: string) { return new Date(`1970-01-01T${time}Z`); @@ -26,47 +32,79 @@ function extractId(input: any): number | null { export default { async beforeCreate(event) { const { data } = event.params; - const { time_start, time_end, client } = data; + const { time_start, time_end, client, services } = data; const clientId = extractId(client); - const slotId = extractId(data.slot); + // Проверка наличия обязательных полей + if (!slotId) throw new Error(ERR_MISSING_SLOT); + if (!clientId) throw new Error(ERR_MISSING_CLIENT); + if (!extractId(services)) throw new Error(ERR_MISSING_SERVICE); + + // Проверка корректности времени заказа. if (!time_start || !time_end) { throw new Error(ERR_INVALID_TIME); } - if (timeToDate(time_start) >= timeToDate(time_end)) { throw new Error(ERR_INVALID_TIME); } - const isClientActive = await strapi.db + // Получаем слот + const slot = await strapi.db.query('api::slot.slot').findOne({ + where: { id: slotId }, + populate: ['master'], + }); + if (!slot) throw new Error(ERR_MISSING_SLOT); + + // 1. Слот не должен быть закрыт + if (slot.state === 'closed') { + throw new Error(ERR_SLOT_CLOSED); + } + + // Получаем клиента + const clientEntity = await strapi.db .query('api::customer.customer') .findOne({ - where: { - id: clientId, - active: true, - }, + where: { id: clientId }, + populate: { masters: true }, }); + console.log('🚀 ~ clientEntity ~ clientEntity:', clientEntity); + if (!clientEntity) throw new Error(ERR_MISSING_CLIENT); - if (!isClientActive) { + // Проверка активности клиента + if (!clientEntity.active) { throw new Error(ERR_INACTIVE_CLIENT); } - const slot = await strapi.db.query('api::slot.slot').findOne({ - where: { - id: slotId, - }, - populate: ['master'], - }); - - const master = slot.master; - - const isMasterActive = master.active && master.role === 'master'; - - if (!isMasterActive) { + // Получаем мастера слота + const slotMaster = slot.master; + if (!slotMaster) throw new Error(ERR_INVALID_MASTER); + if (!slotMaster.active || slotMaster.role !== 'master') { throw new Error(ERR_INACTIVE_MASTER); } + // 2. Проверка ролей и связей + const isClientMaster = clientEntity.role === 'master'; + const slotMasterId = slotMaster.id; + + if (!isClientMaster) { + // Клиент не должен быть мастером слота + if (clientEntity.id === slotMasterId) { + throw new Error(ERR_INVALID_CLIENT); + } + // Клиент должен быть в списке клиентов мастера + const masters = clientEntity.masters?.map(m => m.id) || []; + if (!masters.includes(slotMasterId)) { + throw new Error(ERR_INVALID_MASTER); + } + } else { + // Мастер не может записать другого мастера + if (slotMasterId !== clientEntity.id) { + throw new Error(ERR_INVALID_MASTER); + } + } + + // Проверка пересечений заказов по времени. const overlappingEntities = await strapi.db .query('api::order.order') .findMany({ @@ -83,7 +121,6 @@ export default { }, populate: ['slot'], }); - if (overlappingEntities.length > 0) { throw new Error(ERR_OVERLAPPING_TIME); }