diff --git a/src/controllers/work/work-controller.ts b/src/controllers/work/work-controller.ts new file mode 100644 index 0000000..8df4ddc --- /dev/null +++ b/src/controllers/work/work-controller.ts @@ -0,0 +1,172 @@ +import { + Body, + Controller, + Delete, + Get, + Put, + Path, + Post, + Query, + Request, + Route, + Security, + Tags, +} from "tsoa"; +import { Prisma, Status } from "@prisma/client"; + +import prisma from "../../db"; +import { RequestWithUser } from "../../interfaces/user"; +import HttpError from "../../interfaces/http-error"; +import HttpStatus from "../../interfaces/http-status"; + +type WorkCreate = { + order: number; + name: string; + serviceId: string; +}; + +type WorkUpdate = { + order?: number; + name?: string; + serviceId?: string; +}; + +@Route("api/v1/work") +@Tags("Work") +@Security("keycloak") +export class WorkController extends Controller { + @Get() + async getWork( + @Query() query: string = "", + @Query() page: number = 1, + @Query() pageSize: number = 30, + ) { + const where = { + OR: [{ name: { contains: query } }], + } satisfies Prisma.WorkWhereInput; + + const [result, total] = await prisma.$transaction([ + prisma.work.findMany({ + orderBy: { createdAt: "asc" }, + include: { service: true }, + where, + take: pageSize, + skip: (page - 1) * pageSize, + }), + prisma.work.count({ where }), + ]); + + return { result, page, pageSize, total }; + } + + @Get("{workId}") + async getWorkById(@Path() workId: string) { + const record = await prisma.work.findFirst({ + include: { service: true }, + where: { id: workId }, + }); + + if (!record) + throw new HttpError(HttpStatus.NOT_FOUND, "Work cannot be found.", "data_not_found"); + + return record; + } + @Get("{workId}/product") + async getProductOfWork( + @Path() workId: string, + @Query() query: string = "", + @Query() page: number = 1, + @Query() pageSize: number = 30, + ) { + const where = { + AND: [ + { + workProduct: { + some: { workId }, + }, + }, + { + OR: [{ name: { contains: query } }], + }, + ], + } satisfies Prisma.ProductWhereInput; + + const [result, total] = await prisma.$transaction([ + prisma.product.findMany({ + where, + take: pageSize, + skip: (page - 1) * pageSize, + }), + prisma.product.count({ + where, + }), + ]); + + return { result, page, pageSize, total }; + } + + @Post() + async createWork(@Request() req: RequestWithUser, @Body() body: WorkCreate) { + const service = await prisma.service.findFirst({ + where: { id: body.serviceId }, + }); + + if (!service) { + throw new HttpError( + HttpStatus.BAD_REQUEST, + "Service not found.", + "missing_or_invalid_parameter", + ); + } + + const record = await prisma.work.create({ + data: { + ...body, + createdBy: req.user.name, + updateBy: req.user.name, + }, + }); + + await prisma.service.updateMany({ + where: { id: service.id }, + data: { status: Status.ACTIVE }, + }); + + this.setStatus(HttpStatus.CREATED); + + return record; + } + + @Put("{workId}") + async editService( + @Request() req: RequestWithUser, + @Body() body: WorkUpdate, + @Path() workId: string, + ) { + if (!(await prisma.work.findUnique({ where: { id: workId } }))) { + throw new HttpError(HttpStatus.NOT_FOUND, "Work cannot be found.", "data_not_found"); + } + + const record = await prisma.work.update({ + data: { ...body, updateBy: req.user.name }, + where: { id: workId }, + }); + + return record; + } + + @Delete("{workId}") + async deleteWork(@Path() workId: string) { + const record = await prisma.work.findFirst({ where: { id: workId } }); + + if (!record) { + throw new HttpError(HttpStatus.NOT_FOUND, "Work cannot be found.", "data_not_found"); + } + + if (record.status !== Status.CREATED) { + throw new HttpError(HttpStatus.FORBIDDEN, "Work is in used.", "missing_or_invalid_parameter"); + } + + return await prisma.work.delete({ where: { id: workId } }); + } +}