@openinc/parse-server-opendash
Version:
Parse Server Cloud Code for open.INC Stack.
333 lines (331 loc) • 13 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.init = init;
const cron = __importStar(require("cron"));
const cron_1 = require("cron");
const __1 = require("..");
const openware_1 = require("../features/openware");
const types_1 = require("../types");
const excludeFields = [
"ACL",
"updatedAt",
"objectId",
"tenant",
"source",
"unitInfo",
"tag",
"article",
];
const standardFields = [
"start", //date
"ordernr", //0
"status", //1
"articlenr", //2
"articlename", //3
"setup_time", //4
"duration", //5
"order_quantity", //6
"targettime", //7
];
const defaultValueTypes = [
{ unit: "", name: "ordernr", type: "String" }, //0
{ unit: "", name: "status", type: "String" }, //1
{ unit: "", name: "articlenr", type: "String" }, //2
{ unit: "", name: "articlename", type: "String" }, //3
{ unit: "ms", name: "setup_time", type: "Number" }, //4
{ unit: "ms", name: "duration", type: "Number" }, //5
{ unit: "#", name: "order_quantity", type: "Number" }, //6
{ unit: "ms", name: "targettime", type: "Number" }, //7
];
async function init() {
scheduleOrderStartedStatusCheck("0 * * * * *");
(0, __1.beforeSaveHook)(types_1.MES_Order, async (request) => {
const { object, original, user } = request;
// Non-sync client & Server times. ALlow 1 minute difference
const nowThresholded = Date.now() - 60000;
await (0, __1.defaultHandler)(request);
await (0, __1.defaultAclHandler)(request, {
allowCustomACL: true,
allowTenantUserWrite: true,
});
if (!object.tag) {
const source = await object.get("source")?.fetch({ useMasterKey: true });
if (!source || !source.tag) {
throw new Error("No source found in order. Cannot start order.");
}
object.set("tag", source.tag);
}
if (!object.get("articlenr")) {
const article = await object
.get("article")
?.fetch({ useMasterKey: true });
if (article) {
object.set("articlenr", article.get("artnr"));
object.set("articlename", article?.get("name"));
object.set("targettime", object.targettime
? object.targettime
: article?.get("targettime") || 0);
}
}
if (object.get("status") === "canceled") {
}
// If the order is started and has a source, it is running
if (object.get("start") &&
object.get("start").getTime() > nowThresholded &&
object.get("source") &&
!object.get("status")) {
object.set("status", "running");
}
if (object.get("start") &&
object.get("start").getTime() > Date.now() &&
object.get("source") &&
!object.get("status")) {
object.set("status", "planned");
}
// If the order is started and has no source, it is unknown
if (object.get("start") &&
object.get("start").getTime() < nowThresholded &&
!object.get("source")) {
object.set("status", "unknown");
}
// If the order has been started and ended, it is done
if (object.get("start") &&
object.get("duration") &&
(object.get("status") === "running" || object.get("status") === "planned")) {
object.set("status", "done");
}
});
(0, __1.afterSaveHook)(types_1.MES_Order, async (request) => {
const { object, original, user } = request;
try {
if (original) {
// If the order is canceled, publish it as canceled
if (object.get("status") === "canceled" &&
original.get("status") !== "canceled") {
const data = await object2OWItem(object);
await (0, openware_1.publishDataItem)(data, user?.getEmail(), true);
return;
}
// If the order is rescheduled, publish it as rescheduled
if ((original?.get("start")?.getTime() || 0) !==
(object.get("start")?.getTime() || 0)) {
console.log("-".repeat(20));
console.log("Publishing rescheduled order");
console.log("-".repeat(20));
const rescheduled = await object2OWItem(original);
rescheduled.values[0].value[0] = "rescheduled";
await (0, openware_1.publishDataItem)(rescheduled, user?.getEmail(), true);
return;
}
}
if (object.get("status") === "canceled") {
// If order was canceled before, do not publish it
return;
}
const data = await object2OWItem(object);
await (0, openware_1.publishDataItem)(data, user?.getEmail(), true);
// Publish all running orders separately to make use of these as reference values
if (object.get("status") === "running") {
const runningData = { ...data };
runningData.id = "ow_mes_order_running";
runningData.name = "Order_Running";
console.log("-".repeat(20));
console.log("Publishing running order " + object.id);
console.log("-".repeat(20));
await (0, openware_1.publishDataItem)(runningData, user?.getEmail(), true);
}
}
catch (e) {
console.error(e);
console.log("Order Data not published:" + e.message, e);
}
});
}
async function object2OWItem(object) {
const tag = object.get("tag");
const configString = await new Parse.Query("OD3_Config")
.equalTo("key", "ow.mes.unitInfo")
.descending("priority")
.first({ useMasterKey: true });
const fieldInfos = JSON.parse(configString?.get("value") || "{}");
if (!tag || tag === "") {
throw new Error("No tag found in source. Cannot publish DataItem.");
}
const schemaQ = new Parse.Schema("OD3_MES_Order");
//@ts-expect-error
const schema = await schemaQ.get({ useMasterKey: true });
const fields = schema.fields;
const extraVType = await createCustomValueTypes(object, fields, fieldInfos);
const values = await createValueArrayForObject(object, extraVType, fields);
const valueTypes = [...defaultValueTypes, ...extraVType];
return {
id: "ow_mes_order",
name: "Order",
source: tag,
meta: {},
valueTypes,
values,
};
}
function createCustomValueTypes(object, fields, fieldInfos) {
const keyObject = object.toJSON();
return Object.keys(keyObject)
.filter((field) => {
return !(excludeFields.indexOf(field) !== -1 ||
standardFields.indexOf(field) !== -1);
})
.filter((field) => fields[field].type === "String" ||
fields[field].type === "Number" ||
fields[field].type === "Boolean")
.map((field) => {
const fieldData = fields[field];
switch (fieldData.type) {
case "String":
return {
unit: "",
name: field,
type: "String",
};
case "Number":
return {
unit: fieldInfos[field]?.unit || "",
name: field,
type: "Number",
};
case "Boolean":
return {
unit: "",
name: field,
type: "Boolean",
};
case "Date":
return {
unit: "ms",
name: field,
type: "Number",
};
default:
return {
unit: "",
name: field,
type: "String",
};
}
});
}
async function createValueArrayForObject(object, extraValues, fields) {
const values = [];
const status = object.get("status");
const ordernr = object.get("ordernr");
// const articleData = await object.get("article")?.fetch();
const article = object?.get("articlename");
const articlenr = object?.get("articlenr");
const setup_time = object.get("setup_time");
const duration = object.get("duration");
const order_quantity = object.get("order_quantity");
const targettime = object.get("targettime");
/*
{ unit: "", name: "ordernr", type: "String" }, //0
{ unit: "", name: "status", type: "String" }, //1
{ unit: "", name: "articlenr", type: "String" }, //2
{ unit: "", name: "articlename", type: "String" }, //3
{ unit: "ms", name: "setup_time", type: "Number" }, //4
{ unit: "ms", name: "duration", type: "Number" }, //5
{ unit: "#", name: "order_quantity", type: "Number" }, //6
{ unit: "ms", name: "targettime", type: "Number" }, //7
*/
values.push(ordernr || "unknown"); //0
values.push(status || "unknown"); //1
values.push(articlenr); //2
values.push(article); //3
values.push(setup_time ?? 0); //4
values.push(duration ?? 0); //5
values.push(order_quantity ?? 0); //6
values.push(targettime ?? 0); //7
for (const extraValue of extraValues) {
let value = object.get(extraValue.name);
if (value && fields[extraValue.name].type === "Date") {
if (value instanceof Date) {
value = value.getTime();
}
}
values.push(value);
}
return [{ date: object.get("start").getTime(), value: values }];
}
function scheduleOrderStartedStatusCheck(cronInterval) {
const job = new cron_1.CronJob(cronInterval, // cronTime
() => {
const date = new Date(Date.now() - 24 * 60 * 60 * 1000);
//Orders of last 24 hours
const query = new Parse.Query(types_1.MES_Order);
query.greaterThanOrEqualTo("start", date);
query.find({ useMasterKey: true }).then((orders) => {
orders.forEach((order) => {
const status = order.get("status");
if (!status) {
if (order.get("tag")) {
if (order.get("start").getTime() < Date.now()) {
order.set("status", "running");
order.save(null, { useMasterKey: true });
}
else {
order.set("status", "planned");
order.save(null, { useMasterKey: true });
}
}
else {
order.set("status", "unknown");
order.save(null, { useMasterKey: true });
}
}
else {
if (status === "unknown" || status === "planned") {
if (order.get("start").getTime() < Date.now()) {
order.set("status", "running");
order.save(null, { useMasterKey: true });
}
}
}
});
});
}, () => {
const dt = cron.sendAt(cronInterval);
}, // onComplete
true, // start
"Europe/Berlin" // timeZone
);
}