import { Injectable, NotFoundException, Logger } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository, Connection } from 'typeorm'; import { Order } from './entities/order.entity'; import { CreateOrderDto } from './dto/create-order.dto'; import { UpdateOrderDto } from './dto/update-order.dto'; import { Product } from '@/products/entities/product.entity'; import { OrderPriority } from '@/orderpiorities/entities/orderpiority.entity'; import { Page } from '@/pages/entities/page.entity'; import { OrderDetail } from '@/order_details/entities/order_detail.entity'; @Injectable() export class OrdersService { private readonly logger = new Logger(OrdersService.name); constructor( @InjectRepository(Order) private readonly orderRepository: Repository<Order>, @InjectRepository(Product) private readonly productRepository: Repository<Product>, @InjectRepository(OrderPriority) private readonly orderpiorityRepository: Repository<OrderPriority>, @InjectRepository(Page) private readonly pageRepository: Repository<Page>, @InjectRepository(OrderDetail) private readonly orderDetailRepository: Repository<OrderDetail>, private readonly connection: Connection, ) {} async create(createOrderDto: CreateOrderDto): Promise<Order> { this.logger.log( `Creating or updating order for customer ${createOrderDto.customerID}`, ); return await this.connection.transaction(async (manager) => { const isUpdate = !!createOrderDto.orderID; // ✅ Map orderDetails จาก product if (createOrderDto.orderDetails?.length > 0) { for (const detail of createOrderDto.orderDetails) { const product = await this.productRepository.findOne({ where: { ProductID: detail.productID }, }); if (!product) { throw new NotFoundException( `Product with ID ${detail.productID} not found`, ); } detail.Productname = `${product.brand} ${product.size}`; detail.size = product.size; detail.waterBrand = product.brand; detail.status = detail.status || 'Active'; detail.totalPrice = detail.quantity * detail.pricePerUnit; } } // ✅ Default status if (!createOrderDto.status) { createOrderDto.status = 'กำลังรอ'; } let order: Order; if (isUpdate) { const existing = await this.orderRepository.findOne({ where: { OrderID: createOrderDto.orderID }, relations: ['orderDetails'], }); if (!existing) { throw new NotFoundException( `Order with ID ${createOrderDto.orderID} not found`, ); } Object.assign(existing, createOrderDto); if (createOrderDto.orderDetails) { // ✅ ตัด entity.order = existing ออก เพื่อไม่ให้เกิด recursive loop const orderDetailEntities = createOrderDto.orderDetails.map((dto) => this.orderDetailRepository.create(dto), ); existing.orderDetails = orderDetailEntities; } order = await manager.save(existing); this.logger.log(`Order updated with ID ${order.OrderID}`); } else { order = this.orderRepository.create(createOrderDto); order = await manager.save(order); this.logger.log(`Order created with ID ${order.OrderID}`); } // ✅ สร้าง OrderPriority ให้ทุกหน้า (ถ้ายังไม่มี) const allPages = await this.pageRepository.find({ relations: ['orderPriorities'], }); for (const page of allPages) { const alreadyExists = page.orderPriorities.some( (op) => op.order?.OrderID === order.OrderID, ); if (!alreadyExists) { const newPriority = this.orderpiorityRepository.create({ order, page, priority: page.orderPriorities.length + 1, }); await manager.save(newPriority); this.logger.log(`Created OrderPriority for Page ${page.PageID}`); } } return order; }); } async upsertMany(ordersDto: CreateOrderDto[]): Promise<Order[]> { this.logger.log(`Upserting ${ordersDto.length} order(s)`); return await this.connection.transaction(async (manager) => { const upsertedOrders: Order[] = []; // ดึง Page ทั้งหมดมาไว้ก่อน const allPages = await this.pageRepository.find({ relations: ['orderPriorities'], }); for (const dto of ordersDto) { // ถ้าไม่มี status → ตั้ง default if (!dto.status) { dto.status = 'กำลังรอ'; } // ถ้ามี orderDetails → map ข้อมูลจาก Product if (dto.orderDetails && dto.orderDetails.length > 0) { for (const detail of dto.orderDetails) { const product = await this.productRepository.findOne({ where: { ProductID: detail.productID }, }); if (!product) { throw new NotFoundException( `Product with ID ${detail.productID} not found`, ); } detail.Productname = `${product.brand} ${product.size}`; detail.size = product.size; detail.waterBrand = product.brand; detail.status = detail.status || 'Active'; detail.totalPrice = detail.quantity * detail.pricePerUnit; } } // Save Order const orderEntity = this.orderRepository.create(dto); const savedOrder = await manager.save(orderEntity); upsertedOrders.push(savedOrder); this.logger.log(`📝 Order upserted with ID ${savedOrder.OrderID}`); // 🔁 สร้าง OrderPriority ให้ทุก Page ถ้ายังไม่มี for (const page of allPages) { const alreadyExists = page.orderPriorities?.some( (op) => op.order?.OrderID === savedOrder.OrderID, ); if (!alreadyExists) { const newPriority = this.orderpiorityRepository.create({ order: savedOrder, page: page, priority: page.orderPriorities.length + 1, }); const savedPriority = await manager.save(newPriority); page.orderPriorities.push(savedPriority); this.logger.log( `📌 OrderPriority created in Page ${page.PageID} for Order ${savedOrder.OrderID}`, ); } } } return upsertedOrders; }); } async findAll(): Promise<Order[]> { this.logger.log('Fetching all orders with orderDetails'); const orders = await this.orderRepository.find({ relations: ['orderDetails'], }); this.logger.log(`Fetched ${orders.length} order(s)`); return orders; } async findOne(id: number): Promise<Order> { this.logger.log(`Fetching order with ID ${id}`); const order = await this.orderRepository.findOne({ where: { OrderID: id }, relations: ['orderDetails'], }); if (!order) { this.logger.error(`Order with ID ${id} not found`); throw new NotFoundException(`Order with ID ${id} not found`); } this.logger.log(`Order with ID ${id} fetched successfully`); return order; } async update(id: number, updateOrderDto: UpdateOrderDto): Promise<Order> { this.logger.log(`Updating order with ID ${id}`); await this.orderRepository.update(id, updateOrderDto); const updatedOrder = await this.findOne(id); this.logger.log(`Order with ID ${id} updated successfully`); return updatedOrder; } async remove(id: number): Promise<Order> { this.logger.log(`Deleting order with ID ${id}`); // ✅ หา order พร้อมดึง orderDetails มา const order = await this.orderRepository.findOne({ where: { OrderID: id }, relations: ['orderDetails'], }); if (!order) { this.logger.error(`Order with ID ${id} not found for deletion`); throw new NotFoundException(`Order with ID ${id} not found`); } // ✅ ลบ orderDetails ทีละตัว if (order.orderDetails && order.orderDetails.length > 0) { this.logger.log( `Deleting ${order.orderDetails.length} orderDetails for order ID ${id}`, ); await this.orderDetailRepository.remove(order.orderDetails); } // ✅ ลบ order หลังจากลบ orderDetails await this.orderRepository.remove(order); this.logger.log(`Order with ID ${id} and its orderDetails deleted`); return order; // ส่งกลับ order ที่ลบไป (หรือจะเปลี่ยนเป็น message เฉยๆ ก็ได้) } }