121 lines
4.9 KiB
JavaScript
121 lines
4.9 KiB
JavaScript
'use strict';
|
|
// services/oeeStore.js — "Overall Equipment Efficiency" (OEE) data entry.
|
|
// Stored in the PORTAL's own app DB (not SAP), one document per (tab, month):
|
|
// a monthly sheet for one production area (EBB Production, PD Production, …).
|
|
// The row grid (date + shift + all the downtime/output inputs, plus the
|
|
// derived rates) is kept verbatim as a JSON array — the per-tab column schema
|
|
// and formulas live on the client (public/oee.html); the server just persists
|
|
// what it is given and enforces per-user tab permissions (see routes/oee.js).
|
|
const { getPool } = require('./appSqlPool');
|
|
|
|
const TABLE = `[dbo].[ZOEE_ENTRIES]`;
|
|
|
|
async function exec(sqlQuery, params = []) {
|
|
const pool = await getPool();
|
|
const req = pool.request();
|
|
let i = 0;
|
|
const text = sqlQuery.replace(/\?/g, () => { const n = `p${i}`; req.input(n, params[i]); i++; return `@${n}`; });
|
|
const result = await req.query(text);
|
|
return result.recordset || [];
|
|
}
|
|
|
|
function isAlreadyExists(e) {
|
|
const m = (e.message || '').toLowerCase();
|
|
return m.includes('already exists') || m.includes('there is already an object');
|
|
}
|
|
|
|
async function bootstrap() {
|
|
console.log('[OEE] Checking table', TABLE, '…');
|
|
await exec(`
|
|
CREATE TABLE ${TABLE} (
|
|
ID INT IDENTITY(1,1) PRIMARY KEY,
|
|
COMPANY NVARCHAR(100),
|
|
TAB NVARCHAR(50) NOT NULL,
|
|
MONTH NVARCHAR(20) NOT NULL,
|
|
ROWS_JSON NVARCHAR(MAX),
|
|
REMARK NVARCHAR(MAX),
|
|
CANCELED BIT DEFAULT 0,
|
|
CREATED_BY NVARCHAR(50),
|
|
CREATED_BY_ID INT,
|
|
CREATED_AT DATETIME2,
|
|
UPDATED_AT DATETIME2
|
|
)
|
|
`).catch(e => { if (!isAlreadyExists(e)) throw e; else console.log('[OEE] Table already exists — OK'); });
|
|
console.log('[OEE] ✅ Ready');
|
|
}
|
|
|
|
function safeJson(v, fb) { if (!v) return fb; try { return JSON.parse(v); } catch (_e) { return fb; } }
|
|
|
|
function fromRow(r, withRows) {
|
|
if (!r) return null;
|
|
const o = {
|
|
id: r.ID,
|
|
company: r.COMPANY || '',
|
|
tab: r.TAB,
|
|
month: r.MONTH,
|
|
remark: r.REMARK || '',
|
|
canceled: !!r.CANCELED,
|
|
createdBy: r.CREATED_BY || '',
|
|
createdById: r.CREATED_BY_ID || null,
|
|
createdAt: r.CREATED_AT ? new Date(r.CREATED_AT).toISOString() : null,
|
|
updatedAt: r.UPDATED_AT ? new Date(r.UPDATED_AT).toISOString() : null,
|
|
rowCount: 0,
|
|
};
|
|
const rows = safeJson(r.ROWS_JSON, []);
|
|
o.rowCount = Array.isArray(rows) ? rows.length : 0;
|
|
if (withRows) o.rows = Array.isArray(rows) ? rows : [];
|
|
return o;
|
|
}
|
|
|
|
// List documents (headers only). Optional filters: company, tab, month, and
|
|
// an allow-set of tabs (per-user restriction — omit for no restriction).
|
|
async function list({ company, tab, month, allowTabs, top = 30, skip = 0 } = {}) {
|
|
const where = []; const params = [];
|
|
if (company) { where.push(`COMPANY = ?`); params.push(company); }
|
|
if (tab) { where.push(`TAB = ?`); params.push(tab); }
|
|
if (month) { where.push(`MONTH = ?`); params.push(month); }
|
|
if (Array.isArray(allowTabs) && allowTabs.length) {
|
|
where.push(`TAB IN (${allowTabs.map(() => '?').join(',')})`);
|
|
allowTabs.forEach(t => params.push(t));
|
|
}
|
|
const w = where.length ? `WHERE ${where.join(' AND ')}` : '';
|
|
const rows = await exec(
|
|
`SELECT * FROM ${TABLE} ${w} ORDER BY ID DESC OFFSET ${Math.max(0, skip | 0)} ROWS FETCH NEXT ${Math.min(100, top | 0)} ROWS ONLY`,
|
|
params
|
|
);
|
|
return rows.map(r => fromRow(r, false));
|
|
}
|
|
|
|
async function getById(id) {
|
|
const rows = await exec(`SELECT * FROM ${TABLE} WHERE ID = ?`, [parseInt(id)]);
|
|
return rows.length ? fromRow(rows[0], true) : null;
|
|
}
|
|
|
|
async function create({ company, tab, month, rows, remark, createdBy, createdById }) {
|
|
const now = new Date().toISOString().replace('T', ' ').replace('Z', '').substring(0, 23);
|
|
const idRows = await exec(
|
|
`INSERT INTO ${TABLE} (COMPANY, TAB, MONTH, ROWS_JSON, REMARK, CANCELED, CREATED_BY, CREATED_BY_ID, CREATED_AT, UPDATED_AT)
|
|
VALUES (?, ?, ?, ?, ?, 0, ?, ?, ?, ?);
|
|
SELECT SCOPE_IDENTITY() AS ID;`,
|
|
[company || '', tab, month, JSON.stringify(Array.isArray(rows) ? rows : []), remark || null,
|
|
createdBy || null, createdById || null, now, now]
|
|
);
|
|
return idRows[0].ID;
|
|
}
|
|
|
|
async function update(id, { month, rows, remark }) {
|
|
const sets = []; const vals = [];
|
|
if (month !== undefined) { sets.push('MONTH = ?'); vals.push(month); }
|
|
if (rows !== undefined) { sets.push('ROWS_JSON = ?'); vals.push(JSON.stringify(Array.isArray(rows) ? rows : [])); }
|
|
if (remark !== undefined) { sets.push('REMARK = ?'); vals.push(remark || null); }
|
|
sets.push('UPDATED_AT = ?'); vals.push(new Date().toISOString().replace('T', ' ').replace('Z', '').substring(0, 23));
|
|
vals.push(parseInt(id));
|
|
await exec(`UPDATE ${TABLE} SET ${sets.join(', ')} WHERE ID = ?`, vals);
|
|
}
|
|
|
|
async function cancel(id) {
|
|
await exec(`UPDATE ${TABLE} SET CANCELED = 1, UPDATED_AT = SYSUTCDATETIME() WHERE ID = ?`, [parseInt(id)]);
|
|
}
|
|
|
|
module.exports = { bootstrap, list, getById, create, update, cancel };
|