Files
sap-erp/routes/oee.js
T
John eead8f5ffd
SAP-ERP Portal CI/CD / build (push) Successful in 3m57s
sale order
2026-10-05 18:45:17 +05:30

131 lines
7.4 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;
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;