jws-backend/src/controllers/06-request-list-controller.ts
Kanjana 50fca4d540
All checks were successful
Spell Check / Spell Check with Typos (push) Successful in 5s
feat: remove customerName add reportDate
2025-07-09 16:02:45 +07:00

1296 lines
37 KiB
TypeScript

import {
Prisma,
QuotationStatus,
RequestDataStatus,
RequestWorkStatus,
TaskStatus,
} from "@prisma/client";
import {
Body,
Controller,
Delete,
Get,
Head,
Path,
Post,
Put,
Query,
Request,
Route,
Security,
Tags,
} from "tsoa";
import { RequestWithUser } from "../interfaces/user";
import prisma from "../db";
import {
branchRelationPermInclude,
createPermCheck,
createPermCondition,
} from "../services/permission";
import { queryOrNot, whereDateQuery } from "../utils/relation";
import { notFoundError } from "../utils/error";
import { deleteFile, fileLocation, getFile, getPresigned, listFile, setFile } from "../utils/minio";
import HttpError from "../interfaces/http-error";
import HttpStatus from "../interfaces/http-status";
import { getGroupUser } from "../services/keycloak";
// User in company can edit.
const permissionCheck = createPermCheck((_) => true);
// 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: {
registeredBranch: { OR: permissionCond(req.user) },
},
} satisfies Prisma.RequestDataWhereInput;
const list = await prisma.requestData.groupBy({
_count: true,
by: "requestDataStatus",
where: where,
});
return list.reduce<Record<RequestDataStatus, number>>(
(a, c) => Object.assign(a, { [c.requestDataStatus]: c._count }),
{
[RequestDataStatus.Pending]: 0,
[RequestDataStatus.Ready]: 0,
[RequestDataStatus.InProgress]: 0,
[RequestDataStatus.Completed]: 0,
[RequestDataStatus.Canceled]: 0,
},
);
}
@Get()
@Security("keycloak")
async getRequestDataList(
@Request() req: RequestWithUser,
@Query() page: number = 1,
@Query() pageSize: number = 30,
@Query() query: string = "",
@Query() responsibleOnly?: boolean,
@Query() requestDataStatus?: RequestDataStatus,
@Query() quotationId?: string,
@Query() code?: string,
@Query() incomplete?: boolean,
@Query() startDate?: Date,
@Query() endDate?: Date,
) {
const where = {
OR: queryOrNot<Prisma.RequestDataWhereInput[]>(query, [
{ code: { contains: query, mode: "insensitive" } },
{ quotation: { code: { contains: query, mode: "insensitive" } } },
{ quotation: { workName: { contains: query, mode: "insensitive" } } },
{
quotation: {
customerBranch: {
OR: [
{ code: { contains: query, mode: "insensitive" } },
{ registerName: { contains: query, mode: "insensitive" } },
{ registerNameEN: { contains: query, mode: "insensitive" } },
{ firstName: { contains: query, mode: "insensitive" } },
{ firstNameEN: { contains: query, mode: "insensitive" } },
{ lastName: { contains: query, mode: "insensitive" } },
{ lastNameEN: { contains: query, mode: "insensitive" } },
],
},
},
},
{
employee: {
OR: [
{
employeePassport: {
some: { number: { contains: query, mode: "insensitive" } },
},
},
{ code: { contains: query, mode: "insensitive" } },
{ firstName: { contains: query, mode: "insensitive" } },
{ firstNameEN: { contains: query, mode: "insensitive" } },
{ lastName: { contains: query, mode: "insensitive" } },
{ lastNameEN: { contains: query, mode: "insensitive" } },
],
},
},
]),
code,
requestDataStatus: incomplete
? {
notIn: [RequestDataStatus.Completed, RequestDataStatus.Canceled],
}
: requestDataStatus,
requestWork: responsibleOnly
? {
some: {
productService: {
service: {
workflow: {
step: {
some: {
OR: [
{
responsiblePerson: {
some: { userId: req.user.sub },
},
},
{
responsibleGroup: {
some: {
group: {
in: await getGroupUser(req.user.sub).then((r) =>
r.map(({ name }: { name: string }) => name),
),
},
},
},
},
],
},
},
},
},
},
},
}
: undefined,
quotation: {
id: quotationId,
registeredBranch: { OR: permissionCond(req.user) },
},
...whereDateQuery(startDate, endDate),
} satisfies Prisma.RequestDataWhereInput;
const [result, total] = await prisma.$transaction([
prisma.requestData.findMany({
where,
include: {
quotation: {
include: {
productServiceList: {
include: {
service: {
include: {
workflow: {
include: {
step: {
orderBy: { order: "asc" },
include: {
value: true,
responsiblePerson: {
include: { user: true },
},
responsibleInstitution: true,
responsibleGroup: true,
},
},
},
},
},
},
},
},
customerBranch: {
include: { customer: true },
},
},
},
employee: {
include: {
employeePassport: {
orderBy: { expireDate: "desc" },
},
customerBranch: {
include: {
province: {
include: {
employmentOffice: true,
},
},
district: {
include: {
employmentOffice: true,
},
},
},
},
},
},
},
take: pageSize,
skip: (page - 1) * pageSize,
orderBy: [{ quotation: { urgent: "desc" } }, { createdAt: "desc" }],
}),
prisma.requestData.count({ where }),
]);
const dataRequestData = result.map((item) => {
const employee = item.employee;
const dataOffice =
employee.customerBranch.district?.employmentOffice.at(0) ??
employee.customerBranch.province?.employmentOffice.at(0);
return {
...item,
dataOffice,
};
});
return {
result: dataRequestData,
page,
pageSize,
total,
};
}
@Get("{requestDataId}")
@Security("keycloak")
async getRequestData(@Path() requestDataId: string) {
const record = await prisma.requestData.findFirst({
where: { id: requestDataId },
include: {
quotation: {
include: {
customerBranch: { include: { customer: true } },
debitNoteQuotation: {
select: { code: true },
},
invoice: {
include: {
installments: true,
payment: true,
},
},
createdBy: true,
},
},
employee: {
include: {
employeePassport: {
orderBy: { expireDate: "desc" },
},
},
},
},
});
if (!record) throw notFoundError("Request Data");
return record;
}
@Post("update-messenger")
@Security("keycloak")
async updateRequestData(
@Request() req: RequestWithUser,
@Body()
boby: {
defaultMessengerId: string;
requestDataId: string[];
},
) {
const record = await prisma.requestData.updateManyAndReturn({
where: {
id: { in: boby.requestDataId },
quotation: {
registeredBranch: {
OR: permissionCond(req.user),
},
},
},
data: {
defaultMessengerId: boby.defaultMessengerId,
},
});
if (record.length <= 0) throw notFoundError("Request Data");
return record[0];
}
}
@Route("/api/v1/request-data/{requestDataId}")
@Tags("Request List")
export class RequestDataActionController extends Controller {
@Post("reject-request-cancel")
@Security("keycloak")
async rejectRequestCancel(
@Request() req: RequestWithUser,
@Path() requestDataId: string,
@Body()
body: {
reason?: string;
},
) {
const result = await prisma.requestData.updateManyAndReturn({
where: {
id: requestDataId,
quotation: {
registeredBranch: {
OR: permissionCond(req.user),
},
},
},
data: {
rejectRequestCancel: true,
rejectRequestCancelReason: body.reason || "",
},
});
if (result.length <= 0) throw notFoundError("Request Data");
return result[0];
}
@Post("request-work/{requestWorkId}/reject-request-cancel")
@Security("keycloak")
async rejectWorkRequestCancel(
@Request() req: RequestWithUser,
@Path() requestWorkId: string,
@Body()
body: {
reason?: string;
},
) {
const result = await prisma.requestWork.updateManyAndReturn({
where: {
id: requestWorkId,
request: {
quotation: {
registeredBranch: {
OR: permissionCond(req.user),
},
},
},
},
data: {
rejectRequestCancel: true,
rejectRequestCancelReason: body.reason || "",
},
});
if (result.length <= 0) throw notFoundError("Request Data");
return result[0];
}
@Post("cancel")
@Security("keycloak")
async cancelRequestData(@Request() req: RequestWithUser, @Path() requestDataId: string) {
const result = await prisma.requestData.findFirst({
where: {
id: requestDataId,
quotation: {
registeredBranch: {
OR: permissionCond(req.user),
},
},
},
});
if (!result) throw notFoundError("Request Data");
await prisma.$transaction(async (tx) => {
const workStepCondition = {
requestWork: { requestDataId },
workStatus: { notIn: [RequestWorkStatus.Completed, RequestWorkStatus.Ended] },
};
await Promise.all([
tx.requestData.update({
where: { id: requestDataId },
data: {
requestDataStatus: RequestDataStatus.Canceled,
},
}),
tx.requestWorkStepStatus.updateMany({
where: workStepCondition,
data: {
workStatus: RequestWorkStatus.Canceled,
},
}),
tx.task.updateMany({
where: {
taskStatus: { notIn: [TaskStatus.Complete, TaskStatus.Redo] },
requestWorkStep: workStepCondition,
},
data: { taskStatus: TaskStatus.Canceled },
}),
]);
await Promise.all([
tx.quotation
.updateManyAndReturn({
where: {
requestData: {
every: { requestDataStatus: RequestDataStatus.Canceled },
},
},
data: { quotationStatus: QuotationStatus.Canceled, urgent: false },
})
.then(async (res) => {
await tx.notification.createMany({
data: res.map((v) => ({
title: "สถานะใบเสนอราคาเปลี่ยนแปลง / Quotation Status Updated",
detail: "รหัส / code : " + v.code + " Canceled",
receiverId: v.createdByUserId,
})),
});
}),
tx.taskOrder.updateMany({
where: {
taskList: {
every: { taskStatus: TaskStatus.Canceled },
},
},
data: { taskOrderStatus: TaskStatus.Canceled },
}),
]);
});
}
@Put("request-work/step-status/{step}")
@Security("keycloak")
async updateRequestWorkDataStepStatus(
@Path() requestDataId: string,
@Path() step: number,
@Body()
payload: {
workStatus?: RequestWorkStatus;
requestWorkId: string;
attributes?: Record<string, any>;
customerDuty?: boolean | null;
customerDutyCost?: number | null;
companyDuty?: boolean | null;
companyDutyCost?: number | null;
individualDuty?: boolean | null;
individualDutyCost?: number | null;
responsibleUserLocal?: boolean | null;
responsibleUserId?: string | null;
}[],
) {
payload.forEach((item) => {
if (!item.responsibleUserId) item.responsibleUserId = undefined;
});
return await prisma.$transaction(async (tx) => {
const workStepCondition = await tx.requestData.findFirst({
where: {
id: requestDataId,
},
select: { id: true },
});
if (!workStepCondition) {
throw new Error("RequestWork not found requestDataId");
}
const data = await Promise.all(
payload.map(async (item) => {
return await tx.requestWorkStepStatus.upsert({
include: {
requestWork: {
include: {
request: true,
},
},
},
where: {
step_requestWorkId: {
step: step,
requestWorkId: item.requestWorkId,
},
requestWork: {
request: { id: requestDataId },
},
},
create: {
...item,
step: step,
requestWorkId: item.requestWorkId,
},
update: item,
});
}),
);
if (
data.some((item) => {
return (
item.workStatus === "Ready" && item.requestWork.request.requestDataStatus === "Pending"
);
})
) {
await tx.requestData.updateMany({
where: {
id: requestDataId,
requestDataStatus: "Pending",
},
data: { requestDataStatus: "Ready" },
});
}
if (
data.some((item) => {
return (
item.workStatus === "InProgress" ||
item.workStatus === "Waiting" ||
item.workStatus === "Validate" ||
item.workStatus === "Completed" ||
item.workStatus === "Ended"
);
})
) {
await tx.requestData.update({
where: {
id: requestDataId,
},
data: { requestDataStatus: "InProgress" },
});
}
if (
data.some((item) => {
return item.workStatus === "Canceled";
})
) {
const dataId = data.map((itemId) => itemId.requestWork.id);
await tx.task.updateMany({
where: {
taskStatus: { notIn: [TaskStatus.Complete, TaskStatus.Redo] },
requestWorkStep: {
step: step,
requestWorkId: { in: dataId },
workStatus: { notIn: [RequestWorkStatus.Completed, RequestWorkStatus.Ended] },
},
},
data: { taskStatus: TaskStatus.Canceled },
});
await Promise.all([
tx.quotation
.updateManyAndReturn({
where: {
quotationStatus: { not: QuotationStatus.Canceled },
requestData: {
every: { requestDataStatus: RequestDataStatus.Canceled },
},
},
data: { quotationStatus: QuotationStatus.Canceled, urgent: false },
})
.then(async (res) => {
await tx.notification.createMany({
data: res.map((v) => ({
title: "สถานะใบเสนอราคาเปลี่ยนแปลง / Quotation Status Updated",
detail: "รหัส / code : " + v.code + " Canceled",
receiverId: v.createdByUserId,
})),
});
}),
tx.taskOrder.updateMany({
where: {
taskList: {
every: { taskStatus: TaskStatus.Canceled },
},
},
data: { taskOrderStatus: TaskStatus.Canceled },
}),
]);
}
const requestList = await tx.requestData.findMany({
include: {
requestWork: {
include: {
productService: {
include: {
product: true,
service: true,
work: {
include: { productOnWork: true },
},
},
},
stepStatus: true,
},
},
},
where: {
requestWork: {
some: {
requestDataId: requestDataId,
},
},
},
});
const completed: string[] = [];
requestList.forEach((item) => {
const completeCheck = item.requestWork.every((work) => {
const stepCount =
work.productService.work?.productOnWork.find(
(v) => v.productId === work.productService.productId,
)?.stepCount || 0;
const completeCount = work.stepStatus.filter(
(v) =>
v.workStatus === RequestWorkStatus.Completed ||
v.workStatus === RequestWorkStatus.Ended ||
v.workStatus === RequestWorkStatus.Canceled,
).length;
// NOTE: step found then check if complete count equals step count
if (stepCount === completeCount && completeCount > 0) return true;
// NOTE: likely no step found and completed at least one
if (stepCount === 0 && completeCount > 0) return true;
});
if (completeCheck) completed.push(item.id);
});
await tx.requestData.updateMany({
where: { id: { in: completed } },
data: { requestDataStatus: RequestDataStatus.Completed },
});
await tx.quotation
.updateManyAndReturn({
where: {
quotationStatus: {
notIn: [QuotationStatus.Canceled, QuotationStatus.ProcessComplete],
},
requestData: {
every: {
requestDataStatus: {
in: [RequestDataStatus.Canceled, RequestDataStatus.Completed],
},
},
},
},
data: { quotationStatus: QuotationStatus.ProcessComplete, urgent: false },
})
.then(async (res) => {
await tx.notification.createMany({
data: res.map((v) => ({
title: "สถานะใบเสนอราคาเปลี่ยนแปลง / Quotation Status Updated",
detail: "รหัส / code : " + v.code + " Completed",
receiverId: v.createdByUserId,
})),
});
});
// dataRecord.push(record);
return data;
});
}
}
@Route("/api/v1/request-work")
@Tags("Request List")
export class RequestListController extends Controller {
async #getLineToken() {
if (!process.env.LINE_MESSAGING_API_TOKEN) {
console.warn("Line Webhook Activated but LINE_MESSAGING_API_TOKEN not set.");
}
return process.env.LINE_MESSAGING_API_TOKEN;
}
@Get()
@Security("keycloak")
async getRequestWork(
@Request() req: RequestWithUser,
@Query() page: number = 1,
@Query() pageSize: number = 30,
@Query() requestDataId?: string,
@Query() workStatus?: RequestWorkStatus,
@Query() readyToTask?: boolean,
@Query() cancelOnly?: boolean,
@Query() quotationId?: string,
) {
let statusCondition: Prisma.RequestWorkWhereInput["stepStatus"] = {};
if (readyToTask) {
statusCondition = {
some: {
OR: [
{ workStatus: RequestWorkStatus.Ready },
{
workStatus: { in: [RequestWorkStatus.Ready, RequestWorkStatus.InProgress] },
task: {
some: {
taskStatus: TaskStatus.Redo,
requestWorkStep: {
workStatus: { notIn: [RequestWorkStatus.Completed, RequestWorkStatus.Ended] },
},
},
},
},
],
},
};
}
if (workStatus && !readyToTask && !cancelOnly) {
statusCondition = {
some: { workStatus },
};
}
const where = {
OR: cancelOnly
? [
{
stepStatus: { some: { workStatus: RequestWorkStatus.Canceled } },
},
{
request: { requestDataStatus: RequestDataStatus.Canceled },
},
]
: undefined,
stepStatus: readyToTask || workStatus ? statusCondition : undefined,
creditNoteId: cancelOnly ? null : undefined,
request: {
id: requestDataId,
requestDataStatus: readyToTask
? { notIn: [RequestDataStatus.Canceled, RequestDataStatus.Completed] }
: undefined,
quotationId,
quotation: {
registeredBranch: { OR: permissionCond(req.user) },
},
},
} satisfies Prisma.RequestWorkWhereInput;
const [result, total] = await prisma.$transaction([
prisma.requestWork.findMany({
where,
include: {
request: {
include: {
quotation: readyToTask
? {
include: {
customerBranch: {
include: { customer: true },
},
},
}
: true,
employee: true,
},
},
stepStatus: cancelOnly
? true
: {
include: {
task: { where: { taskStatus: TaskStatus.Complete } },
},
},
productService: {
include: {
service: {
include: {
workflow: {
include: {
step: {
include: {
value: true,
responsiblePerson: {
include: { user: true },
},
responsibleInstitution: true,
responsibleGroup: 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}")
@Security("keycloak")
async getRequestWorkById(@Path() requestWorkId: string) {
const record = await prisma.requestWork.findFirst({
include: {
request: {
include: {
quotation: true,
employee: true,
},
},
stepStatus: true,
productService: {
include: {
service: {
include: {
workflow: {
include: {
step: {
include: {
value: true,
responsiblePerson: {
include: { user: true },
},
responsibleInstitution: true,
responsibleGroup: 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<string, any> },
) {
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: {
workStatus?: RequestWorkStatus;
attributes?: Record<string, any>;
customerDuty?: boolean | null;
customerDutyCost?: number | null;
companyDuty?: boolean | null;
companyDutyCost?: number | null;
individualDuty?: boolean | null;
individualDutyCost?: number | null;
responsibleUserLocal?: boolean | null;
responsibleUserId?: string | null;
},
) {
if (!payload.responsibleUserId) payload.responsibleUserId = undefined;
return await prisma.$transaction(async (tx) => {
const record = await tx.requestWorkStepStatus.upsert({
include: {
requestWork: {
include: {
request: true,
},
},
},
where: {
step_requestWorkId: {
step: step,
requestWorkId,
},
},
create: {
...payload,
step: step,
requestWorkId,
},
update: payload,
});
if (record.responsibleUserId === null) {
await tx.requestWorkStepStatus.update({
where: {
step_requestWorkId: {
step: step,
requestWorkId,
},
responsibleUserId: null,
},
data: {
responsibleUserId: record.requestWork?.request.defaultMessengerId,
},
});
}
switch (payload.workStatus) {
case "Ready":
if (record.requestWork.request.requestDataStatus === "Pending") {
await tx.requestData.updateMany({
where: {
id: record.requestWork.requestDataId,
requestDataStatus: "Pending",
},
data: { requestDataStatus: "Ready" },
});
}
break;
case "InProgress":
case "Waiting":
case "Validate":
case "Completed":
case "Ended":
await tx.requestData.update({
where: {
id: record.requestWork.requestDataId,
},
data: { requestDataStatus: "InProgress" },
});
break;
case "Canceled":
await tx.task.updateMany({
where: {
taskStatus: { notIn: [TaskStatus.Complete, TaskStatus.Redo] },
requestWorkStep: {
step: step,
requestWorkId,
workStatus: { notIn: [RequestWorkStatus.Completed, RequestWorkStatus.Ended] },
},
},
data: { taskStatus: TaskStatus.Canceled },
});
await Promise.all([
tx.quotation
.updateManyAndReturn({
where: {
quotationStatus: { not: QuotationStatus.Canceled },
requestData: {
every: { requestDataStatus: RequestDataStatus.Canceled },
},
},
data: { quotationStatus: QuotationStatus.Canceled, urgent: false },
})
.then(async (res) => {
await tx.notification.createMany({
data: res.map((v) => ({
title: "สถานะใบเสนอราคาเปลี่ยนแปลง / Quotation Status Updated",
detail: "รหัส / code : " + v.code + " Canceled",
receiverId: v.createdByUserId,
})),
});
}),
tx.taskOrder.updateMany({
where: {
taskList: {
every: { taskStatus: TaskStatus.Canceled },
},
},
data: { taskOrderStatus: TaskStatus.Canceled },
}),
]);
break;
}
const requestList = await tx.requestData.findMany({
include: {
requestWork: {
include: {
productService: {
include: {
product: true,
service: true,
work: {
include: { productOnWork: true },
},
},
},
stepStatus: true,
},
},
},
where: {
requestWork: {
some: {
requestDataId: record.requestWork.requestDataId,
},
},
},
});
const completed: string[] = [];
requestList.forEach((item) => {
const completeCheck = item.requestWork.every((work) => {
const stepCount =
work.productService.work?.productOnWork.find(
(v) => v.productId === work.productService.productId,
)?.stepCount || 0;
const completeCount = work.stepStatus.filter(
(v) =>
v.workStatus === RequestWorkStatus.Completed ||
v.workStatus === RequestWorkStatus.Ended ||
v.workStatus === RequestWorkStatus.Canceled,
).length;
// NOTE: step found then check if complete count equals step count
if (stepCount === completeCount && completeCount > 0) return true;
// NOTE: likely no step found and completed at least one
if (stepCount === 0 && completeCount > 0) return true;
});
if (completeCheck) completed.push(item.id);
});
await tx.requestData.updateMany({
where: { id: { in: completed } },
data: { requestDataStatus: RequestDataStatus.Completed },
});
await tx.quotation
.updateManyAndReturn({
where: {
quotationStatus: {
notIn: [QuotationStatus.Canceled, QuotationStatus.ProcessComplete],
},
AND: [
{
requestData: {
every: {
requestDataStatus: {
in: [RequestDataStatus.Canceled, RequestDataStatus.Completed],
},
},
},
},
{
requestData: {
some: {},
},
},
],
},
data: { quotationStatus: QuotationStatus.ProcessComplete, urgent: false },
include: {
customerBranch: {
include: {
customer: {
include: {
branch: {
where: { userId: { not: null } },
},
},
},
},
},
},
})
.then(async (res) => {
await tx.notification.createMany({
data: res.map((v) => ({
title: "สถานะใบเสนอราคาเปลี่ยนแปลง / Quotation Status Updated",
detail: "รหัส / code : " + v.code + " Completed",
receiverId: v.createdByUserId,
})),
});
const token = await this.#getLineToken();
if (!token) return;
const textHead = "JWS ALERT:";
const textAlert = "ขอแจ้งให้ทราบว่าใบเสนอราคา";
const textAlert2 = "ได้ดำเนินการเสร็จสิ้นทุกกระบวนการเรียบร้อยแล้ว";
const textAlert3 = "หากต้องการข้อมูลเพิ่มเติม กรุณาแจ้งให้ฝ่ายที่เกี่ยวข้องทราบ 🙏";
let finalTextWork = "";
let textData = "";
let dataCustomerId: string[] = [];
let textWorkList: string[] = [];
let dataUserId: string[] = [];
if (res) {
res.forEach((data, index) => {
data.customerBranch.customer.branch.forEach((item) => {
if (!dataCustomerId?.includes(item.id) && item.userId) {
dataCustomerId.push(item.id);
dataUserId.push(item.userId);
}
});
textWorkList.push(`${index + 1}. เลขที่ใบเสนอราคา ${data.code} ${data.workName}`);
});
finalTextWork = textWorkList.join("\n");
}
textData = `${textHead}\n\n${textAlert}\n${finalTextWork}\n${textAlert2}\n\n${textAlert3}`;
const data = {
to: dataUserId,
messages: [
{
type: "text",
text: textData,
},
],
};
await fetch("https://api.line.me/v2/bot/message/multicast", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify(data),
});
});
return record;
});
}
}
@Route("api/v1/request-work/{requestId}/step-status/{step}")
@Tags("Request List")
export class RequestListFileController extends Controller {
private async checkPermission(user: RequestWithUser["user"], id: string) {
const data = await prisma.requestWork.findUnique({
where: { id },
include: {
request: {
include: {
quotation: {
include: { registeredBranch: { include: branchRelationPermInclude(user) } },
},
},
},
},
});
if (!data) throw notFoundError("Request Work");
await permissionCheck(user, data.request.quotation.registeredBranch);
}
@Get("attachment")
@Security("keycloak")
async listAttachment(
@Request() req: RequestWithUser,
@Path() requestId: string,
@Path() step: number,
) {
await this.checkPermission(req.user, requestId);
return await listFile(fileLocation.request.attachment(requestId, step));
}
@Get("attachment/{name}")
@Security("keycloak")
async getAttachment(
@Request() req: RequestWithUser,
@Path() requestId: string,
@Path() step: number,
@Path() name: string,
) {
await this.checkPermission(req.user, requestId);
return await getFile(fileLocation.request.attachment(requestId, step, name));
}
@Head("attachment/{name}")
@Security("keycloak")
async headAttachment(
@Request() req: RequestWithUser,
@Path() requestId: string,
@Path() step: number,
@Path() name: string,
) {
await this.checkPermission(req.user, requestId);
return await getPresigned("head", fileLocation.request.attachment(requestId, step, name));
}
@Put("attachment/{name}")
@Security("keycloak")
async putAttachment(
@Request() req: RequestWithUser,
@Path() requestId: string,
@Path() step: number,
@Path() name: string,
) {
await this.checkPermission(req.user, requestId);
return await setFile(fileLocation.request.attachment(requestId, step, name));
}
@Delete("attachment/{name}")
@Security("keycloak")
async delAttachment(
@Request() req: RequestWithUser,
@Path() requestId: string,
@Path() step: number,
@Path() name: string,
) {
await this.checkPermission(req.user, requestId);
return await deleteFile(fileLocation.request.attachment(requestId, step, name));
}
}