From 0319990232e6b62614bea1458a1e87b49ea80d56 Mon Sep 17 00:00:00 2001 From: Methapon2001 <61303214+Methapon2001@users.noreply.github.com> Date: Fri, 19 Jul 2024 17:59:35 +0700 Subject: [PATCH] feat: structure input before insert to database --- src/controllers/quotation-controller.ts | 181 +++++++++++++++++++++++- 1 file changed, 175 insertions(+), 6 deletions(-) diff --git a/src/controllers/quotation-controller.ts b/src/controllers/quotation-controller.ts index dfa1554..57f7853 100644 --- a/src/controllers/quotation-controller.ts +++ b/src/controllers/quotation-controller.ts @@ -26,7 +26,7 @@ type QuotationCreate = { paySplitCount?: number; paySplit?: Date[]; - payBillDate?: number; + payBillDate?: Date; workerCount: number; // EmployeeId or Create new employee @@ -65,12 +65,12 @@ type QuotationCreate = { id: string; // Other fields will come from original data work: { + id: string; // Name field will come from original data product: { id: string; amount: number; discount: number; - pricePerUnit: number; }[]; }[]; }[]; @@ -84,7 +84,7 @@ type QuotationUpdate = { paySplitCount?: number; paySplit?: Date[]; - payBillDate?: number; + payBillDate?: Date; workerCount: number; // EmployeeId or Create new employee @@ -123,12 +123,12 @@ type QuotationUpdate = { id: string; // Other fields will come from original data work: { + id: string; // Name field will come from original data product: { id: string; amount: number; discount: number; - pricePerUnit: number; }[]; }[]; }[]; @@ -197,7 +197,168 @@ export class QuotationController extends Controller { @Post() @Security("keycloak") - async createQuotation(@Request() req: RequestWithUser, @Body() body: QuotationCreate) {} + async createQuotation(@Request() req: RequestWithUser, @Body() body: QuotationCreate) { + const existingEmployee = body.worker.filter((v) => typeof v === "string"); + const serviceIdList = body.service.map((v) => v.id); + const productIdList = body.service.flatMap((a) => + a.work.flatMap((b) => b.product.map((c) => c.id)), + ); + + const [customer, customerBranch, employee, service, product] = await prisma.$transaction([ + prisma.customer.findUnique({ + where: { id: body.customerId }, + }), + prisma.customerBranch.findUnique({ + include: { customer: true }, + where: { id: body.customerBranchId }, + }), + prisma.employee.findMany({ + where: { id: { in: existingEmployee } }, + }), + prisma.service.findMany({ + include: { + work: true, + }, + where: { id: { in: serviceIdList } }, + }), + prisma.product.findMany({ + where: { id: { in: productIdList } }, + }), + ]); + + if (!customer) + throw new HttpError( + HttpStatus.BAD_REQUEST, + "Customer cannot be found.", + "relationCustomerNotFound", + ); + if (!customerBranch) + throw new HttpError( + HttpStatus.BAD_REQUEST, + "Customer Branch cannot be found.", + "relationCustomerBranchNotFound", + ); + + const { service: _service, worker: _worker, ...rest } = body; + + await prisma.$transaction(async (tx) => { + const nonExistEmployee = body.worker.filter((v) => typeof v !== "string"); + const lastEmployee = await tx.runningNo.upsert({ + where: { + key: `EMPLOYEE_${customerBranch.customer.code}-${customerBranch.branchNo.toString().padStart(2, "0")}-${new Date().getFullYear().toString().slice(-2).padStart(2, "0")}`, + }, + create: { + key: `EMPLOYEE_${customerBranch.customer.code}-${customerBranch.branchNo.toString().padStart(2, "0")}-${new Date().getFullYear().toString().slice(-2).padStart(2, "0")}`, + value: 1, + }, + update: { value: { increment: nonExistEmployee.length } }, + }); + const newEmployee = await Promise.all( + nonExistEmployee.map(async (v, i) => + tx.employee.create({ + data: { + ...v, + code: `${customerBranch.customer.code}-${customerBranch.branchNo.toString().padStart(2, "0")}-${new Date().getFullYear().toString().slice(-2).padStart(2, "0")}${(lastEmployee.value + i).toString().padStart(4, "0")}`, + customerBranchId: customerBranch.id, + }, + }), + ), + ); + const sortedEmployeeId: string[] = []; + + while (body.worker.length > 0) { + const popExist = body.worker.shift(); + if (typeof popExist === "string") sortedEmployeeId.push(popExist); + else { + const popNew = newEmployee.shift(); + popNew && sortedEmployeeId.push(popNew.id); + } + } + + const price = { totalPrice: 0, totalDiscount }; + const restructureService = body.service.flatMap((a) => { + const currentService = service.find((b) => b.id === a.id); + + if (!currentService) return []; // should not possible + + return { + id: currentService.id, + name: currentService.name, + code: currentService.code, + detail: currentService.detail, + work: a.work.flatMap((c) => { + const currentWork = currentService.work.find((d) => d.id === c.id); + + if (!currentWork) return []; // should not possible + + return { + id: currentWork.id, + order: currentWork.order, + name: currentWork.name, + product: c.product.flatMap((e) => { + const currentProduct = product.find((f) => f.id === e.id); + + if (!currentProduct) return []; // should not possible + + return { ...e, pricePerUnit: currentProduct.price }; + }), + }; + }), + }; + }); + + const quotation = await tx.quotation.create({ + data: { + ...rest, + statusOrder: +(rest.status === "INACTIVE"), + code: "", + worker: { + createMany: { + data: sortedEmployeeId.map((v, i) => ({ + no: i, + code: "", + employeeId: v, + })), + }, + }, + service: { + createMany: { + data: body.service.flatMap((a) => { + const src = service.find((b) => b.id == a.id); + return src + ? { + id: a.id, + name: src.name, + code: src.code, + detail: src.detail, + } + : []; // should not be possible to not found. + }), + }, + }, + totalPrice, + totalDiscount, + vatExcluded: 0, + vat: 0, + paySplit: { + createMany: { + data: (rest.paySplit || []).map((v, i) => ({ + no: i + 1, + date: v, + })), + }, + }, + }, + }); + // await tx.quotationServiceWork.createMany({ + // data: service.flatMap((a) => + // a.work.map((b) => ({ id: b.id, order: b.order, name: b.name, serviceId: a.id })), + // ), + // }); + + throw new Error("Test Quotation Structure"); + }); + } @Put("{quotationId}") @Security("keycloak") @@ -205,7 +366,15 @@ export class QuotationController extends Controller { @Request() req: RequestWithUser, @Path() quotationId: string, @Body() body: QuotationUpdate, - ) {} + ) { + const record = await prisma.quotation.findUnique({ + where: { id: quotationId }, + }); + + if (!record) { + throw new HttpError(HttpStatus.NOT_FOUND, "Quotation not found.", "quotationNotFound"); + } + } @Delete("{quotationId}") @Security("keycloak")