+36
-6
@@ -1,11 +1,13 @@
|
||||
'use strict';
|
||||
// routes/notifications.js — aggregates "pending on me" items across the
|
||||
// workflows that already have clear, per-user pending logic (Work Order,
|
||||
// Production Order, BOM Requests, and — admin only — Password Reset
|
||||
// requests), for the sidebar bell + dashboard "Pending Actions" widget.
|
||||
// Deliberately scoped to these four for now; other approval workflows
|
||||
// (Purchase Requests, Customer/Vendor registration, Project approvals,
|
||||
// etc.) aren't included yet.
|
||||
// Production Order, Batch Issuance, BOM Requests, Production Deviations,
|
||||
// and — admin only — Password Reset requests), for the sidebar bell +
|
||||
// dashboard "Pending Actions" widget. Every item is gated by the same
|
||||
// approval-step/role check its own workflow route enforces, so a user only
|
||||
// ever sees what they're actually permitted to act on. Other approval
|
||||
// workflows (Purchase Requests, Customer/Vendor registration, Project
|
||||
// approvals, etc.) aren't included yet.
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { verifyToken, hasStepPerm, hasStepAssigned } = require('../middleware/auth');
|
||||
@@ -56,13 +58,24 @@ router.get('/pending', verifyToken, async (req, res) => {
|
||||
// Release and Transfer to Finished Goods have no standalone page of
|
||||
// their own — those stay on production.html's detail popup.
|
||||
const STAGE_CARD_HREF = { release: '/production', issuance: '/issue-production', receipt: '/receipt-production', transfer_fg: '/production', close: '/close-production' };
|
||||
// Consumable Orders (Release → Issue → Close only, no Receipt/Transfer to
|
||||
// FG) are gated by their OWN dedicated steps, never the general
|
||||
// production_order:* ones — mirrors services/productionOrderStore.js's
|
||||
// own notifyStepFor()/CONSUMABLE_STEP_FOR (not exported, so duplicated
|
||||
// here, same convention as WORK_ORDER_STEP_KEYS above). Without this, a
|
||||
// user holding the general 'production_order:release' step (but NOT
|
||||
// 'production_order:consumable_release') incorrectly saw every pending
|
||||
// Consumable Order in the bell too, even though the Production Order
|
||||
// page itself already correctly hides Consumable Orders from them.
|
||||
const CONSUMABLE_STEP_FOR = { release: 'consumable_release', issuance: 'consumable_issue', close: 'consumable_close' };
|
||||
const pos = await poStore.listProductionOrders({ status: 'IN_PROGRESS' });
|
||||
// REJECTED orders (receipt posted with rejection lines) still need to be
|
||||
// CLOSED — surface them to the close-step users too.
|
||||
const rejected = await poStore.listProductionOrders({ status: 'REJECTED' });
|
||||
rejected.forEach(p => { pos.push(Object.assign({}, p, { stage: 4 })); }); // stage 4 = Close
|
||||
pos.forEach(p => {
|
||||
const key = poStore.STEP_KEYS[p.stage];
|
||||
const generalKey = poStore.STEP_KEYS[p.stage];
|
||||
const key = p.isConsumable ? (CONSUMABLE_STEP_FOR[generalKey] || null) : generalKey;
|
||||
// Same rule as the Issue/Receipt/Close pages themselves: being ASSIGNED
|
||||
// the step (any perm — view/add/edit/approve) means the action is yours,
|
||||
// so it must show in the bell too. (Was 'approve'-only, which hid e.g.
|
||||
@@ -120,6 +133,23 @@ router.get('/pending', verifyToken, async (req, res) => {
|
||||
});
|
||||
} catch (e) { console.warn('[notifications] bom scan failed:', e.message); }
|
||||
|
||||
// Production Deviations awaiting QA sign-off — pending for whoever holds
|
||||
// 'approve' on production_order:deviation (see [[production-deviation-workflow]]).
|
||||
// Only QA_STATUS='PENDING' counts as pending; N_A (QA not required for this
|
||||
// one) / APPROVED / REJECTED are already resolved, nothing left to do.
|
||||
try {
|
||||
if (hasStepPerm(user, 'production_order:deviation', 'approve')) {
|
||||
const devs = await require('../services/deviationStore').listDeviations({});
|
||||
devs.filter(d => d.qaStatus === 'PENDING').forEach(d => {
|
||||
items.push({
|
||||
module: 'deviation', label: 'Deviation', title: d.sapDocNum ? `PWO #${d.sapDocNum}` : `Item ${d.itemCode}`,
|
||||
detail: `${d.type.charAt(0) + d.type.slice(1).toLowerCase()} — ${d.itemCode}${d.newItemCode ? ' → ' + d.newItemCode : ''} — awaiting QA`,
|
||||
link: d.sapAbsEntry ? `/production?open=${d.sapAbsEntry}` : '/deviations', id: d.id, cardHref: '/deviations',
|
||||
});
|
||||
});
|
||||
}
|
||||
} catch (e) { console.warn('[notifications] deviation scan failed:', e.message); }
|
||||
|
||||
if (user.role === 'admin' || user.role === 'sap_adder') {
|
||||
try {
|
||||
const pending = await require('../services/passwordResetStore').listRequests('PENDING');
|
||||
|
||||
Reference in New Issue
Block a user