// FILE: src/routes/contracts.js // ไม่มี contract.* ใน seed → map เป็นงานดูแลองค์กร/โปรเจ็กต์: // list/get → projects.view (ORG) // create/update/delete → projects.manage (ORG) import { Router } from "express"; import sql from "../db/index.js"; import { requirePerm } from "../middleware/requirePerm.js"; const r = Router(); // LIST r.get( "/", requirePerm("projects.view", { orgParam: "org_id" }), async (req, res) => { const { project_id, org_id, contract_no, q, limit = 50, offset = 0, } = req.query; const p = req.principal; const params = []; const cond = []; if (!p.is_superadmin) { if (org_id) { if (!p.inOrg(Number(org_id))) return res.status(403).json({ error: "FORBIDDEN_ORG" }); cond.push("c.org_id=?"); params.push(Number(org_id)); } else if (p.org_ids?.length) { cond.push(`c.org_id IN (${p.org_ids.map(() => "?").join(",")})`); params.push(...p.org_ids); } } else if (org_id) { cond.push("c.org_id=?"); params.push(Number(org_id)); } if (project_id) { cond.push("c.project_id=?"); params.push(Number(project_id)); } if (contract_no) { cond.push("c.contract_no=?"); params.push(contract_no); } if (q) { cond.push("(c.contract_no LIKE ? OR c.title LIKE ?)"); params.push(`%${q}%`, `%${q}%`); } const where = cond.length ? `WHERE ${cond.join(" AND ")}` : ""; const [rows] = await sql.query( `SELECT c.* FROM contracts c ${where} ORDER BY c.id DESC LIMIT ? OFFSET ?`, [...params, Number(limit), Number(offset)] ); res.json(rows); } ); // GET r.get( "/:id", requirePerm("projects.view", { orgParam: "org_id" }), async (req, res) => { const id = Number(req.params.id); const [[row]] = await sql.query("SELECT * FROM contracts WHERE id=?", [id]); if (!row) return res.status(404).json({ error: "Not found" }); const p = req.principal; if (!p.is_superadmin && !p.inOrg(row.org_id)) return res.status(403).json({ error: "FORBIDDEN_ORG" }); res.json(row); } ); // CREATE r.post( "/", requirePerm("projects.manage", { orgParam: "org_id" }), async (req, res) => { const { org_id, project_id, contract_no, title, status } = req.body || {}; if (!org_id || !project_id || !contract_no) return res .status(400) .json({ error: "org_id, project_id, contract_no required" }); const [rs] = await sql.query( `INSERT INTO contracts (org_id, project_id, contract_no, title, status, created_by) VALUES (?,?,?,?,?,?)`, [ org_id, project_id, contract_no, title || null, status || null, req.principal.user_id, ] ); res.json({ id: rs.insertId }); } ); // UPDATE r.put( "/:id", requirePerm("projects.manage", { orgParam: "org_id" }), async (req, res) => { const id = Number(req.params.id); const [[row]] = await sql.query("SELECT * FROM contracts WHERE id=?", [id]); if (!row) return res.status(404).json({ error: "Not found" }); const p = req.principal; if (!p.is_superadmin && !p.inOrg(row.org_id)) return res.status(403).json({ error: "FORBIDDEN_ORG" }); const { title, status } = req.body || {}; await sql.query("UPDATE contracts SET title=?, status=? WHERE id=?", [ title ?? row.title, status ?? row.status, id, ]); res.json({ ok: 1 }); } ); // DELETE r.delete( "/:id", requirePerm("projects.manage", { orgParam: "org_id" }), async (req, res) => { const id = Number(req.params.id); const [[row]] = await sql.query("SELECT * FROM contracts WHERE id=?", [id]); if (!row) return res.status(404).json({ error: "Not found" }); const p = req.principal; if (!p.is_superadmin && !p.inOrg(row.org_id)) return res.status(403).json({ error: "FORBIDDEN_ORG" }); await sql.query("DELETE FROM contracts WHERE id=?", [id]); res.json({ ok: 1 }); } ); export default r;