diff --git a/src/controllers/06-request-list-controller.ts b/src/controllers/06-request-list-controller.ts index 37fd8e2..a01f465 100644 --- a/src/controllers/06-request-list-controller.ts +++ b/src/controllers/06-request-list-controller.ts @@ -321,6 +321,14 @@ export class RequestDataController extends Controller { @Route("/api/v1/request-data/{requestDataId}") @Tags("Request List") export class RequestDataActionController 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; + } + @Post("reject-request-cancel") @Security("keycloak") async rejectRequestCancel( @@ -395,6 +403,17 @@ export class RequestDataActionController extends Controller { }, }, }, + include: { + quotation: { + include: { + customerBranch: { + include: { + customer: { include: { branch: { where: { userId: { not: null } } } } }, + }, + }, + }, + }, + }, }); if (!result) throw notFoundError("Request Data"); @@ -445,15 +464,73 @@ export class RequestDataActionController extends Controller { })), }); }), - tx.taskOrder.updateMany({ - where: { - taskList: { - every: { taskStatus: TaskStatus.Canceled }, + tx.taskOrder + .updateManyAndReturn({ + where: { + taskList: { + every: { taskStatus: TaskStatus.Canceled }, + }, }, - }, - data: { taskOrderStatus: TaskStatus.Canceled }, - }), + data: { taskOrderStatus: TaskStatus.Canceled }, + }) + .then(async (res) => { + await Promise.all( + res.map((v) => + tx.notification.create({ + data: { + title: "สถานะใบเสนอราคาเปลี่ยนแปลง / Quotation Status Updated", + detail: "รหัส / code : " + v.code + " Canceled", + receiverId: v.createdByUserId, + groupReceiver: { create: { name: "document_checker" } }, + }, + }), + ), + ); + }), ]); + + 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 dataUserId: string[] = []; + + result.quotation.customerBranch.customer.branch.forEach((item) => { + if (!dataCustomerId?.includes(item.id) && item.userId) { + dataCustomerId.push(item.id); + dataUserId.push(item.userId); + } + }); + finalTextWork = `เลขที่ใบเสนอราคา: ${result.code} ${result.quotation.workName}`; + + 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), + }); }); } @@ -674,6 +751,19 @@ export class RequestDataActionController extends Controller { }, }, data: { quotationStatus: QuotationStatus.ProcessComplete, urgent: false }, + include: { + customerBranch: { + include: { + customer: { + include: { + branch: { + where: { userId: { not: null } }, + }, + }, + }, + }, + }, + }, }) .then(async (res) => { await tx.notification.createMany({ @@ -683,6 +773,56 @@ export class RequestDataActionController extends Controller { 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), + }); }); // dataRecord.push(record); return data; diff --git a/src/controllers/07-task-controller.ts b/src/controllers/07-task-controller.ts index c9b6b9d..ba2f656 100644 --- a/src/controllers/07-task-controller.ts +++ b/src/controllers/07-task-controller.ts @@ -925,14 +925,18 @@ export class TaskActionController extends Controller { data: { requestDataStatus: RequestDataStatus.Completed }, }) .then(async (res) => { - await tx.notification.createMany({ - data: res.map((v) => ({ - title: "รายการคำขอเสร็จสิ้น / Request Complete", - detail: "รหัส / code : " + v.code + " Completed", - receiverId: v.quotation.createdByUserId, - groupReceiver: { create: { name: "document_checker" } }, - })), - }); + await Promise.all( + res.map((v) => + tx.notification.create({ + data: { + title: "สถานะใบเสนอราคาเปลี่ยนแปลง / Quotation Status Updated", + detail: "รหัส / code : " + v.code + " Completed", + receiverId: v.quotation.createdByUserId, + groupReceiver: { create: { name: "document_checker" } }, + }, + }), + ), + ); }); await tx.quotation .updateManyAndReturn({ @@ -973,14 +977,18 @@ export class TaskActionController extends Controller { }, }) .then(async (res) => { - await tx.notification.createMany({ - data: res.map((v) => ({ - title: "สถานะใบเสนอราคาเปลี่ยนแปลง / Quotation Status Updated", - detail: "รหัส / code : " + v.code + " Completed", - receiverId: v.createdByUserId, - groupReceiver: { create: { name: "document_checker" } }, - })), - }); + await Promise.all( + res.map((v) => + tx.notification.create({ + data: { + title: "สถานะใบเสนอราคาเปลี่ยนแปลง / Quotation Status Updated", + detail: "รหัส / code : " + v.code + " Completed", + receiverId: v.createdByUserId, + groupReceiver: { create: { name: "document_checker" } }, + }, + }), + ), + ); const token = await this.#getLineToken(); diff --git a/src/controllers/08-credit-note-controller.ts b/src/controllers/08-credit-note-controller.ts index fd7a2a3..48ee2ab 100644 --- a/src/controllers/08-credit-note-controller.ts +++ b/src/controllers/08-credit-note-controller.ts @@ -83,6 +83,14 @@ type CreditNoteUpdate = { @Route("api/v1/credit-note") @Tags("Credit Note") export class CreditNoteController 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("stats") @Security("keycloak") async getCreditNoteStats(@Request() req: RequestWithUser, @Query() quotationId?: string) { @@ -366,33 +374,92 @@ export class CreditNoteController extends Controller { update: { value: { increment: 1 } }, }); - return await prisma.creditNote.create({ - include: { - requestWork: { - include: { - request: true, + return await prisma.creditNote + .create({ + include: { + requestWork: { + include: { + request: true, + }, + }, + quotation: { + include: { + customerBranch: { + include: { + customer: { include: { branch: { where: { userId: { not: null } } } } }, + }, + }, + }, }, }, - quotation: true, - }, - data: { - reason: body.reason, - detail: body.detail, - remark: body.remark, - paybackType: body.paybackType, - paybackBank: body.paybackBank, - paybackAccount: body.paybackAccount, - paybackAccountName: body.paybackAccountName, - code: `CN${currentYear.toString().padStart(2, "0")}${currentMonth.toString().padStart(2, "0")}${last.value.toString().padStart(6, "0")}`, - value, - requestWork: { - connect: body.requestWorkId.map((v) => ({ - id: v, - })), + data: { + reason: body.reason, + detail: body.detail, + remark: body.remark, + paybackType: body.paybackType, + paybackBank: body.paybackBank, + paybackAccount: body.paybackAccount, + paybackAccountName: body.paybackAccountName, + code: `CN${currentYear.toString().padStart(2, "0")}${currentMonth.toString().padStart(2, "0")}${last.value.toString().padStart(6, "0")}`, + value, + requestWork: { + connect: body.requestWorkId.map((v) => ({ + id: v, + })), + }, + quotationId: body.quotationId, }, - quotationId: body.quotationId, - }, - }); + }) + .then(async (res) => { + 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.quotation.customerBranch.customer.branch.forEach((item) => { + if (!dataCustomerId?.includes(item.id) && item.userId) { + dataCustomerId.push(item.id); + dataUserId.push(item.userId); + } + }); + finalTextWork = `จำนวนเงิน ${res.value.toFixed(2)} บาท `; + } + + textData = `${textHead}\n\n${textAlert}\n${finalTextWork}${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 res; + }); }, { isolationLevel: Prisma.TransactionIsolationLevel.Serializable }, ); @@ -573,6 +640,14 @@ export class CreditNoteActionController extends Controller { return creditNoteData; } + 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; + } + @Post("accept") @Security("keycloak", MANAGE_ROLES) async acceptCreditNote(@Request() req: RequestWithUser, @Path() creditNoteId: string) { @@ -591,23 +666,81 @@ export class CreditNoteActionController extends Controller { @Body() body: { paybackStatus: PaybackStatus }, ) { await this.#checkPermission(req.user, creditNoteId); - return await prisma.creditNote.update({ - where: { id: creditNoteId }, - include: { - requestWork: { - include: { - request: true, + return await prisma.creditNote + .update({ + where: { id: creditNoteId }, + include: { + requestWork: { + include: { + request: true, + }, + }, + quotation: { + include: { + customerBranch: { + include: { + customer: { include: { branch: { where: { userId: { not: null } } } } }, + }, + }, + }, }, }, - quotation: true, - }, - data: { - creditNoteStatus: - body.paybackStatus === PaybackStatus.Done ? CreditNoteStatus.Success : undefined, - paybackStatus: body.paybackStatus, - paybackDate: body.paybackStatus === PaybackStatus.Done ? new Date() : undefined, - }, - }); + data: { + creditNoteStatus: + body.paybackStatus === PaybackStatus.Done ? CreditNoteStatus.Success : undefined, + paybackStatus: body.paybackStatus, + paybackDate: body.paybackStatus === PaybackStatus.Done ? new Date() : undefined, + }, + }) + .then(async (res) => { + 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.quotation.customerBranch.customer.branch.forEach((item) => { + if (!dataCustomerId?.includes(item.id) && item.userId) { + dataCustomerId.push(item.id); + dataUserId.push(item.userId); + } + }); + finalTextWork = `จำนวนเงิน ${res.value.toFixed(2)} บาท `; + } + + textData = `${textHead}\n\n${textAlert}\n${finalTextWork}${textAlert2}\n\n${textAlert3}`; + + const data = { + to: dataUserId, + messages: [ + { + type: "text", + text: textData, + }, + ], + }; + body.paybackStatus === PaybackStatus.Done + ? await fetch("https://api.line.me/v2/bot/message/multicast", { + method: "POST", + headers: { + Authorization: `Bearer ${token}`, + "Content-Type": "application/json", + }, + body: JSON.stringify(data), + }) + : undefined; + }); } } diff --git a/src/controllers/09-line-controller.ts b/src/controllers/09-line-controller.ts index 8e708be..87480b7 100644 --- a/src/controllers/09-line-controller.ts +++ b/src/controllers/09-line-controller.ts @@ -613,39 +613,22 @@ export class LineController extends Controller { @Query() endDate?: Date, ) { const where = { - OR: - query || pendingOnly - ? [ - ...(queryOrNot(query, [ - { code: { contains: query, mode: "insensitive" } }, - { workName: { contains: query, mode: "insensitive" } }, - { - customerBranch: { - OR: [ - { code: { contains: query, mode: "insensitive" } }, - { registerName: { contains: query, mode: "insensitive" } }, - { firstName: { contains: query, mode: "insensitive" } }, - { firstNameEN: { contains: query, mode: "insensitive" } }, - { lastName: { contains: query, mode: "insensitive" } }, - { lastNameEN: { contains: query, mode: "insensitive" } }, - ], - }, - }, - ]) || []), - ...(queryOrNot(!!pendingOnly, [ - { - requestData: { - some: { - requestDataStatus: "Pending", - }, - }, - }, - { - requestData: { none: {} }, - }, - ]) || []), - ] - : undefined, + OR: queryOrNot(query, [ + { code: { contains: query, mode: "insensitive" } }, + { workName: { contains: query, mode: "insensitive" } }, + { + customerBranch: { + OR: [ + { code: { contains: query, mode: "insensitive" } }, + { registerName: { contains: query, mode: "insensitive" } }, + { firstName: { contains: query, mode: "insensitive" } }, + { firstNameEN: { contains: query, mode: "insensitive" } }, + { lastName: { contains: query, mode: "insensitive" } }, + { lastNameEN: { contains: query, mode: "insensitive" } }, + ], + }, + }, + ]), isDebitNote: false, code, payCondition, @@ -667,6 +650,22 @@ export class LineController extends Controller { }, } : undefined, + AND: pendingOnly + ? { + OR: [ + { + requestData: { + some: { + requestDataStatus: "Pending", + }, + }, + }, + { + requestData: { none: {} }, + }, + ], + } + : undefined, ...whereDateQuery(startDate, endDate), } satisfies Prisma.QuotationWhereInput;