import { Controller, Post, Delete, Route, Security, Tags, Body, Path, Request, Response, Get } from "tsoa"; import { LessThan, MoreThan } from "typeorm"; import { AppDataSource } from "../database/data-source"; import HttpSuccess from "../interfaces/http-success"; import HttpStatusCode from "../interfaces/http-status"; import HttpError from "../interfaces/http-error"; import { Command } from "../entities/Command"; import { CommandOperator, CreateCommandOperatorDto } from "../entities/CommandOperator"; import { RequestWithUser } from "../middlewares/user"; @Route("api/v1/org/commandOperator") @Tags("CommandOperator") @Security("bearerAuth") @Response( HttpStatusCode.INTERNAL_SERVER_ERROR, "เกิดข้อผิดพลาด ไม่สามารถแสดงรายการได้ กรุณาลองใหม่ในภายหลัง", ) export class CommandOperatorController extends Controller { private commandRepo = AppDataSource.getRepository(Command); private commandOperatorRepo = AppDataSource.getRepository(CommandOperator); /** * API รายชื่อเจ้าหน้าที่ดำเนินการที่คำสั่ง * @summary API รายชื่อเจ้าหน้าที่ดำเนินการที่คำสั่ง * @param commandId คีย์คำสั่ง */ @Get("{commandId}") async getCommandOperatorByCommandId( @Path() commandId: string ) { const command = await this.commandRepo.findOne({ where: { id: commandId }, select: { id: true }, }); if (!command) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลคำสั่งนี้"); } const commandOperators = await this.commandOperatorRepo.find({ where: { commandId: command.id }, order: { orderNo: "ASC" }, }); return new HttpSuccess(commandOperators); } /** * API สลับลำดับเจ้าหน้าที่ดำเนินการ (UP / DOWN) * @summary API สลับลำดับเจ้าหน้าที่ดำเนินการ (UP / DOWN) * @param direction สลับขึ้นหรือลง (UP / DOWN) * @param operatorId คีย์เจ้าหน้าที่ดำเนินการ */ @Get("swap/{direction}/{operatorId}") async swapCommandOperator( @Path() direction: string, @Path() operatorId: string, ) { const source = await this.commandOperatorRepo.findOne({ where: { id: operatorId }, }); if (!source) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลเจ้าหน้าที่"); } const sourceOrder = source.orderNo; const isUp = direction.trim().toUpperCase() === "UP"; let dest: CommandOperator | null; if (isUp) { dest = await this.commandOperatorRepo.findOne({ where: { commandId: source.commandId, orderNo: LessThan(sourceOrder), }, order: { orderNo: "DESC" }, }); } else { dest = await this.commandOperatorRepo.findOne({ where: { commandId: source.commandId, orderNo: MoreThan(sourceOrder), }, order: { orderNo: "ASC" }, }); } // ถ้าไม่มีตัวให้สลับ (บนสุด / ล่างสุด) if (!dest) { return new HttpSuccess(); } // swap const temp = source.orderNo; source.orderNo = dest.orderNo; dest.orderNo = temp; await Promise.all([ this.commandOperatorRepo.save(source), this.commandOperatorRepo.save(dest), ]); return new HttpSuccess(); } /** * API เพิ่มเจ้าหน้าที่ดำเนินการที่คำสั่ง * @summary API เพิ่มเจ้าหน้าที่ดำเนินการที่คำสั่ง * @param commandId คีย์คำสั่ง */ @Post("{commandId}") async createCommandOperators( @Path() commandId: string, @Request() request: RequestWithUser, @Body() body: CreateCommandOperatorDto, ) { const command = await this.commandRepo.findOne({ where: { id: commandId }, select: { id: true }, }); if (!command) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลคำสั่งนี้"); } const lastOrderNo = await this.commandOperatorRepo.findOne({ where: { commandId: commandId }, order: { orderNo: "DESC" }, select: { orderNo: true }, }); const nextOrderNo = (lastOrderNo?.orderNo ?? 1) + 1; const now = new Date(); const operator = Object.assign( new CommandOperator(), { ...body, commandId: command.id, orderNo: nextOrderNo, createdUserId: request.user.sub, createdFullName: request.user.name, createdAt: now, lastUpdateUserId: request.user.sub, lastUpdateFullName: request.user.name, lastUpdatedAt: now, } ); await this.commandOperatorRepo.save(operator); return new HttpSuccess(); } /** * API ลบเจ้าหน้าที่ดำเนินการที่คำสั่ง * @summary API ลบเจ้าหน้าที่ดำเนินการที่คำสั่ง * @param commandId คีย์คำสั่ง * @param operatorId คีย์เจ้าหน้าที่ดำเนินการ */ @Delete("{commandId}/{operatorId}") public async deleteCommandOperator( @Path() commandId: string, @Path() operatorId: string, ) { const queryRunner = AppDataSource.createQueryRunner(); await queryRunner.connect(); await queryRunner.startTransaction(); try { // 1. หา operator const operator = await queryRunner.manager.findOne(CommandOperator, { where: { id: operatorId, commandId: commandId, }, }); if (!operator) { throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบเจ้าหน้าที่ดำเนินการ"); } // // 2. ห้ามลบ orderNo = 1 // if (operator.orderNo === 1) { // throw new HttpError( // HttpStatusCode.BAD_REQUEST, // "ไม่สามารถลบเจ้าหน้าที่ลำดับที่ 1 ได้" // ); // } const removedOrderNo = operator.orderNo; // 3. ลบ await queryRunner.manager.remove(operator); // 4. re orderNumber ตัวที่เหลือ await queryRunner.manager .createQueryBuilder() .update(CommandOperator) .set({ orderNo: () => "orderNo - 1", }) .where("commandId = :commandId", { commandId }) .andWhere("orderNo > :removedOrderNo", { removedOrderNo }) .execute(); await queryRunner.commitTransaction(); return new HttpSuccess(true); } catch (error) { await queryRunner.rollbackTransaction(); throw error; } finally { await queryRunner.release(); } } }