import { Body, Controller, Delete, Get, Path, Post, Put, Query, Request, Route, Security, Tags, } from "tsoa"; import { RequestWithUser } from "../interfaces/user"; import prisma from "../db"; import { Prisma, Status } from "@prisma/client"; import { branchRelationPermInclude, createPermCheck, createPermCondition, } from "../services/permission"; import HttpError from "../interfaces/http-error"; import HttpStatus from "../interfaces/http-status"; import { notFoundError } from "../utils/error"; import { filterStatus } from "../services/prisma"; type WorkflowPayload = { name: string; step: { name: string; type?: string; value?: string[]; responsiblePersonId?: string[]; }[]; registeredBranchId?: string; status?: Status; }; const permissionCondCompany = createPermCondition((_) => true); const permissionCheckCompany = createPermCheck((_) => true); @Route("api/v1/workflow-template") @Tags("Workflow") @Security("keycloak") export class FlowTemplateController extends Controller { @Get() async getFlowTemplate( @Request() req: RequestWithUser, @Query() page: number = 1, @Query() pageSize: number = 30, @Query() status?: Status, @Query() query = "", ) { const where = { OR: [ { name: { contains: query } }, { step: { some: { name: { contains: query } }, }, }, ], ...filterStatus(status), registeredBranch: { OR: permissionCondCompany(req.user), }, } satisfies Prisma.WorkflowTemplateWhereInput; const [result, total] = await prisma.$transaction([ prisma.workflowTemplate.findMany({ where, include: { step: { include: { value: true, responsiblePerson: { include: { user: true }, }, }, }, }, orderBy: [{ statusOrder: "asc" }, { createdAt: "asc" }], take: pageSize, skip: (page - 1) * pageSize, }), prisma.workflowTemplate.count({ where }), ]); return { result, page, pageSize, total }; } @Get("{templateId}") async getFlowTemplateById(@Request() _req: RequestWithUser, @Path() templateId: string) { return await prisma.workflowTemplate.findFirst({ include: { step: { include: { value: true, responsiblePerson: { include: { user: true }, }, }, }, }, where: { id: templateId }, orderBy: { createdAt: "asc" }, }); } @Post() async createFlowTemplate(@Request() req: RequestWithUser, @Body() body: WorkflowPayload) { const userAffiliatedBranch = await prisma.branch.findFirst({ include: branchRelationPermInclude(req.user), where: body.registeredBranchId ? { id: body.registeredBranchId } : { user: { some: { userId: req.user.sub } }, }, }); if (!userAffiliatedBranch) { throw new HttpError( HttpStatus.BAD_REQUEST, "You must be affilated with at least one branch or specifiy branch to be registered (System permission required).", "reqMinAffilatedBranch", ); } await permissionCheckCompany(req.user, userAffiliatedBranch); return await prisma.workflowTemplate.create({ data: { ...body, registeredBranchId: userAffiliatedBranch.id, step: { create: body.step.map((v, i) => ({ type: v.type, value: { create: v.value?.map((val) => ({ value: val, })), }, name: v.name, order: i + 1, responsiblePerson: { create: v.responsiblePersonId?.map((id) => ({ userId: id, })), }, })), }, }, }); } @Put("{templateId}") async updateFlowTemplate( @Request() req: RequestWithUser, @Path() templateId: string, @Body() body: WorkflowPayload, ) { const record = await prisma.workflowTemplate.findUnique({ where: { id: templateId }, include: { registeredBranch: { include: branchRelationPermInclude(req.user), }, }, }); if (!record) throw notFoundError("Workflow"); await permissionCheckCompany(req.user, record.registeredBranch); return await prisma.workflowTemplate.update({ where: { id: templateId }, data: { ...body, statusOrder: +(body.status === "INACTIVE"), step: { deleteMany: {}, create: body.step.map((v, i) => ({ type: v.type, name: v.name, order: i + 1, value: { create: v.value?.map((val) => ({ value: val })), }, responsiblePerson: { create: v.responsiblePersonId?.map((id) => ({ userId: id })), }, })), }, }, }); } @Delete("{templateId}") async deleteFlowTemplateById(@Request() req: RequestWithUser, @Path() templateId: string) { const record = await prisma.workflowTemplate.findUnique({ where: { id: templateId }, include: { registeredBranch: { include: branchRelationPermInclude(req.user), }, }, }); if (!record) throw notFoundError("Workflow"); await permissionCheckCompany(req.user, record.registeredBranch); return await prisma.workflowTemplate.delete({ where: { id: templateId }, }); } }