jws-backend/src/controllers/07-task-controller.ts

382 lines
9.8 KiB
TypeScript
Raw Normal View History

import {
Body,
Controller,
Delete,
Get,
Path,
Post,
Put,
Query,
Request,
Route,
Security,
Tags,
} from "tsoa";
import prisma from "../db";
import { notFoundError } from "../utils/error";
2024-12-04 10:26:50 +07:00
import { TaskStatus } from "@prisma/client";
import { RequestWithUser } from "../interfaces/user";
2024-12-03 17:11:44 +07:00
import {
branchRelationPermInclude,
createPermCheck,
createPermCondition,
} from "../services/permission";
import HttpError from "../interfaces/http-error";
import HttpStatus from "../interfaces/http-status";
const MANAGE_ROLES = ["system", "head_of_admin", "admin", "document_checker"];
function globalAllow(user: RequestWithUser["user"]) {
const allowList = ["system", "head_of_admin"];
return allowList.some((v) => user.roles?.includes(v));
}
const permissionCondCompany = createPermCondition((_) => true);
const permissionCheck = createPermCheck(globalAllow);
const permissionCheckCompany = createPermCheck((_) => true);
@Route("/api/v1/task")
@Tags("Task Order")
export class TaskController extends Controller {
2024-12-03 09:37:35 +07:00
@Get("stats")
async getTaskOrderStats() {
const task = await prisma.taskOrder.groupBy({
by: ["taskStatus"],
_count: true,
});
2024-12-03 10:20:45 +07:00
return task.reduce<Record<TaskStatus, number>>(
2024-12-03 09:37:35 +07:00
(a, c) => Object.assign(a, { [c.taskStatus]: c._count }),
2024-12-03 10:20:45 +07:00
{
[TaskStatus.Pending]: 0,
[TaskStatus.InProgress]: 0,
[TaskStatus.Validate]: 0,
[TaskStatus.Complete]: 0,
2024-12-04 14:26:22 +07:00
[TaskStatus.Canceled]: 0,
2024-12-03 10:20:45 +07:00
},
2024-12-03 09:37:35 +07:00
);
}
@Get()
@Security("keycloak")
async getTaskOrderList(
2024-12-03 17:11:44 +07:00
@Request() req: RequestWithUser,
@Query() query: string = "",
@Query() page = 1,
@Query() pageSize = 30,
@Query() taskStatus?: TaskStatus,
2024-12-06 13:21:57 +07:00
) {
return this.getTaskOrderListByCriteria(req, query, page, pageSize, taskStatus);
}
@Post("list")
@Security("keycloak")
async getTaskOrderListByCriteria(
@Request() req: RequestWithUser,
@Query() query: string = "",
@Query() page = 1,
@Query() pageSize = 30,
@Query() taskStatus?: TaskStatus,
@Body() body?: { code?: string[] },
) {
const [result, total] = await prisma.$transaction([
prisma.taskOrder.findMany({
where: {
taskStatus,
2024-12-03 17:11:44 +07:00
registeredBranch: { OR: permissionCondCompany(req.user) },
2024-12-06 13:21:57 +07:00
code: body?.code ? { in: body.code } : undefined,
OR: [
{ code: { contains: query, mode: "insensitive" } },
{ taskName: { contains: query } },
{ contactName: { contains: query } },
{ contactTel: { contains: query } },
],
},
include: {
institution: true,
createdBy: true,
},
}),
prisma.taskOrder.count(),
]);
return { result, total, page, pageSize };
}
@Get("{taskId}")
@Security("keycloak")
2024-12-03 17:11:44 +07:00
async getTaskOrder(@Request() req: RequestWithUser, @Path() taskId: string) {
const record = await prisma.taskOrder.findFirst({
2024-12-03 17:11:44 +07:00
where: { id: taskId, registeredBranch: { OR: permissionCondCompany(req.user) } },
include: {
taskList: {
include: {
requestWork: {
include: {
request: {
include: {
employee: true,
quotation: true,
},
},
2024-12-06 14:37:23 +07:00
productService: {
include: {
service: true,
work: true,
product: true,
},
},
},
},
},
},
institution: true,
createdBy: true,
},
});
if (!record) throw notFoundError("Task Order");
return record;
}
@Post()
2024-12-03 17:11:44 +07:00
@Security("keycloak", MANAGE_ROLES)
async createTaskOrderList(
@Request() req: RequestWithUser,
@Body()
body: {
taskName: string;
contactName: string;
contactTel: string;
institutionId: string;
2024-12-03 17:11:44 +07:00
registeredBranchId?: string;
2024-12-04 10:49:22 +07:00
taskList: { requestWorkId: string; step: number }[];
},
) {
return await prisma.$transaction(async (tx) => {
const last = await tx.runningNo.upsert({
where: {
key: "TASK",
},
create: {
key: "TASK",
value: 1,
},
update: {
value: { increment: 1 },
},
});
const current = new Date();
const year = `${current.getFullYear()}`.slice(-2).padStart(2, "0");
const month = `${current.getMonth() + 1}`.padStart(2, "0");
const code = `PO${year}${month}${last.value.toString().padStart(6, "0")}`;
2024-12-04 10:49:22 +07:00
const { taskList, ...rest } = body;
2024-12-03 17:11:44 +07:00
const userAffiliatedBranch = await tx.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 specify branch to be registered (System permission required).",
"reqMinAffilatedBranch",
);
}
await permissionCheckCompany(req.user, userAffiliatedBranch);
2024-12-06 11:25:38 +07:00
return await tx.taskOrder.create({
include: {
taskList: {
include: {
requestWork: {
include: {
request: {
include: {
employee: true,
quotation: true,
},
},
productService: {
include: {
service: true,
work: true,
product: true,
},
},
},
},
},
},
institution: true,
createdBy: true,
},
data: {
...rest,
code,
2024-12-03 17:11:44 +07:00
registeredBranchId: userAffiliatedBranch.id,
createdByUserId: req.user.sub,
taskList: {
2024-12-04 10:49:22 +07:00
connect: taskList.map((v) => ({ step_requestWorkId: v })),
},
},
});
});
}
@Put("{taskId}")
@Security("keycloak")
async editTaskById(
2024-12-03 17:11:44 +07:00
@Request() req: RequestWithUser,
@Path() taskId: string,
@Body()
body: {
taskName: string;
taskStatus: TaskStatus;
contactName: string;
contactTel: string;
institutionId: string;
2024-12-04 10:49:22 +07:00
taskList: { requestWorkId: string; step: number }[];
},
) {
const record = await prisma.taskOrder.findFirst({
where: { id: taskId },
include: {
2024-12-03 17:11:44 +07:00
registeredBranch: { include: branchRelationPermInclude(req.user) },
taskList: {
include: { requestWork: true },
},
institution: true,
createdBy: true,
},
});
2024-12-03 17:11:44 +07:00
if (!record) throw notFoundError("Task Order");
await permissionCheckCompany(req.user, record.registeredBranch);
await prisma.taskOrder.update({
where: { id: taskId },
include: {
taskList: {
include: {
requestWork: true,
},
},
institution: true,
2024-12-03 17:11:44 +07:00
registeredBranch: true,
createdBy: true,
},
data: {
...body,
taskList: {
disconnect: record?.taskList
.filter(
(lhs) =>
2024-12-04 10:49:22 +07:00
!body.taskList.find(
(rhs) => lhs.requestWorkId === rhs.requestWorkId && lhs.step === rhs.step,
),
)
.map((v) => ({
step_requestWorkId: {
requestWorkId: v.requestWorkId,
step: v.step,
},
})),
2024-12-04 10:49:22 +07:00
connect: body.taskList.map((v) => ({ step_requestWorkId: v })),
},
},
});
}
@Delete("{taskId}")
2024-12-03 17:11:44 +07:00
@Security("keycloak", MANAGE_ROLES)
async deleteTask(@Request() req: RequestWithUser, @Path() taskId: string) {
await prisma.$transaction(async (tx) => {
2024-12-03 17:11:44 +07:00
let record = await tx.taskOrder.findFirst({
where: { id: taskId },
include: {
registeredBranch: {
include: branchRelationPermInclude(req.user),
},
},
});
if (!record) throw notFoundError("Task Order");
2024-12-03 17:11:44 +07:00
await permissionCheck(req.user, record.registeredBranch);
});
}
}
@Route("/api/v1/task/{taskId}")
@Tags("Task Order")
export class TaskActionController extends Controller {
@Post("accept")
2024-12-04 14:52:14 +07:00
@Security("keycloak")
async acceptTaskOrder(@Request() req: RequestWithUser, @Path() taskId: string) {
const record = await prisma.taskOrder.findFirst({
include: {
taskList: {
orderBy: { step: "asc" },
},
},
where: { id: taskId },
});
if (!record) throw notFoundError("Task Order");
return await prisma.$transaction(async (tx) => {
await tx.taskOrder.update({
where: { id: taskId },
data: {
2024-12-02 13:13:50 +07:00
taskStatus: "InProgress",
},
});
await tx.requestWorkStepStatus.updateMany({
where: { taskOrderId: taskId },
data: {
workStatus: "InProgress",
},
});
await tx.requestData.updateMany({
where: {
requestWork: {
some: {
stepStatus: {
some: { taskOrderId: taskId },
},
},
},
},
data: { requestDataStatus: "InProgress" },
});
});
}
@Post("submit")
@Security("keycloak")
async submitTaskOrder(@Request() req: RequestWithUser, @Path() taskId: string) {}
@Post("complete")
@Security("keycloak")
async completeTaskOrder(@Request() req: RequestWithUser, @Path() taskId: string) {}
}
2024-12-04 10:49:22 +07:00
@Route("api/v1/task-order/{taskId}")
@Tags("Task Order")
export class TaskOrderAttachmentController extends Controller {}