IcostPro/app/api/ingredients/route.ts
2026-02-11 21:36:58 +01:00

143 lines
3.9 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server';
import { ObjectId } from 'mongodb';
import { getDb } from '@/lib/mongodb';
export async function GET(request: NextRequest) {
const { searchParams } = request.nextUrl;
const page = Math.max(1, parseInt(searchParams.get('page') || '1'));
const limit = Math.min(100, Math.max(1, parseInt(searchParams.get('limit') || '10')));
const search = searchParams.get('search') || '';
const categoryId = searchParams.get('categoryId');
const subcategoryId = searchParams.get('subcategoryId');
const db = await getDb();
const matchStage: Record<string, unknown> = {};
if (categoryId) {
matchStage.categoryId = new ObjectId(categoryId);
}
if (subcategoryId) {
matchStage.subcategoryId = new ObjectId(subcategoryId);
}
if (search) {
matchStage.$or = [
{ name: { $regex: search, $options: 'i' } },
{ code: { $regex: search, $options: 'i' } },
];
}
const pipeline = [
{ $match: matchStage },
{
$lookup: {
from: 'categories',
localField: 'categoryId',
foreignField: '_id',
as: 'categoryDoc',
},
},
{
$lookup: {
from: 'subcategories',
localField: 'subcategoryId',
foreignField: '_id',
as: 'subcategoryDoc',
},
},
{
$lookup: {
from: 'suppliers',
localField: 'supplierId',
foreignField: '_id',
as: 'supplierDoc',
},
},
{
$project: {
code: 1,
name: 1,
category: { $arrayElemAt: ['$categoryDoc.name', 0] },
subcategory: { $arrayElemAt: ['$subcategoryDoc.name', 0] },
quantity: 1,
unit: 1,
unitPrice: 1,
vat: 1,
supplier: { $arrayElemAt: ['$supplierDoc.name', 0] },
createdAt: 1,
updatedAt: 1,
},
},
{ $sort: { createdAt: -1 as const } },
];
const [data, countResult] = await Promise.all([
db.collection('ingredients')
.aggregate(pipeline)
.skip((page - 1) * limit)
.limit(limit)
.toArray(),
db.collection('ingredients')
.countDocuments(matchStage),
]);
return NextResponse.json({
data,
total: countResult,
page,
limit,
});
}
export async function POST(request: Request) {
const body = await request.json();
const { name, categoryId, subcategoryId, quantity, unit, unitPrice, vat, supplierId } = body;
if (!name || !categoryId || !subcategoryId || !quantity || !unit || unitPrice == null || vat == null || !supplierId) {
return NextResponse.json({ error: 'All fields are required' }, { status: 400 });
}
const db = await getDb();
// Auto-generate code
const last = await db.collection('ingredients')
.find({}, { projection: { code: 1 } })
.sort({ code: -1 })
.limit(1)
.next();
const lastNum = last?.code ? parseInt(last.code.replace('ING-', '')) : 0;
const code = `ING-${String(lastNum + 1).padStart(3, '0')}`;
const now = new Date();
const doc: Record<string, unknown> = {
code,
name,
categoryId: new ObjectId(categoryId),
subcategoryId: new ObjectId(subcategoryId),
quantity,
unit,
unitPrice,
vat,
supplierId: new ObjectId(supplierId),
createdAt: now,
updatedAt: now,
};
// Optional discount fields
if (body.discountType) {
doc.discountType = body.discountType;
doc.discountValue = body.discountValue ?? 0;
doc.applyDiscountToNet = body.applyDiscountToNet ?? false;
}
// Optional advanced fields
if (body.minStockLevel != null) doc.minStockLevel = body.minStockLevel;
if (body.storageInstructions) doc.storageInstructions = body.storageInstructions;
if (body.shelfLifeDays != null) doc.shelfLifeDays = body.shelfLifeDays;
if (body.notes) doc.notes = body.notes;
const result = await db.collection('ingredients').insertOne(doc);
return NextResponse.json({ _id: result.insertedId, ...doc }, { status: 201 });
}