129 lines
7.3 KiB
JavaScript
129 lines
7.3 KiB
JavaScript
'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;
|
|
// 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 = await store.list({ company: cq(req), tab, month, allowTabs: allow, top, skip });
|
|
res.json({ success: true, data });
|
|
} 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;
|