import { StockOpnameLocationRes, StockOpnameRequest } from "@/common/types/stockOpname"; import { Prisma, Team } from "prisma/generated/client"; import { NextRequest, NextResponse } from "next/server"; import { prisma } from "prisma/client"; import _ from "lodash" import getServerCredential from "@/common/libs/getServerCredential"; type Quantity = { [key in keyof typeof Team]: number | null } export async function GET(request: NextRequest) { const PAGE_SIZE = 30; const params = request.nextUrl.searchParams const companyId = params.get('companyId') const search = params.get('search') const page = params.get('page') ?? null const show = params.get('show') const intPage = page ? parseInt(page) : 1 if (!companyId) { return NextResponse.json({ error: 'Bad Request. Missing companyId' }, { status: 400 }) } const where: Prisma.ProductWhereInput = { AND: { stockOpnames: { some: {} }, companyId: parseInt(companyId), isDifferent: show ? (show == 'diff' ? true : false) : undefined, OR: [ { name: { mode: 'insensitive', contains: search ?? '' } }, { itemCode: { mode: 'insensitive', contains: search ?? '' } }, { barcode: { mode: 'insensitive', contains: search ?? '' } }, { stockOpnames: { some: { location: { name: { mode: 'insensitive', contains: search ?? '' } } } } }, ] } } const products = await prisma.product.findMany({ skip: (intPage - 1) * PAGE_SIZE, take: PAGE_SIZE, where }) const productCount = await prisma.product.count({ where }) const pagination = { page: intPage, totalPage: Math.ceil(productCount / PAGE_SIZE), } type ProductWithSum = typeof products[0] & { quantity: Quantity } const productsWithSum: ProductWithSum[] = [] for (const product of products) { const quantity = await calculateOpnameQuantity({ productId: product.id, companyId: parseInt(companyId) }) productsWithSum.push({ ...product, quantity }) } return NextResponse.json({ result: productsWithSum, ...pagination }) } const calculateOpnameQuantity = async ( where: { productId: number, companyId: number } ): Promise => { const quantity: Quantity = { COUNT1: null, COUNT2: null, COUNT3: null, VERIFICATION: null } for (const team of Object.values(Team)) { const opnameQty = await prisma.stockOpname.groupBy({ by: ['productId', 'team'], _sum: { quantity: true }, where: { team, ...where } }) if (opnameQty.length === 0) continue quantity[team] = opnameQty[0]._sum.quantity } return quantity } export async function POST(request: NextRequest) { const credential = getServerCredential() if (!credential) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) const body: StockOpnameRequest = await request.json() const { companyId, team } = credential const query = { locationId: body.location, productId: body.product, companyId, team } const stockOpname = await prisma.stockOpname.findFirst({ where: query }) const data = { ...query, userId: credential.id, quantity: body.quantity, isDifferent: false } let newStockOpname = null if (!stockOpname) { newStockOpname = await prisma.stockOpname.create({ data }) } else { newStockOpname = await prisma.stockOpname.update({ where: { id: stockOpname.id }, data }) } await computeIsDifferent({ productId: body.product, companyId: companyId }) return NextResponse.json(newStockOpname) } const SELF_HOST = process.env.SELF_HOST as string const computeIsDifferent = async ({ companyId, productId }: { companyId: number, productId: number }) => { const totalQty: { [key in keyof typeof Team]: number | null } = { COUNT1: null, COUNT2: null, COUNT3: null, VERIFICATION: null } const searchParams = new URLSearchParams({ companyId: companyId.toString(), productId: productId.toString() }) const stockOpnamesFetch = await fetch(`${SELF_HOST}/api/stock-opname/location?${searchParams}`) const stockOpnames: StockOpnameLocationRes[] = await stockOpnamesFetch.json() let isDifferent: boolean = false let verificationCounter: number = 0 for (const opname of stockOpnames) { let { COUNT1, COUNT2, COUNT3, VERIFICATION } = opname if (totalQty['COUNT1'] === null && _.isNumber(COUNT1.quantity)) totalQty['COUNT1'] = 0 if (totalQty['COUNT2'] === null && _.isNumber(COUNT2.quantity)) totalQty['COUNT2'] = 0 if (totalQty['COUNT3'] === null && _.isNumber(COUNT3.quantity)) totalQty['COUNT3'] = 0 if (totalQty['VERIFICATION'] === null && _.isNumber(VERIFICATION.quantity)) totalQty['VERIFICATION'] = 0 if (_.isNumber(totalQty['COUNT1']) && _.isNumber(COUNT1.quantity)) totalQty['COUNT1'] += COUNT1.quantity if (_.isNumber(totalQty['COUNT2']) && _.isNumber(COUNT2.quantity)) totalQty['COUNT2'] += COUNT2.quantity if (_.isNumber(totalQty['COUNT3']) && _.isNumber(COUNT3.quantity)) totalQty['COUNT3'] += COUNT3.quantity if (_.isNumber(totalQty['VERIFICATION']) && _.isNumber(VERIFICATION.quantity)) totalQty['VERIFICATION'] += VERIFICATION.quantity if (_.isNumber(COUNT1.quantity) && _.isNumber(COUNT2.quantity) && COUNT1.quantity !== COUNT2.quantity) isDifferent = true if (_.isNumber(COUNT1.quantity) && _.isNumber(COUNT3.quantity) && COUNT1.quantity !== COUNT3.quantity) isDifferent = true if (_.isNumber(COUNT2.quantity) && _.isNumber(COUNT3.quantity) && COUNT2.quantity !== COUNT3.quantity) isDifferent = true if (_.isNumber(VERIFICATION.quantity)) verificationCounter++ } const product = await prisma.product.findFirst({ where: { id: productId } }) if (!product) return const onhandQty = product.onhandQty const differenceQty = product.differenceQty const allQty = onhandQty + differenceQty if (!isDifferent) { const conditional = { verificationCheckAll: verificationCounter > 0 && verificationCounter === stockOpnames.length, anyCountEqWithOnhand: [totalQty['COUNT1'], totalQty['COUNT2'], totalQty['COUNT3']].includes(onhandQty), anyCountEqWithAllQty: [totalQty['COUNT1'], totalQty['COUNT2'], totalQty['COUNT3']].includes(allQty), count1EqWithCount2: totalQty['COUNT1'] !== null && totalQty['COUNT2'] !== null && totalQty['COUNT1'] === totalQty['COUNT2'], count1EqWithCount3: totalQty['COUNT1'] !== null && totalQty['COUNT3'] !== null && totalQty['COUNT1'] === totalQty['COUNT3'], count2EqWithCount3: totalQty['COUNT2'] !== null && totalQty['COUNT3'] !== null && totalQty['COUNT2'] === totalQty['COUNT3'], } isDifferent = !( conditional.verificationCheckAll || conditional.anyCountEqWithOnhand || conditional.anyCountEqWithAllQty || conditional.count1EqWithCount2 || conditional.count1EqWithCount3 || conditional.count2EqWithCount3 ) } await prisma.product.update({ where: { id: product.id }, data: { isDifferent } }) }