import { Customer, CustomerBranch, ProductGroup, QuotationStatus, RequestWorkStatus, User, } 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 }, }, orderBy: { createdAt: "desc" }, 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 }, }, orderBy: { createdAt: "desc" }, 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 }, }, orderBy: { createdAt: "desc" }, 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({ include: { quotationProductServiceList: { include: { quotation: true, }, }, }, 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: { quotation: { createdAt: { gte: startDate, lte: endDate } }, }, }, productGroup: { registeredBranch: { OR: permissionCondCompany(req.user) } }, }, orderBy: { quotationProductServiceList: { _count: "desc" }, }, take: limit, }); const doing = await prisma.quotationProductServiceList.groupBy({ _count: true, by: "productId", where: { quotation: { createdAt: { gte: startDate, lte: endDate }, registeredBranch: { OR: permissionCondCompany(req.user) }, }, productId: { in: record.map((v) => v.id) }, requestWork: { some: { stepStatus: { some: { workStatus: { in: [ RequestWorkStatus.Pending, RequestWorkStatus.InProgress, RequestWorkStatus.Validate, RequestWorkStatus.Completed, RequestWorkStatus.Ended, ], }, }, }, }, }, }, }); const order = await prisma.quotationProductServiceList.groupBy({ _count: true, by: "productId", where: { quotation: { createdAt: { gte: startDate, lte: endDate }, registeredBranch: { OR: permissionCondCompany(req.user) }, }, productId: { in: record.map((v) => v.id) }, }, }); 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, order: order.find((item) => item.productId === v.id)?._count || 0, createdAt: v.createdAt, updatedAt: v.updatedAt, })); } @Get("sale") async saleReport( @Request() req: RequestWithUser, @Query() limit?: number, @Query() startDate?: Date, @Query() endDate?: Date, ) { const list = await prisma.quotationProductServiceList.findMany({ include: { quotation: { include: { createdBy: true, customerBranch: { include: { customer: true }, }, }, }, product: { include: { productGroup: true, }, }, }, where: { quotation: { isDebitNote: false, registeredBranch: { OR: permissionCondCompany(req.user) }, createdAt: { gte: startDate, lte: endDate }, quotationStatus: { in: [ QuotationStatus.PaymentInProcess, QuotationStatus.PaymentSuccess, QuotationStatus.ProcessComplete, ], }, }, }, take: limit, }); return list.reduce<{ byProductGroup: (ProductGroup & { _count: number })[]; bySale: (User & { _count: number })[]; byCustomer: ((CustomerBranch & { customer: Customer }) & { _count: number })[]; }>( (a, c) => { { const found = a.byProductGroup.find((v) => v.id === c.product.productGroupId); if (found) { found._count++; } else { a.byProductGroup.push({ ...c.product.productGroup, _count: 1 }); } } { const found = a.bySale.find((v) => v.id === c.quotation.createdByUserId); if (found) { found._count++; } else { if (c.quotation.createdBy) { a.bySale.push({ ...c.quotation.createdBy, _count: 1 }); } } } { const found = a.byCustomer.find((v) => v.id === c.quotation.customerBranchId); if (found) { found._count++; } else { a.byCustomer.push({ ...c.quotation.customerBranch, _count: 1 }); } } return a; }, { byProductGroup: [], bySale: [], byCustomer: [] }, ); } }