Repository Public
1// Vrai-Prix — méthode du coût : catalogue des assemblages avec coût unitaire décomposé (localisation au choix).2import { NextRequest, NextResponse } from "next/server";3import { buildContext } from "@/lib/cost/catalog";4import { assemblyUnitCost } from "@/lib/cost/engine";5import { cached } from "@/lib/cost/cache";67export const runtime = "nodejs";89export function GET(req: NextRequest) {10 const loc = req.nextUrl.searchParams.get("location") ?? "QC-MTL";11 const q = (req.nextUrl.searchParams.get("q") ?? "").trim().toLowerCase();12 const cat = req.nextUrl.searchParams.get("category");13 try {14 const data = cached(`assemblies:${loc}`, 10 * 60_000, () => {15 const ctx = buildContext({ locationCode: loc });16 const f = ctx.location;17 return {18 asOf: ctx.asOf, location: f,19 assemblies: [...ctx.assemblies.values()].map((a) => {20 const u = assemblyUnitCost(a, ctx);21 return { code: a.code, nameFr: a.nameFr, nameEn: a.nameEn, descriptionFr: a.descriptionFr, descriptionEn: a.descriptionEn, unit: a.unit, category: a.category, masterformat: a.masterformat, quality: a.quality, economicLife: a.economicLife, conditionGroup: a.conditionGroup,22 material: u.material, labour: u.labour, equipment: u.equipment, direct: u.direct,23 adjusted: Math.round(100 * (u.material * f.materialFactor + u.labour * f.labourFactor + u.equipment * f.equipmentFactor)) / 100,24 sigmaPct: Math.round(u.sigmaPct * 1000) / 1000, observedShare: Math.round(u.observedShare * 100) / 100, freshestObservation: u.freshestObservation, components: a.components.length };25 }),26 };27 });28 const fold = (s: string) => s.normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase();29 let list = data.assemblies;30 if (q) list = list.filter((a) => fold(a.nameFr).includes(fold(q)) || fold(a.nameEn).includes(fold(q)) || a.code.toLowerCase().includes(q));31 if (cat) list = list.filter((a) => a.category === cat);32 return NextResponse.json({ asOf: data.asOf, location: data.location, count: list.length, assemblies: list });33 } catch (e) {34 return NextResponse.json({ error: (e as Error).message }, { status: 500 });35 }36}37