import { Credential } from "@/common/types/auth"; import { StockOpnameLocationRes, StockOpnameRequest } from "@/common/types/stockOpname"; import { Team } from "@prisma/client"; import { NextRequest, NextResponse } from "next/server"; import { prisma } from "prisma/client"; type Quantity = { [key in keyof typeof Team]: number | null } const calculateOpnameQuantity = async ( where: { productId: number, companyId: number } ): Promise => { const quantity: Quantity = { COUNT1: null, COUNT2: 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 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 intPage = page ? parseInt(page) : 1; if (!companyId) { return NextResponse.json({ error: 'Bad Request. Missing companyId' }, { status: 400 }) } const where = { AND: { stockOpnames: { some: {} }, companyId: parseInt(companyId), OR: [ { name: { contains: search ?? '' } }, { itemCode: { contains: search ?? '' } }, { barcode: { contains: search ?? '' } }, ] } } const products = await prisma.product.findMany({ skip: (intPage - 1) * PAGE_SIZE, take: PAGE_SIZE, where, select: { id: true, name: true, itemCode: true, barcode: true, onhandQty: true, differenceQty: true, isDifferent: true } }) 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 }) } export async function POST(request: NextRequest) { const credentialStr = request.cookies.get('credential')?.value const credential: Credential | null = credentialStr ? JSON.parse(credentialStr) : null 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 }) } 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, 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() const count2Count = await prisma.stockOpname.count({ where: { companyId, productId, team: 'COUNT2' } }) const isCount2Counted: boolean = count2Count > 0 let isDifferent: boolean = false for (const opname of stockOpnames) { let { COUNT1, COUNT2, VERIFICATION } = opname if (!totalQty['COUNT1'] && COUNT1.quantity) totalQty['COUNT1'] = 0 if (!totalQty['COUNT2'] && COUNT2.quantity) totalQty['COUNT2'] = 0 if (!totalQty['VERIFICATION'] && VERIFICATION.quantity) totalQty['VERIFICATION'] = 0 if (totalQty['COUNT1'] !== null && COUNT1.quantity) totalQty['COUNT1'] += COUNT1.quantity if (totalQty['COUNT2'] !== null && COUNT2.quantity) totalQty['COUNT2'] += COUNT2.quantity if (totalQty['VERIFICATION'] !== null && VERIFICATION.quantity) totalQty['VERIFICATION'] += VERIFICATION.quantity if (isCount2Counted && COUNT1.quantity != COUNT2.quantity) { isDifferent = true } } const product = await prisma.product.findFirst({ where: { id: productId } }) if (!product) return const onhandQty = product?.onhandQty || 0 if (!isDifferent) { if ( (typeof totalQty['VERIFICATION'] === 'number' && totalQty['VERIFICATION'] > 0) || totalQty['COUNT2'] == onhandQty || totalQty['COUNT1'] == onhandQty || totalQty['COUNT1'] == totalQty['COUNT2'] ) { isDifferent = false } else { isDifferent = true } if (isCount2Counted && totalQty['COUNT1'] != onhandQty) { isDifferent = true } } await prisma.product.update({ where: { id: product.id }, data: { isDifferent } }) }