'use strict'; // routes/oee.js — "Overall Equipment Efficiency" (OEE) module. CRUD over the // portal app-DB table ZOEE_ENTRIES (services/oeeStore.js). One document per // (tab, month). Gated by the generic Approval Step 'oee:entry' (view/add/edit) // and, additionally, by per-user allowed tabs (Admin → user → OEE) — mirrors // the Man Power module. 'edit' also gates Cancel. const express = require('express'); const router = express.Router(); const { verifyToken, requireApprovalStep } = require('../middleware/auth'); const store = require('../services/oeeStore'); // Tab catalogue (key → label). Only 'ebb' has a defined column format so far; // the rest are placeholders until their sheets are provided. The full column // schema + formulas live on the client (public/oee.html) — the server only // needs the keys/labels to expose the tab list and validate the tab field. const TABS = [ { key: 'ebb', label: 'EBB Production', ready: true }, { key: 'pd', label: 'PD Production', ready: true }, { key: 'needle', label: 'PDS Needle Assembly', ready: false }, { key: 'autoclave', label: 'Autoclave', ready: true }, { key: 'packing', label: 'Packing', ready: false }, { key: 'moulding', label: 'Moulding', ready: true }, { key: 'sheet', label: 'Plastic Sheet Plant', ready: true }, ]; const TAB_KEYS = new Set(TABS.map(t => t.key)); const cq = (req) => req.query?.company || req.body?.company || null; // This user's allowed OEE tabs (Admin → user → OEE). Returns an array, or null // = no restriction (all tabs). Read fresh from DB, like Man Power. async function allowedTabsFor(userId) { try { const u = await require('../services/hanaUsers').findById(userId); const t = Array.isArray(u && u.oeeTabs) ? u.oeeTabs.map(String) : []; return t.length ? t : null; } catch (_e) { return null; } } // Expose tab metadata so the frontend renders the right tabs/labels. router.get('/tabs', verifyToken, (req, res) => { res.json({ success: true, data: TABS.map(t => ({ key: t.key, label: t.label, ready: t.ready })) }); }); // ── List (view) ─────────────────────────────────────────────────── router.get('/', verifyToken, requireApprovalStep('oee:entry', 'view'), async (req, res) => { try { const allow = await allowedTabsFor(req.user.id); const top = Math.min(Number(req.query.top) || 30, 100); const skip = Number(req.query.skip) || 0; const tab = (req.query.tab || '').trim() || null; const month = (req.query.month || '').trim() || null; const monthFrom = (req.query.monthFrom || '').trim() || null; const monthTo = (req.query.monthTo || '').trim() || null; // If a specific tab was requested but the user isn't allowed it, return none. if (tab && allow && !allow.includes(tab)) return res.json({ success: true, data: [] }); const { data, total } = await store.list({ company: cq(req), tab, month, monthFrom, monthTo, allowTabs: allow, top, skip }); res.json({ success: true, data, total }); } catch (err) { res.status(500).json({ success: false, message: err.message }); } }); // ── Single document (view) ──────────────────────────────────────── router.get('/:id', verifyToken, requireApprovalStep('oee:entry', 'view'), async (req, res) => { try { const doc = await store.getById(req.params.id); if (!doc) return res.status(404).json({ success: false, message: 'Not found' }); const allow = await allowedTabsFor(req.user.id); if (allow && !allow.includes(doc.tab)) return res.status(403).json({ success: false, message: 'You are not permitted this OEE form.' }); res.json({ success: true, data: doc }); } catch (err) { res.status(404).json({ success: false, message: err.message }); } }); function validateBody(body) { const tab = (body.tab || '').trim(); const month = (body.month || '').trim(); if (!TAB_KEYS.has(tab)) throw new Error('Unknown or missing OEE form.'); if (!month) throw new Error('Month is required.'); const rows = Array.isArray(body.rows) ? body.rows : []; // Keep only rows that actually carry data (a date or any non-empty value). const used = rows.filter(r => r && Object.keys(r).some(k => { const v = r[k]; if (typeof v === 'number') return v !== 0; return v != null && String(v).trim() !== ''; })); // Every used row must carry a Date. used.forEach((r, i) => { if (!(r.date || '').toString().trim()) throw new Error(`Date is required — row ${i + 1}`); }); if (!used.length) throw new Error('Add at least one row with a Date before saving.'); return { tab, month, rows: used }; } // ── Create (add) ────────────────────────────────────────────────── router.post('/', verifyToken, requireApprovalStep('oee:entry', 'add'), async (req, res) => { try { const { tab, month, rows } = validateBody(req.body); const allow = await allowedTabsFor(req.user.id); if (allow && !allow.includes(tab)) return res.status(403).json({ success: false, message: 'You are not permitted this OEE form.' }); const id = await store.create({ company: cq(req), tab, month, rows, remark: req.body.remark, createdBy: req.user.username || null, createdById: req.user.id || null, }); res.json({ success: true, data: { id } }); } catch (err) { res.status(400).json({ success: false, message: err.message }); } }); // ── Update (edit) ───────────────────────────────────────────────── router.patch('/:id', verifyToken, requireApprovalStep('oee:entry', 'edit'), async (req, res) => { try { const existing = await store.getById(req.params.id); if (!existing) return res.status(404).json({ success: false, message: 'Not found' }); if (existing.canceled) return res.status(400).json({ success: false, message: 'This document is cancelled.' }); const allow = await allowedTabsFor(req.user.id); if (allow && !allow.includes(existing.tab)) return res.status(403).json({ success: false, message: 'You are not permitted this OEE form.' }); // Tab is fixed for a document; only month/rows/remark change. const { month, rows } = validateBody({ ...req.body, tab: existing.tab }); await store.update(req.params.id, { month, rows, remark: req.body.remark }); res.json({ success: true }); } catch (err) { res.status(400).json({ success: false, message: err.message }); } }); // ── Cancel (soft) ───────────────────────────────────────────────── router.post('/:id/cancel', verifyToken, requireApprovalStep('oee:entry', 'edit'), async (req, res) => { try { const existing = await store.getById(req.params.id); if (!existing) return res.status(404).json({ success: false, message: 'Not found' }); const allow = await allowedTabsFor(req.user.id); if (allow && !allow.includes(existing.tab)) return res.status(403).json({ success: false, message: 'You are not permitted this OEE form.' }); await store.cancel(req.params.id); res.json({ success: true }); } catch (err) { res.status(400).json({ success: false, message: err.message }); } }); module.exports = router;