import { BadRequestException, Injectable, Logger, NotFoundException, } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { MoreThanOrEqual, Repository } from 'typeorm'; import { Queue } from './entities/queue.entity'; import { CreateQueueDto } from './dto/create-queue.dto'; import { UpdateQueueDto } from './dto/update-queue.dto'; import { Machine } from '@/machines/entities/machine.entity'; import { Page } from '@/pages/entities/page.entity'; import { Order } from '@/orders/entities/order.entity'; import { Employee } from '@/employees/entities/employee.entity'; @Injectable() export class QueuesService { private readonly logger = new Logger(QueuesService.name); deleteByDate( dateStr: string, ): { deletedCount: number } | PromiseLike<{ deletedCount: number }> { throw new Error('Method not implemented.'); } constructor( @InjectRepository(Queue) private readonly queueRepository: Repository<Queue>, @InjectRepository(Machine) private readonly machineRepository: Repository<Machine>, @InjectRepository(Page) private readonly pageRepository: Repository<Page>, @InjectRepository(Order) private readonly orderRepository: Repository<Order>, @InjectRepository(Employee) private readonly employeeRepository: Repository<Employee>, ) {} async getLatestQueuesFromDate(dateStr?: string): Promise<Queue[]> { this.logger.log( `📡 Fetching queues from ${dateStr || 'the most recent date'}`, ); let startDate: Date; if (dateStr) { // ✅ ถ้ามี `dateStr` ให้ใช้เป็นวันที่เริ่มต้น const parts = dateStr.includes('/') ? dateStr.trim().split('/') : dateStr.trim().split('-'); if (parts.length !== 3) { throw new BadRequestException( 'Invalid date format. Use dd/MM/yyyy or yyyy-MM-dd', ); } if (dateStr.includes('/')) { const [day, month, year] = parts.map(Number); startDate = new Date(year, month - 1, day); } else { const [year, month, day] = parts.map(Number); startDate = new Date(year, month - 1, day); } } else { // ✅ ถ้าไม่ส่ง `dateStr` มา → ใช้วันที่ล่าสุดแทน const latestExistingQueue = await this.queueRepository.find({ order: { createdAt: 'DESC' }, take: 1, }); if (!latestExistingQueue.length) { this.logger.warn(`⚠️ No queues found in the system`); return []; } startDate = new Date(latestExistingQueue[0].createdAt); } startDate.setHours(0, 0, 0, 0); // ตั้งเป็น 00:00 ของวันนั้น this.logger.log( `🔍 Fetching all queues from ${startDate.toISOString()} onwards`, ); return await this.queueRepository.find({ where: { createdAt: MoreThanOrEqual(startDate) }, order: { createdAt: 'ASC' }, // เรียงจากเก่าสุดไปใหม่สุด }); } async create(createQueueDto: CreateQueueDto) { const { MachineID, PageID, OrderID, EmployeeIds, ...queueData } = createQueueDto; // console.log('📌 Received CreateQueueDto:', createQueueDto); // 🔍 Fetch related entities const machine = await this.machineRepository.findOne({ where: { MachineID }, }); if (!machine) throw new NotFoundException(`Machine with ID ${MachineID} not found`); const page = await this.pageRepository.findOne({ where: { PageID } }); if (!page) throw new NotFoundException(`Page with ID ${PageID} not found`); const order = await this.orderRepository.findOne({ where: { OrderID } }); if (!order) throw new NotFoundException(`Order with ID ${OrderID} not found`); const employees = await this.employeeRepository.findByIds(EmployeeIds); if (employees.length !== EmployeeIds.length) { throw new NotFoundException(`One or more employees not found`); } // console.log('✅ Related Entities Fetched:'); // console.log(' - Machine:', machine); // console.log(' - Page:', page); // console.log(' - Order:', order); // console.log(' - Employees:', employees); // ✅ Create Queue entity and save to DB const newQueue = this.queueRepository.create({ ...queueData, machine, page, order, employees, }); // console.log('🛠️ Preparing to save new Queue:', newQueue); const savedQueue = await this.queueRepository.save(newQueue); // console.log('✅ Queue saved successfully:', savedQueue); // ✅ Return the response with full details return { message: 'Queue created successfully', queue: savedQueue, }; } async createMultiple(createQueueDtos: CreateQueueDto[]) { const newQueues = []; if (!Array.isArray(createQueueDtos)) { throw new BadRequestException('Request body must be an array of queues'); } for (const createQueueDto of createQueueDtos) { const { MachineID, PageID, OrderID, EmployeeIds, ...queueData } = createQueueDto; // console.log('👉 Raw EmployeeIds:', EmployeeIds); // ✅ ตรวจสอบว่า `EmployeeIds` เป็น Array ที่ไม่ว่าง if (!Array.isArray(EmployeeIds) || EmployeeIds.length === 0) { throw new BadRequestException(`EmployeeIds must be a non-empty array`); } // ✅ แปลงค่าให้เป็นตัวเลข และกรองค่าที่ไม่ถูกต้อง const validEmployeeIds = EmployeeIds.map((id) => Number(id)).filter( (id) => !isNaN(id) && id > 0, ); // console.log('✅ Valid EmployeeIds:', validEmployeeIds); if (validEmployeeIds.length !== EmployeeIds.length) { throw new BadRequestException( `Invalid EmployeeIds provided: ${EmployeeIds}`, ); } // ✅ ตรวจสอบและแปลง `MachineID`, `OrderID`, `PageID` const machineId = Number(MachineID); if (isNaN(machineId)) throw new BadRequestException(`Invalid MachineID: ${MachineID}`); const orderId = Number(OrderID); if (isNaN(orderId)) throw new BadRequestException(`Invalid OrderID: ${OrderID}`); let pageId: number | null = null; if (PageID !== null && PageID !== undefined) { pageId = Number(PageID); if (isNaN(pageId)) throw new BadRequestException(`Invalid PageID: ${PageID}`); } // 🔍 ค้นหา Entity ที่เกี่ยวข้อง const machine = await this.machineRepository.findOne({ where: { MachineID: machineId }, }); if (!machine) throw new NotFoundException(`Machine with ID ${machineId} not found`); const page = pageId !== null ? await this.pageRepository.findOne({ where: { PageID: pageId } }) : null; if (pageId !== null && !page) throw new NotFoundException(`Page with ID ${pageId} not found`); const order = await this.orderRepository.findOne({ where: { OrderID: orderId }, }); if (!order) throw new NotFoundException(`Order with ID ${orderId} not found`); // 🔍 ค้นหา Employees ที่มีอยู่ในฐานข้อมูล const employees = await this.employeeRepository.findByIds(validEmployeeIds); const foundIds = employees.map((e) => e.EmployeeID); const missingIds = validEmployeeIds.filter( (id) => !foundIds.includes(id), ); if (missingIds.length > 0) { console.error(`❌ Missing EmployeeIDs: ${missingIds.join(', ')}`); throw new NotFoundException( `Employees not found: ${missingIds.join(', ')}`, ); } // ✅ สร้าง Queue object const newQueue = this.queueRepository.create({ ...queueData, machine, page, order, employees, }); newQueues.push(newQueue); } // ✅ บันทึกทั้งหมดพร้อมกัน const savedQueues = await this.queueRepository.save(newQueues); return { message: `${savedQueues.length} queues created successfully`, queues: savedQueues, }; } // ✅ Fetch all Queues with relationships async findAll() { return await this.queueRepository.find({ relations: ['machine', 'page', 'order', 'employees'], }); } // ✅ Fetch a single Queue by ID async findOne(id: number) { const queue = await this.queueRepository.findOne({ where: { QueueID: id }, relations: ['machine', 'page', 'order', 'employees'], }); if (!queue) { throw new NotFoundException(`Queue with ID ${id} not found`); } return queue; } // ✅ Update Queue async update(id: number, updateQueueDto: UpdateQueueDto) { try { console.log('🔄 Updating Queue ID:', id, updateQueueDto); const { MachineID, PageID, OrderID, EmployeeIds, startTime, finishTime, ...queueData } = updateQueueDto; // 🔍 ค้นหา Queue ที่จะอัปเดต const existingQueue = await this.queueRepository.findOne({ where: { QueueID: id }, relations: ['machine', 'page', 'order', 'employees'], }); if (!existingQueue) { throw new NotFoundException(`Queue with ID ${id} not found`); } // 🔍 Fetch entities if IDs are provided const machine = MachineID ? await this.machineRepository.findOne({ where: { MachineID } }) : existingQueue.machine; if (MachineID && !machine) throw new NotFoundException(`Machine with ID ${MachineID} not found`); const page = PageID ? await this.pageRepository.findOne({ where: { PageID } }) : existingQueue.page; if (PageID && !page) throw new NotFoundException(`Page with ID ${PageID} not found`); const order = OrderID ? await this.orderRepository.findOne({ where: { OrderID } }) : existingQueue.order; if (OrderID && !order) throw new NotFoundException(`Order with ID ${OrderID} not found`); // 🔍 ค้นหา Employees และคำนวณการเชื่อมโยง let employees = existingQueue.employees; if (EmployeeIds) { const fetchedEmployees = await this.employeeRepository.findByIds(EmployeeIds); if (fetchedEmployees.length !== EmployeeIds.length) { throw new NotFoundException(`One or more employees not found`); } employees = fetchedEmployees; } // ✅ Convert timestamps from string to Date const updateData: Partial<Queue> = { ...queueData, machine, page, order, employees, startTime: startTime ? new Date(startTime) : existingQueue.startTime, finishTime: finishTime ? new Date(finishTime) : existingQueue.finishTime, }; // ✅ ใช้ `save()` แทน `update()` เพื่อรองรับ Many-to-Many (employees) const updatedQueue = await this.queueRepository.save({ ...existingQueue, ...updateData, }); console.log('✅ Queue updated successfully:', updatedQueue); return updatedQueue; } catch (error) { console.error('❌ Error in updateQueue:', error); throw new Error('Database update failed'); } } // ✅ Delete Queue async remove(id: number) { const queue = await this.queueRepository.findOne({ where: { QueueID: id }, relations: ['machine', 'page', 'order', 'employees'], }); if (!queue) { throw new NotFoundException(`Queue with ID ${id} not found`); } await this.queueRepository.delete(id); return { message: 'Queue deleted successfully', deletedQueue: queue }; } async deleteNewlyCreatedQueuesFromDate( dateStr: string, ): Promise<{ deletedCount: number }> { this.logger.log(`🔄 Deleting newly created queues from date: ${dateStr}`); if (!dateStr) throw new BadRequestException('dateStr is required'); // ✅ แปลง string (dd/MM/yyyy หรือ yyyy-MM-dd) → Date object let date: Date; const parts = dateStr.includes('/') ? dateStr.trim().split('/') : dateStr.trim().split('-'); if (parts.length !== 3) { throw new BadRequestException( 'Invalid date format. Use dd/MM/yyyy or yyyy-MM-dd', ); } if (dateStr.includes('/')) { const [day, month, year] = parts.map(Number); date = new Date(year, month - 1, day); } else { const [year, month, day] = parts.map(Number); date = new Date(year, month - 1, day); } const startOfDay = new Date(date.setHours(0, 0, 0, 0)); const now = new Date(); // ✅ ค้นหา Queue ที่ตรงเงื่อนไข const queuesToDelete = await this.queueRepository.find({ where: { startTime: MoreThanOrEqual(startOfDay), createdAt: MoreThanOrEqual(startOfDay), }, }); if (queuesToDelete.length === 0) { this.logger.warn(`⚠️ No queues matched deletion criteria for ${dateStr}`); return { deletedCount: 0 }; } // ✅ Log รายละเอียด queue ที่จะลบ this.logger.log( `📌 Queues to be deleted (${queuesToDelete.length} items):`, ); queuesToDelete.forEach((queue) => { this.logger.log( `🗑️ QueueID: ${queue.QueueID}, startTime: ${queue.startTime}, createdAt: ${queue.createdAt}`, ); }); // ✅ ลบ queue await this.queueRepository.remove(queuesToDelete); this.logger.log( `✅ Successfully deleted ${queuesToDelete.length} queue(s).`, ); return { deletedCount: queuesToDelete.length }; } }