308 lines
7.9 KiB
TypeScript
308 lines
7.9 KiB
TypeScript
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: [] },
|
|
);
|
|
}
|
|
}
|