diff --git a/packages/graphql/api/orders.test.js b/packages/graphql/api/orders.test.js new file mode 100644 index 0000000..384d6c5 --- /dev/null +++ b/packages/graphql/api/orders.test.js @@ -0,0 +1,796 @@ +import { getClientWithToken } from '../apollo/client'; +import * as GQL from '../types'; +import { CustomersService } from './customers'; +import { ERRORS, OrdersService } from './orders'; +import { ServicesService } from './services'; +import { SlotsService } from './slots'; +import dayjs from 'dayjs'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +vi.mock('../apollo/client'); +vi.mock('./customers'); +vi.mock('./services'); +vi.mock('./slots'); +vi.mock('../config/env', () => { + return { + env: { + BOT_TOKEN: 'test', + LOGIN_GRAPHQL: 'test', + PASSWORD_GRAPHQL: 'test', + URL_GRAPHQL: 'test', + }, + }; +}); + +const mockGetClientWithToken = vi.mocked(getClientWithToken); +const mockCustomersService = vi.mocked(CustomersService); +const mockServicesService = vi.mocked(ServicesService); +const mockSlotsService = vi.mocked(SlotsService); + +describe('OrdersService', () => { + /** + * @type {OrdersService} + */ + let ordersService; + const mockUser = { telegramId: 123_456_789 }; + + const mockCustomer = { + active: true, + documentId: 'customer-123', + firstName: 'John', + lastName: 'Doe', + role: GQL.Enum_Customer_Role.Customer, + telegramId: 123_456_789, + }; + + const mockMaster = { + active: true, + documentId: 'master-123', + firstName: 'Jane', + lastName: 'Master', + role: GQL.Enum_Customer_Role.Master, + telegramId: 987_654_321, + }; + + const now = dayjs().minute(0).second(0).millisecond(0); + vi.setSystemTime(now.toDate()); + + const mockSlot = { + datetime_end: now.add(6, 'hour').toISOString(), + datetime_start: now.toISOString(), + documentId: 'slot-123', + master: mockMaster, + orders: [], + state: GQL.Enum_Slot_State.Open, + }; + + const mockService = { + active: true, + documentId: 'service-123', + duration: '01:00:00', // 1 час + master: mockMaster, + name: 'Test Service', + }; + + const mockOrder = { + client: mockCustomer, + datetime_end: now.add(1, 'hour').toISOString(), + datetime_start: now.toISOString(), + documentId: 'order-123', + services: [mockService], + slot: mockSlot, + state: GQL.Enum_Order_State.Created, + }; + + const mockGetCustomerResult = { + data: { + customers: [mockCustomer], + }, + }; + + beforeEach(() => { + ordersService = new OrdersService(mockUser); + vi.clearAllMocks(); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + describe('createOrder', () => { + const mockVariables = { + input: { + client: 'customer-123', + datetime_end: now.add(1, 'hour').toISOString(), + datetime_start: now.toISOString(), + services: ['service-123'], + slot: 'slot-123', + }, + }; + + const mockMutationResult = { + data: { + createOrder: mockOrder, + }, + errors: undefined, + }; + + it('should successfully create order for customer', async () => { + const mockMutate = vi.fn().mockResolvedValue(mockMutationResult); + const mockQuery = vi.fn().mockImplementation(({ query }) => { + if (query === GQL.GetCustomerDocument) { + return Promise.resolve(mockGetCustomerResult); + } + + if (query === GQL.GetOrdersDocument) { + return Promise.resolve({ data: { orders: [] } }); // нет пересекающихся заказов + } + + return Promise.resolve({ data: {} }); + }); + + mockGetClientWithToken.mockResolvedValue({ + mutate: mockMutate, + query: mockQuery, + }); + + // Мокаем ServicesService.getService + const mockGetService = vi.fn().mockResolvedValue({ + service: mockService, + }); + mockServicesService.mockImplementation(() => ({ + getService: mockGetService, + })); + + // Мокаем SlotsService.getSlot + const mockGetSlot = vi.fn().mockResolvedValue({ + slot: mockSlot, + }); + mockSlotsService.mockImplementation(() => ({ + getSlot: mockGetSlot, + })); + + // Мокаем CustomersService.getCustomer + const mockGetCustomer = vi.fn().mockResolvedValue({ + customer: mockCustomer, + }); + mockCustomersService.mockImplementation(() => ({ + getCustomer: mockGetCustomer, + getMasters: vi.fn().mockResolvedValue({ + masters: [mockMaster], + }), + })); + + const result = ordersService.createOrder(mockVariables); + + await expect(result).resolves.toBe(mockMutationResult.data); + }); + + it('should successfully create approved order for master', async () => { + const masterCustomer = { + ...mockCustomer, + role: GQL.Enum_Customer_Role.Master, + }; + + const masterSlot = { + ...mockSlot, + master: masterCustomer, + }; + + const mockMutate = vi.fn().mockResolvedValue(mockMutationResult); + const mockQuery = vi.fn().mockImplementation(({ query }) => { + if (query === GQL.GetCustomerDocument) { + return Promise.resolve({ + data: { customers: [masterCustomer] }, + }); + } + + if (query === GQL.GetOrdersDocument) { + return Promise.resolve({ data: { orders: [] } }); + } + + return Promise.resolve({ data: {} }); + }); + + mockGetClientWithToken.mockResolvedValue({ + mutate: mockMutate, + query: mockQuery, + }); + + const mockGetService = vi.fn().mockResolvedValue({ + service: mockService, + }); + mockServicesService.mockImplementation(() => ({ + getService: mockGetService, + })); + + const mockGetSlot = vi.fn().mockResolvedValue({ + slot: masterSlot, + }); + mockSlotsService.mockImplementation(() => ({ + getSlot: mockGetSlot, + })); + + const mockGetCustomer = vi.fn().mockResolvedValue({ + customer: masterCustomer, + }); + mockCustomersService.mockImplementation(() => ({ + getCustomer: mockGetCustomer, + getMasters: vi.fn().mockResolvedValue({ + masters: [masterCustomer], + }), + })); + + const result = ordersService.createOrder({ + ...mockVariables, + input: { + ...mockVariables.input, + client: masterCustomer.documentId, + }, + }); + + await expect(result).resolves.toBe(mockMutationResult.data); + }); + + it('should throw error when slot is missing', async () => { + const variablesWithoutSlot = { + input: { + client: 'customer-123', + datetime_start: now.toISOString(), + services: ['service-123'], + }, + }; + + const result = ordersService.createOrder(variablesWithoutSlot); + + await expect(result).rejects.toThrow(ERRORS.MISSING_SLOT); + }); + + it('should throw error when services are missing', async () => { + const variablesWithoutServices = { + input: { + client: 'customer-123', + datetime_start: now.toISOString(), + slot: 'slot-123', + }, + }; + + const result = ordersService.createOrder(variablesWithoutServices); + + await expect(result).rejects.toThrow(ERRORS.MISSING_SERVICES); + }); + + it('should throw error when datetime_start is missing', async () => { + const variablesWithoutStart = { + input: { + client: 'customer-123', + services: ['service-123'], + slot: 'slot-123', + }, + }; + + const result = ordersService.createOrder(variablesWithoutStart); + + await expect(result).rejects.toThrow(ERRORS.MISSING_START_TIME); + }); + + it('should throw error when client is missing', async () => { + const variablesWithoutClient = { + input: { + datetime_start: now.toISOString(), + services: ['service-123'], + slot: 'slot-123', + }, + }; + + const result = ordersService.createOrder(variablesWithoutClient); + + await expect(result).rejects.toThrow(ERRORS.MISSING_CLIENT); + }); + + it('should throw error when order time is in the past', async () => { + const pastTime = now.subtract(1, 'hour'); + const variablesWithPastTime = { + input: { + client: 'customer-123', + datetime_end: pastTime.add(1, 'hour').toISOString(), + datetime_start: pastTime.toISOString(), + services: ['service-123'], + slot: 'slot-123', + }, + }; + + const result = ordersService.createOrder(variablesWithPastTime); + + await expect(result).rejects.toThrow(ERRORS.NO_ORDER_IN_PAST); + }); + + it('should throw error when order time is invalid', async () => { + const variablesWithInvalidTime = { + input: { + client: 'customer-123', + datetime_end: now.toISOString(), // равно datetime_start + datetime_start: now.toISOString(), + services: ['service-123'], + slot: 'slot-123', + }, + }; + + const result = ordersService.createOrder(variablesWithInvalidTime); + + await expect(result).rejects.toThrow(ERRORS.INVALID_TIME); + }); + + it('should throw error when slot is not found', async () => { + const mockQuery = vi.fn().mockImplementation(({ query }) => { + if (query === GQL.GetCustomerDocument) { + return Promise.resolve(mockGetCustomerResult); + } + + return Promise.resolve({ data: {} }); + }); + + mockGetClientWithToken.mockResolvedValue({ + mutate: vi.fn(), + query: mockQuery, + }); + + const mockGetSlot = vi.fn().mockResolvedValue({ + slot: null, // слот не найден + }); + mockSlotsService.mockImplementation(() => ({ + getSlot: mockGetSlot, + })); + + const result = ordersService.createOrder(mockVariables); + + await expect(result).rejects.toThrow(ERRORS.MISSING_SLOT); + }); + + it('should throw error when order is out of slot time', async () => { + const mockQuery = vi.fn().mockImplementation(({ query }) => { + if (query === GQL.GetCustomerDocument) { + return Promise.resolve(mockGetCustomerResult); + } + + return Promise.resolve({ data: {} }); + }); + + mockGetClientWithToken.mockResolvedValue({ + mutate: vi.fn(), + query: mockQuery, + }); + + const mockGetSlot = vi.fn().mockResolvedValue({ + slot: mockSlot, + }); + mockSlotsService.mockImplementation(() => ({ + getSlot: mockGetSlot, + })); + + const mockGetCustomer = vi.fn().mockResolvedValue({ + customer: mockCustomer, + }); + mockCustomersService.mockImplementation(() => ({ + getCustomer: mockGetCustomer, + getMasters: vi.fn().mockResolvedValue({ + masters: [mockMaster], + }), + })); + + const variablesWithOutOfSlotTime = { + input: { + client: 'customer-123', + datetime_end: now.add(8, 'hour').toISOString(), + datetime_start: now.add(7, 'hour').toISOString(), // после окончания слота + services: ['service-123'], + slot: 'slot-123', + }, + }; + + const result = ordersService.createOrder(variablesWithOutOfSlotTime); + + await expect(result).rejects.toThrow(ERRORS.NO_ORDER_OUT_OF_SLOT); + }); + + it('should throw error when slot is closed', async () => { + const closedSlot = { + ...mockSlot, + state: GQL.Enum_Slot_State.Closed, + }; + + const mockQuery = vi.fn().mockImplementation(({ query }) => { + if (query === GQL.GetCustomerDocument) { + return Promise.resolve(mockGetCustomerResult); + } + + return Promise.resolve({ data: {} }); + }); + + mockGetClientWithToken.mockResolvedValue({ + mutate: vi.fn(), + query: mockQuery, + }); + + const mockGetSlot = vi.fn().mockResolvedValue({ + slot: closedSlot, + }); + mockSlotsService.mockImplementation(() => ({ + getSlot: mockGetSlot, + })); + + const mockGetCustomer = vi.fn().mockResolvedValue({ + customer: mockCustomer, + }); + mockCustomersService.mockImplementation(() => ({ + getCustomer: mockGetCustomer, + getMasters: vi.fn().mockResolvedValue({ + masters: [mockMaster], + }), + })); + + const result = ordersService.createOrder(mockVariables); + + await expect(result).rejects.toThrow(ERRORS.SLOT_CLOSED); + }); + + it('should throw error when client is not found', async () => { + const mockQuery = vi.fn().mockImplementation(({ query }) => { + if (query === GQL.GetCustomerDocument) { + return Promise.resolve(mockGetCustomerResult); + } + + return Promise.resolve({ data: {} }); + }); + + mockGetClientWithToken.mockResolvedValue({ + mutate: vi.fn(), + query: mockQuery, + }); + + const mockGetSlot = vi.fn().mockResolvedValue({ + slot: mockSlot, + }); + mockSlotsService.mockImplementation(() => ({ + getSlot: mockGetSlot, + })); + + const mockGetCustomer = vi.fn().mockResolvedValue({ + customer: null, // клиент не найден + }); + mockCustomersService.mockImplementation(() => ({ + getCustomer: mockGetCustomer, + getMasters: vi.fn().mockResolvedValue({ + masters: [mockMaster], + }), + })); + + const result = ordersService.createOrder(mockVariables); + + await expect(result).rejects.toThrow(ERRORS.NOT_FOUND_CLIENT); + }); + + it('should throw error when client is inactive', async () => { + const inactiveCustomer = { + ...mockCustomer, + active: false, + }; + + const mockQuery = vi.fn().mockImplementation(({ query }) => { + if (query === GQL.GetCustomerDocument) { + return Promise.resolve(mockGetCustomerResult); + } + + return Promise.resolve({ data: {} }); + }); + + mockGetClientWithToken.mockResolvedValue({ + mutate: vi.fn(), + query: mockQuery, + }); + + const mockGetSlot = vi.fn().mockResolvedValue({ + slot: mockSlot, + }); + mockSlotsService.mockImplementation(() => ({ + getSlot: mockGetSlot, + })); + + const mockGetCustomer = vi.fn().mockResolvedValue({ + customer: inactiveCustomer, + }); + mockCustomersService.mockImplementation(() => ({ + getCustomer: mockGetCustomer, + getMasters: vi.fn().mockResolvedValue({ + masters: [mockMaster], + }), + })); + + const result = ordersService.createOrder(mockVariables); + + await expect(result).rejects.toThrow(ERRORS.INACTIVE_CLIENT); + }); + + it('should throw error when master is inactive', async () => { + const inactiveMaster = { + ...mockMaster, + active: false, + }; + + const slotWithInactiveMaster = { + ...mockSlot, + master: inactiveMaster, + }; + + const mockQuery = vi.fn().mockImplementation(({ query }) => { + if (query === GQL.GetCustomerDocument) { + return Promise.resolve(mockGetCustomerResult); + } + + return Promise.resolve({ data: {} }); + }); + + mockGetClientWithToken.mockResolvedValue({ + mutate: vi.fn(), + query: mockQuery, + }); + + const mockGetSlot = vi.fn().mockResolvedValue({ + slot: slotWithInactiveMaster, + }); + mockSlotsService.mockImplementation(() => ({ + getSlot: mockGetSlot, + })); + + const mockGetCustomer = vi.fn().mockResolvedValue({ + customer: mockCustomer, + }); + mockCustomersService.mockImplementation(() => ({ + getCustomer: mockGetCustomer, + getMasters: vi.fn().mockResolvedValue({ + masters: [inactiveMaster], + }), + })); + + const result = ordersService.createOrder(mockVariables); + + await expect(result).rejects.toThrow(ERRORS.INACTIVE_MASTER); + }); + + it('should throw error when customer tries to book themselves as master', async () => { + const activeCustomerAsMaster = { + ...mockCustomer, + active: true, + role: GQL.Enum_Customer_Role.Master, + }; + + const slotWithCustomerAsMaster = { + ...mockSlot, + master: activeCustomerAsMaster, + }; + + const mockQuery = vi.fn().mockImplementation(({ query }) => { + if (query === GQL.GetCustomerDocument) { + return Promise.resolve(mockGetCustomerResult); + } + + return Promise.resolve({ data: {} }); + }); + + mockGetClientWithToken.mockResolvedValue({ + mutate: vi.fn(), + query: mockQuery, + }); + + const mockGetSlot = vi.fn().mockResolvedValue({ + slot: slotWithCustomerAsMaster, + }); + mockSlotsService.mockImplementation(() => ({ + getSlot: mockGetSlot, + })); + + const mockGetCustomer = vi.fn().mockResolvedValue({ + customer: mockCustomer, + }); + mockCustomersService.mockImplementation(() => ({ + getCustomer: mockGetCustomer, + getMasters: vi.fn().mockResolvedValue({ + masters: [activeCustomerAsMaster], + }), + })); + + const result = ordersService.createOrder(mockVariables); + + await expect(result).rejects.toThrow(ERRORS.NO_MASTER_SELF_BOOK); + }); + + it('should throw error when customer is not linked to master', async () => { + const mockQuery = vi.fn().mockImplementation(({ query }) => { + if (query === GQL.GetCustomerDocument) { + return Promise.resolve(mockGetCustomerResult); + } + + return Promise.resolve({ data: {} }); + }); + + mockGetClientWithToken.mockResolvedValue({ + mutate: vi.fn(), + query: mockQuery, + }); + + const mockGetSlot = vi.fn().mockResolvedValue({ + slot: mockSlot, + }); + mockSlotsService.mockImplementation(() => ({ + getSlot: mockGetSlot, + })); + + const mockGetCustomer = vi.fn().mockResolvedValue({ + customer: mockCustomer, + }); + mockCustomersService.mockImplementation(() => ({ + getCustomer: mockGetCustomer, + getMasters: vi.fn().mockResolvedValue({ + masters: [], // клиент не связан с мастером + }), + })); + + const result = ordersService.createOrder(mockVariables); + + await expect(result).rejects.toThrow(ERRORS.INVALID_MASTER); + }); + + it('should throw error when time overlaps with other orders', async () => { + const overlappingOrder = { + ...mockOrder, + documentId: 'order-456', + }; + + const mockQuery = vi.fn().mockImplementation(({ query }) => { + if (query === GQL.GetCustomerDocument) { + return Promise.resolve(mockGetCustomerResult); + } + + if (query === GQL.GetOrdersDocument) { + return Promise.resolve({ + data: { orders: [overlappingOrder] }, + }); // есть пересекающиеся заказы + } + + return Promise.resolve({ data: {} }); + }); + + mockGetClientWithToken.mockResolvedValue({ + mutate: vi.fn(), + query: mockQuery, + }); + + const mockGetSlot = vi.fn().mockResolvedValue({ + slot: mockSlot, + }); + mockSlotsService.mockImplementation(() => ({ + getSlot: mockGetSlot, + })); + + const mockGetCustomer = vi.fn().mockResolvedValue({ + customer: mockCustomer, + }); + mockCustomersService.mockImplementation(() => ({ + getCustomer: mockGetCustomer, + getMasters: vi.fn().mockResolvedValue({ + masters: [mockMaster], + }), + })); + + const result = ordersService.createOrder(mockVariables); + + await expect(result).rejects.toThrow(ERRORS.OVERLAPPING_TIME); + }); + + it('should throw error when service duration is invalid', async () => { + const serviceWithoutDuration = { + ...mockService, + duration: null, + }; + + const mockQuery = vi.fn().mockImplementation(({ query }) => { + if (query === GQL.GetCustomerDocument) { + return Promise.resolve(mockGetCustomerResult); + } + + return Promise.resolve({ data: {} }); + }); + + mockGetClientWithToken.mockResolvedValue({ + mutate: vi.fn(), + query: mockQuery, + }); + + const mockGetSlot = vi.fn().mockResolvedValue({ + slot: mockSlot, + }); + mockSlotsService.mockImplementation(() => ({ + getSlot: mockGetSlot, + })); + + const mockGetCustomer = vi.fn().mockResolvedValue({ + customer: mockCustomer, + }); + mockCustomersService.mockImplementation(() => ({ + getCustomer: mockGetCustomer, + getMasters: vi.fn().mockResolvedValue({ + masters: [mockMaster], + }), + })); + + const mockGetService = vi.fn().mockResolvedValue({ + service: serviceWithoutDuration, + }); + mockServicesService.mockImplementation(() => ({ + getService: mockGetService, + })); + + const result = ordersService.createOrder(mockVariables); + + await expect(result).rejects.toThrow(ERRORS.INVALID_SERVICE_DURATION); + }); + + it('should calculate datetime_end based on service duration', async () => { + const mockMutate = vi.fn().mockResolvedValue(mockMutationResult); + const mockQuery = vi.fn().mockImplementation(({ query }) => { + if (query === GQL.GetCustomerDocument) { + return Promise.resolve(mockGetCustomerResult); + } + + if (query === GQL.GetOrdersDocument) { + return Promise.resolve({ data: { orders: [] } }); + } + + return Promise.resolve({ data: {} }); + }); + + mockGetClientWithToken.mockResolvedValue({ + mutate: mockMutate, + query: mockQuery, + }); + + const mockGetService = vi.fn().mockResolvedValue({ + service: mockService, + }); + mockServicesService.mockImplementation(() => ({ + getService: mockGetService, + })); + + const mockGetSlot = vi.fn().mockResolvedValue({ + slot: mockSlot, + }); + mockSlotsService.mockImplementation(() => ({ + getSlot: mockGetSlot, + })); + + const mockGetCustomer = vi.fn().mockResolvedValue({ + customer: mockCustomer, + }); + mockCustomersService.mockImplementation(() => ({ + getCustomer: mockGetCustomer, + getMasters: vi.fn().mockResolvedValue({ + masters: [mockMaster], + }), + })); + + await ordersService.createOrder(mockVariables); + + expect(mockMutate).toHaveBeenCalledWith({ + mutation: GQL.CreateOrderDocument, + variables: { + ...mockVariables, + input: { + ...mockVariables.input, + datetime_end: now.add(1, 'hour').toISOString(), // 1 час от начала + state: GQL.Enum_Order_State.Created, + }, + }, + }); + }); + }); +}); diff --git a/packages/graphql/api/orders.ts b/packages/graphql/api/orders.ts index 687e451..5b4e813 100644 --- a/packages/graphql/api/orders.ts +++ b/packages/graphql/api/orders.ts @@ -11,13 +11,14 @@ import { isCustomerMaster } from '@repo/utils/customer'; import { getMinutes, isBeforeNow } from '@repo/utils/datetime-format'; import dayjs from 'dayjs'; -const ERRORS = { +export const ERRORS = { INACTIVE_CLIENT: 'Клиент не активен', INACTIVE_MASTER: 'Мастер не активен', INVALID_MASTER: 'Некорректный мастер', INVALID_SERVICE_DURATION: 'Неверная длительность услуги', INVALID_TIME: 'Некорректное время', MISSING_CLIENT: 'Не указан клиент', + MISSING_END_TIME: 'Не указано время окончания', MISSING_ORDER: 'Заказ не найден', MISSING_SERVICE_ID: 'Не указан идентификатор услуги', MISSING_SERVICES: 'Отсутствуют услуги', @@ -25,11 +26,11 @@ const ERRORS = { MISSING_START_TIME: 'Не указано время начала', MISSING_TIME: 'Не указано время', NO_MASTER_SELF_BOOK: 'Нельзя записать к самому себе', + NO_ORDER_IN_PAST: 'Нельзя создать запись на время в прошлом', + NO_ORDER_OUT_OF_SLOT: 'Время заказа выходит за пределы слота', NO_PERMISSION: 'Нет доступа', NOT_FOUND_CLIENT: 'Клиент не найден', NOT_FOUND_MASTER: 'Мастер не найден', - ORDER_IN_PAST: 'Нельзя создать запись на время в прошлом', - ORDER_OUT_OF_SLOT: 'Время заказа выходит за пределы слота', OVERLAPPING_TIME: 'Время пересекается с другими заказами', SLOT_CLOSED: 'Слот закрыт', }; @@ -44,7 +45,6 @@ export class OrdersService extends BaseService { if (!variables.input.slot) throw new Error(ERRORS.MISSING_SLOT); if (!variables.input.services?.length) throw new Error(ERRORS.MISSING_SERVICES); if (!variables.input.services[0]) throw new Error(ERRORS.MISSING_SERVICE_ID); - if (!variables.input.datetime_start) throw new Error(ERRORS.MISSING_START_TIME); if (!variables.input.client) throw new Error(ERRORS.MISSING_CLIENT); const servicesService = new ServicesService(this._user); @@ -163,8 +163,12 @@ export class OrdersService extends BaseService { if (!services?.length) throw new Error(ERRORS.MISSING_SERVICES); // Проверка корректности времени заказа. - if (!datetime_start || !datetime_end) { - throw new Error(ERRORS.MISSING_TIME); + if (!datetime_start) { + throw new Error(ERRORS.MISSING_START_TIME); + } + + if (!datetime_end) { + throw new Error(ERRORS.MISSING_END_TIME); } if (new Date(datetime_end) <= new Date(datetime_start)) { @@ -173,7 +177,7 @@ export class OrdersService extends BaseService { // Проверка, что заказ не создается на время в прошлом if (isBeforeNow(datetime_start, 'minute')) { - throw new Error(ERRORS.ORDER_IN_PAST); + throw new Error(ERRORS.NO_ORDER_IN_PAST); } const slotService = new SlotsService(this._user); @@ -187,7 +191,7 @@ export class OrdersService extends BaseService { new Date(datetime_start) < new Date(slot.datetime_start) || new Date(datetime_end) > new Date(slot.datetime_end) ) { - throw new Error(ERRORS.ORDER_OUT_OF_SLOT); + throw new Error(ERRORS.NO_ORDER_OUT_OF_SLOT); } // 1. Слот не должен быть закрыт