// routes/productionPlanning.js // Daily Production Planning — plain CRUD list gated by a single approval // step (production_planning:entry), same pattern as Man Power/OEE. See // services/productionPlanningStore.js for the data layer. 'use strict'; const express = require('express'); const router = express.Router(); const { verifyToken, requireApprovalStep, requireWorkflowPerm, hasStepAssigned } = require('../middleware/auth'); const store = () => require('../services/productionPlanningStore'); const defaultsStore = () => require('../services/productionPlanningItemDefaultsStore'); // Item-code-wise master defaults (No. of Package / Per Cycle Qty / // No. of Cycle/Day / Product Type) — viewable by anyone who can view EITHER // step of the module (entry or approve — an approver-only user still needs // to see these to review a plan), editable only by those who can edit plans. router.get('/item-defaults', verifyToken, requireWorkflowPerm('production_planning', 'view'), async (req, res) => { try { const data = await defaultsStore().listDefaults(); res.json({ success: true, data }); } catch (err) { res.status(500).json({ success: false, message: err.message }); } }); router.get('/item-defaults/:itemCode', verifyToken, requireWorkflowPerm('production_planning', 'view'), async (req, res) => { try { const data = await defaultsStore().findByItemCode(req.params.itemCode); res.json({ success: true, data }); } catch (err) { res.status(500).json({ success: false, message: err.message }); } }); router.post('/item-defaults', verifyToken, requireApprovalStep('production_planning:entry', 'edit'), async (req, res) => { try { const b = req.body || {}; const saved = await defaultsStore().upsertDefault({ itemCode: b.itemCode, itemName: b.itemName, noOfPackage: b.noOfPackage, perCycleQty: b.perCycleQty, noOfCycleDay: b.noOfCycleDay, productType: b.productType, }, { by: req.user.username, byName: req.user.name || req.user.username }); res.json({ success: true, data: saved }); } catch (err) { res.status(400).json({ success: false, message: err.message }); } }); router.delete('/item-defaults/:id', verifyToken, requireApprovalStep('production_planning:entry', 'edit'), async (req, res) => { try { await defaultsStore().softDeleteDefault(req.params.id); res.json({ success: true }); } catch (err) { res.status(500).json({ success: false, message: err.message }); } }); router.get('/', verifyToken, requireWorkflowPerm('production_planning', 'view'), async (req, res) => { try { const data = await store().listPlans({ company: req.query.company, from: req.query.from, to: req.query.to, status: req.query.status, productType: req.query.productType, market: req.query.market, q: req.query.q }); res.json({ success: true, data }); } catch (err) { res.status(500).json({ success: false, message: err.message }); } }); router.post('/', verifyToken, requireApprovalStep('production_planning:entry', 'add'), async (req, res) => { try { const b = req.body || {}; const saved = await store().createPlan({ planDate: b.planDate, productName: b.productName, productType: b.productType, market: b.market, noOfPackage: b.noOfPackage, quantity: b.quantity, perCycleQty: b.perCycleQty, noOfCycleDay: b.noOfCycleDay, status: b.status, batchNo: b.batchNo, company: b.company, createdBy: req.user.username, createdByName: req.user.name || req.user.username, }); res.json({ success: true, data: saved }); } catch (err) { res.status(400).json({ success: false, message: err.message }); } }); router.put('/:id', verifyToken, requireApprovalStep('production_planning:entry', 'edit'), async (req, res) => { try { const saved = await store().updatePlan(req.params.id, req.body || {}, { by: req.user.username, byName: req.user.name || req.user.username }); res.json({ success: true, data: saved }); } catch (err) { res.status(400).json({ success: false, message: err.message }); } }); router.delete('/:id', verifyToken, requireApprovalStep('production_planning:entry', 'delete'), async (req, res) => { try { await store().softDeletePlan(req.params.id); res.json({ success: true }); } catch (err) { res.status(500).json({ success: false, message: err.message }); } }); router.put('/:id/status', verifyToken, requireApprovalStep('production_planning:entry', 'edit'), async (req, res) => { try { const saved = await store().updateStatus(req.params.id, (req.body || {}).status, { by: req.user.username, byName: req.user.name || req.user.username }); res.json({ success: true, data: saved }); } catch (err) { res.status(400).json({ success: false, message: err.message }); } }); router.put('/:id/approve', verifyToken, requireApprovalStep('production_planning:approve', 'approve'), async (req, res) => { try { const saved = await store().approvePlan(req.params.id, { by: req.user.username, byName: req.user.name || req.user.username }); res.json({ success: true, data: saved }); } catch (err) { res.status(400).json({ success: false, message: err.message }); } }); router.put('/:id/reject', verifyToken, requireApprovalStep('production_planning:approve', 'approve'), async (req, res) => { try { const saved = await store().rejectPlan(req.params.id, (req.body || {}).reason, { by: req.user.username, byName: req.user.name || req.user.username }); res.json({ success: true, data: saved }); } catch (err) { res.status(400).json({ success: false, message: err.message }); } }); module.exports = router;