import { Prisma, RequestDataStatus, RequestWorkStatus } from "@prisma/client"; import { Body, Controller, Get, Path, Put, Query, Request, Route, Security, Tags } from "tsoa"; import { RequestWithUser } from "../interfaces/user"; import prisma from "../db"; import { createPermCondition } from "../services/permission"; import { queryOrNot } from "../utils/relation"; import { notFoundError } from "../utils/error"; // User in company can see. const permissionCond = createPermCondition((_) => true); @Route("/api/v1/request-data") @Tags("Request List") export class RequestDataController extends Controller { @Get("stats") @Security("keycloak") async getRequestDataStats(@Request() req: RequestWithUser) { const where = { quotation: { customerBranch: { customer: { registeredBranch: { OR: permissionCond(req.user) }, }, }, }, } satisfies Prisma.RequestDataWhereInput; const list = await prisma.requestData.groupBy({ _count: true, by: "requestDataStatus", where: where, }); return list.reduce>( (a, c) => Object.assign(a, { [c.requestDataStatus]: c._count }), { [RequestDataStatus.Pending]: 0, [RequestDataStatus.InProgress]: 0, [RequestDataStatus.Completed]: 0, }, ); } @Get() @Security("keycloak") async getRequestDataList( @Request() req: RequestWithUser, @Query() page: number = 1, @Query() pageSize: number = 30, @Query() query: string = "", @Query() requestDataStatus?: RequestDataStatus, ) { const where = { OR: queryOrNot(query, [ { quotation: { code: { contains: query, mode: "insensitive" } } }, { quotation: { workName: { contains: query } } }, { quotation: { customerBranch: { OR: [ { code: { contains: query, mode: "insensitive" } }, { customerName: { contains: query } }, { firstName: { contains: query } }, { firstNameEN: { contains: query } }, { lastName: { contains: query } }, { lastNameEN: { contains: query } }, ], }, }, employee: { OR: [ { employeePassport: { some: { number: { contains: query } }, }, }, { code: { contains: query, mode: "insensitive" } }, { firstName: { contains: query } }, { firstNameEN: { contains: query } }, { lastName: { contains: query } }, { lastNameEN: { contains: query } }, ], }, }, ]), requestDataStatus, quotation: { customerBranch: { customer: { registeredBranch: { OR: permissionCond(req.user) }, }, }, }, } satisfies Prisma.RequestDataWhereInput; const [result, total] = await prisma.$transaction([ prisma.requestData.findMany({ where, include: { quotation: { include: { customerBranch: { include: { customer: true }, }, }, }, employee: { include: { employeePassport: { orderBy: { expireDate: "desc" }, }, }, }, }, take: pageSize, skip: (page - 1) * pageSize, }), prisma.requestData.count({ where }), ]); return { result, page, pageSize, total }; } @Get("{requestDataId}") @Security("keycloak") async getRequestData(@Path() requestDataId: string) { return await prisma.requestData.findFirst({ where: { id: requestDataId }, include: { quotation: { include: { customerBranch: { include: { customer: true } }, invoice: { include: { installments: true, payment: true, }, }, createdBy: true, }, }, employee: { include: { employeePassport: { orderBy: { expireDate: "desc" }, }, }, }, }, }); } } @Route("/api/v1/request-work") @Tags("Request List") export class RequestListController extends Controller { @Get() @Security("keycloak") async getRequestWork( @Request() req: RequestWithUser, @Query() page: number = 1, @Query() pageSize: number = 30, @Query() requestDataId?: string, @Query() workStatus?: RequestWorkStatus, ) { const where = { stepStatus: workStatus ? { some: { workStatus } } : undefined, request: { id: requestDataId, quotation: { customerBranch: { customer: { registeredBranch: { OR: permissionCond(req.user) }, }, }, }, }, } satisfies Prisma.RequestWorkWhereInput; const [result, total] = await prisma.$transaction([ prisma.requestWork.findMany({ where, include: { request: { include: { quotation: true, employee: true, }, }, stepStatus: true, productService: { include: { service: true, work: true, product: { include: { document: true }, }, }, }, }, take: pageSize, skip: (page - 1) * pageSize, }), prisma.requestWork.count({ where }), ]); return { result: result.map((v) => { return Object.assign(v, { productService: Object.assign(v.productService, { product: Object.assign(v.productService.product, { document: v.productService.product.document.map((doc) => doc.name), }), }), }); }), page, pageSize, total, }; } @Get("{requestWorkId}") async getRequestWorkById(@Path() requestWorkId: string) { const record = await prisma.requestWork.findFirst({ include: { request: { include: { quotation: true, employee: true, }, }, stepStatus: true, productService: { include: { service: true, work: true, product: { include: { document: true, }, }, }, }, }, where: { id: requestWorkId }, }); if (!record) throw notFoundError("Request Work"); return Object.assign(record, { productService: Object.assign(record.productService, { product: Object.assign(record.productService.product, { document: record.productService.product.document.map((doc) => doc.name), }), }), }); } @Put("{requestWorkId}") @Security("keycloak") async updateRequestWorkById( @Request() req: RequestWithUser, @Path() requestWorkId: string, @Body() payload: { attributes: Record }, ) { const record = await prisma.requestWork.update({ include: { request: { include: { quotation: true, employee: true, }, }, stepStatus: true, productService: { include: { service: true, work: true, product: { include: { document: true, }, }, }, }, }, where: { id: requestWorkId }, data: { attributes: payload.attributes }, }); return record; } @Put("{requestWorkId}/step-status/{step}") @Security("keycloak") async updateRequestWorkStepStatus( @Path() requestWorkId: string, @Path() step: number, @Body() payload: { requestWorkStatus?: RequestWorkStatus; attributes?: Record }, @Query() successAll?: boolean, ) { const record = await prisma.requestWorkStepStatus.upsert({ include: { requestWork: true, }, where: { step_requestWorkId: { step: step, requestWorkId, }, }, create: { step: step, requestWorkId, workStatus: payload.requestWorkStatus, attributes: payload.attributes, }, update: { workStatus: payload.requestWorkStatus, attributes: payload.attributes, }, }); switch (payload.requestWorkStatus) { case "InProgress": case "Waiting": case "Validate": case "Completed": case "Ended": await prisma.requestData.update({ where: { id: record.requestWork.requestDataId, }, data: { requestDataStatus: "InProgress" }, }); break; } if ( successAll && (payload.requestWorkStatus === "Completed" || payload.requestWorkStatus === "Ended") ) { await prisma.requestData.update({ where: { id: record.requestWork.requestDataId, }, data: { requestDataStatus: "Completed" }, }); } return record; } } export class RequestListAttachmentController extends Controller {}