diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 8a33a11..7dec423 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -1326,6 +1326,8 @@ model QuotationProductServiceList { serviceId String? service Service? @relation(fields: [serviceId], references: [id]) + attributes Json? + worker QuotationProductServiceWorker[] requestWork RequestWork[] } @@ -1413,7 +1415,10 @@ model RequestData { enum RequestWorkStatus { Pending + Ready + Waiting InProgress + Ended Completed } diff --git a/src/controllers/05-quotation-controller.ts b/src/controllers/05-quotation-controller.ts index 92c35a6..e46812f 100644 --- a/src/controllers/05-quotation-controller.ts +++ b/src/controllers/05-quotation-controller.ts @@ -343,7 +343,12 @@ export class QuotationController extends Controller { tx.employee.findMany({ where: { id: { in: ids.employee } } }), tx.product.findMany({ where: { id: { in: ids.product } } }), ids.work.length ? tx.work.findMany({ where: { id: { in: ids.work } } }) : null, - ids.service.length ? tx.service.findMany({ where: { id: { in: ids.service } } }) : null, + ids.service.length + ? tx.service.findMany({ + include: { work: { include: { productOnWork: true } } }, + where: { id: { in: ids.service } }, + }) + : null, ]), ); @@ -425,6 +430,13 @@ export class QuotationController extends Controller { amount: v.amount, discount: v.discount || 0, installmentNo: v.installmentNo, + attributes: service + ?.find((s) => s.id === v.serviceId) + ?.work.find((w) => w.id === v.workId) + ?.productOnWork.find((p) => p.productId === v.productId)?.attributes as Record< + string, + unknown + >, vat, worker: { create: sortedEmployeeId @@ -590,7 +602,12 @@ export class QuotationController extends Controller { tx.employee.findMany({ where: { id: { in: ids.employee } } }), tx.product.findMany({ where: { id: { in: ids.product } } }), ids.work?.length ? tx.work.findMany({ where: { id: { in: ids.work } } }) : null, - ids.service?.length ? tx.service.findMany({ where: { id: { in: ids.service } } }) : null, + ids.service?.length + ? tx.service.findMany({ + include: { work: { include: { productOnWork: true } } }, + where: { id: { in: ids.service } }, + }) + : null, ]), ); @@ -669,6 +686,13 @@ export class QuotationController extends Controller { discount: v.discount || 0, installmentNo: v.installmentNo, vat, + attributes: service + ?.find((s) => s.id === v.serviceId) + ?.work.find((w) => w.id === v.workId) + ?.productOnWork.find((p) => p.productId === v.productId)?.attributes as Record< + string, + unknown + >, worker: { create: sortedEmployeeId .filter((_, i) => !v.workerIndex || i in v.workerIndex) @@ -804,6 +828,147 @@ export class QuotationController extends Controller { where: { id: quotationId }, }); } + + @Post("{quotationId}/worker") + @Security("keycloak", MANAGE_ROLES) + async addWorker( + @Request() req: RequestWithUser, + @Path() quotationId: string, + @Body() + body: { + workerId: string; + productServiceListId: string[]; + }[], + ) { + return await prisma.$transaction(async (tx) => { + let record = await tx.quotation.findFirst({ + include: { + _count: { + select: { paySplit: true }, + }, + customerBranch: { + include: { + customer: { + include: { + registeredBranch: { include: branchRelationPermInclude(req.user) }, + }, + }, + }, + }, + worker: true, + productServiceList: { + include: { + worker: true, + work: true, + service: true, + product: true, + }, + }, + }, + where: { id: quotationId }, + }); + + if (!record) throw notFoundError("Quotation"); + + let quotation = record; + + const paymentSum = await tx.payment.aggregate({ + _sum: { amount: true }, + where: { + invoice: { + quotationId: quotation.id, + payment: { paymentStatus: "PaymentSuccess" }, + }, + }, + }); + + body = body.filter((a) => !quotation.worker.find((b) => b.employeeId === a.workerId)); + if (!paymentSum._sum.amount) { + return await tx.quotation.update({ + include: { + _count: { + select: { paySplit: true }, + }, + customerBranch: { + include: { + customer: { + include: { + registeredBranch: { include: branchRelationPermInclude(req.user) }, + }, + }, + }, + }, + worker: true, + productServiceList: { + include: { + worker: true, + work: true, + service: true, + product: true, + }, + }, + }, + where: { id: quotationId }, + data: { + worker: { + createMany: { + data: body.map((v, i) => ({ + employeeId: v.workerId, + no: quotation.worker.length + i + 1, + })), + }, + }, + productServiceList: { + update: quotation.productServiceList.map((a) => ({ + where: { id: a.id }, + data: { + worker: { + createMany: { + data: body + .filter((b) => b.productServiceListId.includes(a.id)) + .map((val) => ({ employeeId: val.workerId })), + }, + }, + }, + })), + }, + }, + }); + } + + const current = new Date(); + const year = `${current.getFullYear()}`.slice(-2).padStart(2, "0"); + const month = `${current.getMonth() + 1}`.padStart(2, "0"); + + const lastRequest = await tx.runningNo.upsert({ + where: { + key: `REQUEST_${year}${month}`, + }, + create: { + key: `REQUEST_${year}${month}`, + value: quotation.worker.length, + }, + update: { value: { increment: quotation.worker.length } }, + }); + + await tx.quotation.update({ + where: { id: quotationId }, + data: { + requestData: { + create: body.map((v, i) => ({ + code: `TR${year}${month}${(lastRequest.value - quotation.worker.length + i + 1).toString().padStart(6, "0")}`, + employeeId: v.workerId, + requestWork: { + create: v.productServiceListId + .filter((a) => quotation.productServiceList.find((b) => a === b.id)) + .map((v) => ({ productServiceId: v })), + }, + })), + }, + }, + }); + }); + } } @Route("api/v1/quotation/{quotationId}/attachment")