From c004c516c6590b7e71a94e896d3e58ce5b91a7e3 Mon Sep 17 00:00:00 2001 From: Methapon2001 <61303214+Methapon2001@users.noreply.github.com> Date: Tue, 4 Mar 2025 11:27:15 +0700 Subject: [PATCH] feat: stats endpoints --- src/controllers/00-stats-controller.ts | 187 +++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 src/controllers/00-stats-controller.ts diff --git a/src/controllers/00-stats-controller.ts b/src/controllers/00-stats-controller.ts new file mode 100644 index 0000000..a12d7a1 --- /dev/null +++ b/src/controllers/00-stats-controller.ts @@ -0,0 +1,187 @@ +import { QuotationStatus, RequestWorkStatus } from "@prisma/client"; +import { Controller, Get, Query, Request, Route, Security } from "tsoa"; +import prisma from "../db"; +import { createPermCondition } from "../services/permission"; +import { RequestWithUser } from "../interfaces/user"; +import { PaymentStatus } from "../generated/kysely/types"; + +const permissionCondCompany = createPermCondition((_) => true); + +@Route("/api/v1/report") +@Security("keycloak") +export class StatsController extends Controller { + @Get("quotation") + async quotationReport( + @Request() req: RequestWithUser, + @Query() limit?: number, + @Query() startDate?: Date, + @Query() endDate?: Date, + ) { + const record = await prisma.quotation.findMany({ + select: { + code: true, + quotationStatus: true, + createdAt: true, + updatedAt: true, + }, + where: { + registeredBranch: { OR: permissionCondCompany(req.user) }, + createdAt: { gte: startDate, lte: endDate }, + }, + take: limit, + }); + + return record.map((v) => ({ + document: "quotation", + code: v.code, + status: v.quotationStatus, + createdAt: v.createdAt, + updatedAt: v.updatedAt, + })); + } + + @Get("invoice") + async invoiceReport( + @Request() req: RequestWithUser, + @Query() limit?: number, + @Query() startDate?: Date, + @Query() endDate?: Date, + ) { + const record = await prisma.invoice.findMany({ + select: { + code: true, + payment: { + select: { + paymentStatus: true, + }, + }, + createdAt: true, + }, + where: { + quotation: { + isDebitNote: false, + registeredBranch: { OR: permissionCondCompany(req.user) }, + }, + createdAt: { gte: startDate, lte: endDate }, + }, + take: limit, + }); + + return record.map((v) => ({ + document: "invoice", + code: v.code, + status: v.payment?.paymentStatus, + createdAt: v.createdAt, + })); + } + + @Get("receipt") + async receiptReport( + @Request() req: RequestWithUser, + @Query() limit?: number, + @Query() startDate?: Date, + @Query() endDate?: Date, + ) { + const record = await prisma.payment.findMany({ + select: { + code: true, + paymentStatus: true, + createdAt: true, + }, + where: { + paymentStatus: PaymentStatus.PaymentSuccess, + invoice: { + quotation: { + isDebitNote: false, + registeredBranch: { OR: permissionCondCompany(req.user) }, + }, + }, + createdAt: { gte: startDate, lte: endDate }, + }, + take: limit, + }); + + return record.map((v) => ({ + document: "receipt", + code: v.code, + status: v.paymentStatus, + createdAt: v.createdAt, + })); + } + + @Get("product") + async productReport( + @Request() req: RequestWithUser, + @Query() limit?: number, + @Query() startDate?: Date, + @Query() endDate?: Date, + ) { + const record = await prisma.product.findMany({ + select: { + id: true, + code: true, + name: true, + createdAt: true, + updatedAt: true, + _count: { + select: { + quotationProductServiceList: { + where: { + quotation: { + quotationStatus: { + in: [ + QuotationStatus.PaymentInProcess, + QuotationStatus.PaymentSuccess, + QuotationStatus.ProcessComplete, + ], + }, + }, + }, + }, + }, + }, + }, + where: { + quotationProductServiceList: { some: {} }, + productGroup: { registeredBranch: { OR: permissionCondCompany(req.user) } }, + createdAt: { gte: startDate, lte: endDate }, + }, + take: limit, + }); + + const doing = await prisma.quotationProductServiceList.groupBy({ + _count: true, + by: "productId", + where: { + productId: { in: record.map((v) => v.id) }, + requestWork: { + some: { + stepStatus: { + some: { + workStatus: { + in: [ + RequestWorkStatus.Pending, + RequestWorkStatus.InProgress, + RequestWorkStatus.Validate, + RequestWorkStatus.Completed, + RequestWorkStatus.Ended, + ], + }, + }, + }, + }, + }, + }, + }); + + return record.map((v) => ({ + document: "product", + code: v.code, + name: v.name, + sale: v._count.quotationProductServiceList, + did: doing.find((item) => item.productId === v.id)?._count || 0, + createdAt: v.createdAt, + updatedAt: v.updatedAt, + })); + } +}