feat(materials): added in a bigger window on eom transfer lots
This commit is contained in:
@@ -6,9 +6,12 @@ import { tryCatch } from "../../../../globalUtils/tryCatch.js";
|
|||||||
import { createLog } from "../../../logger/logger.js";
|
import { createLog } from "../../../logger/logger.js";
|
||||||
import { query } from "../../../sqlServer/prodSqlServer.js";
|
import { query } from "../../../sqlServer/prodSqlServer.js";
|
||||||
import { labelInfo } from "../../../sqlServer/querys/warehouse/labelInfo.js";
|
import { labelInfo } from "../../../sqlServer/querys/warehouse/labelInfo.js";
|
||||||
|
import { format, formatDuration, intervalToDuration } from "date-fns";
|
||||||
|
import { shiftChange } from "../../../sqlServer/querys/misc/shiftChange.js";
|
||||||
|
import { success } from "zod/v4";
|
||||||
|
|
||||||
type NewLotData = {
|
type NewLotData = {
|
||||||
runnungNumber: number;
|
runningNumber: number;
|
||||||
lotNumber: number;
|
lotNumber: number;
|
||||||
originalAmount: number;
|
originalAmount: number;
|
||||||
level: number;
|
level: number;
|
||||||
@@ -16,6 +19,17 @@ type NewLotData = {
|
|||||||
type: "lot" | "eom";
|
type: "lot" | "eom";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
interface PendingJob {
|
||||||
|
timeoutId: NodeJS.Timeout;
|
||||||
|
runningNumber: string | number;
|
||||||
|
data: any;
|
||||||
|
consumeLot: any;
|
||||||
|
newQty: any;
|
||||||
|
scheduledFor: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const pendingJobs = new Map<string | number, PendingJob>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move manual material to a new lot.
|
* Move manual material to a new lot.
|
||||||
*
|
*
|
||||||
@@ -28,11 +42,116 @@ type NewLotData = {
|
|||||||
* type what way are we lots
|
* type what way are we lots
|
||||||
*/
|
*/
|
||||||
export const lotMaterialTransfer = async (data: NewLotData) => {
|
export const lotMaterialTransfer = async (data: NewLotData) => {
|
||||||
let timeoutTrans: number = data.type === "lot" ? 1 : 10;
|
// check if we already have this running number scheduled
|
||||||
|
if (pendingJobs.has(data.runningNumber)) {
|
||||||
|
const job = pendingJobs.get(data.runningNumber) as PendingJob;
|
||||||
|
|
||||||
|
const duration = intervalToDuration({
|
||||||
|
start: new Date(),
|
||||||
|
end: job.scheduledFor,
|
||||||
|
});
|
||||||
|
createLog(
|
||||||
|
"error",
|
||||||
|
"materials",
|
||||||
|
"ocp",
|
||||||
|
`${
|
||||||
|
data.runningNumber
|
||||||
|
} is pending to be transfered already, remaining time ${formatDuration(
|
||||||
|
duration,
|
||||||
|
{ format: ["hours", "minutes", "seconds"] }
|
||||||
|
)}`
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: `${
|
||||||
|
data.runningNumber
|
||||||
|
} is pending to be transfered already, remaining time ${formatDuration(
|
||||||
|
duration,
|
||||||
|
{ format: ["hours", "minutes", "seconds"] }
|
||||||
|
)}`,
|
||||||
|
data: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// get the shift time
|
||||||
|
const { data: shift, error: shiftError } = (await tryCatch(
|
||||||
|
query(shiftChange, "shift change from material.")
|
||||||
|
)) as any;
|
||||||
|
|
||||||
|
if (shiftError) {
|
||||||
|
createLog(
|
||||||
|
"error",
|
||||||
|
"materials",
|
||||||
|
"ocp",
|
||||||
|
"There was an error getting the shift times will use fallback times"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// shift split
|
||||||
|
const shiftTimeSplit = shift?.data[0]?.shiftChange.split(":");
|
||||||
|
//console.log(shiftTimeSplit);
|
||||||
|
// Current time
|
||||||
|
const now = new Date();
|
||||||
|
|
||||||
|
// Target time: today at 06:35
|
||||||
|
const target = new Date(
|
||||||
|
now.getFullYear(),
|
||||||
|
now.getMonth(),
|
||||||
|
1, //now.getDate(),
|
||||||
|
shiftTimeSplit.length > 0 ? parseInt(shiftTimeSplit[0]) - 1 : 5, // this will parse the hour to remove teh zero
|
||||||
|
shiftTimeSplit.length > 0 ? parseInt(shiftTimeSplit[1]) + 3 : 3,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
// to early time
|
||||||
|
const early = new Date(
|
||||||
|
now.getFullYear(),
|
||||||
|
now.getMonth(),
|
||||||
|
1, //now.getDate(),
|
||||||
|
shiftTimeSplit.length > 0 ? parseInt(shiftTimeSplit[0]) - 1 : 5, // this will parse the hour to remove teh zero
|
||||||
|
shiftTimeSplit.length > 0 ? parseInt(shiftTimeSplit[1]) : 0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
// next month just to be here
|
||||||
|
const nextMonth = new Date(
|
||||||
|
now.getFullYear(),
|
||||||
|
now.getMonth() + 1,
|
||||||
|
1, //now.getDate(),
|
||||||
|
shiftTimeSplit.length > 0 ? parseInt(shiftTimeSplit[0]) - 1 : 5, // this will parse the hour to remove teh zero
|
||||||
|
shiftTimeSplit.length > 0 ? parseInt(shiftTimeSplit[1]) : 0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
// console.log(early, target);
|
||||||
|
// if we are to early return early only if we are sending over eom
|
||||||
|
if (data.type === "eom" && (early > now || target < now)) {
|
||||||
|
createLog(
|
||||||
|
"error",
|
||||||
|
"materials",
|
||||||
|
"ocp",
|
||||||
|
`Eom transfers is not allowed right now please try again at ${format(
|
||||||
|
nextMonth,
|
||||||
|
"M/d/yyyy hh:mm"
|
||||||
|
)} `
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: `Eom transfers is not allowed right now please try again at ${format(
|
||||||
|
nextMonth,
|
||||||
|
"M/d/yyyy hh:mm"
|
||||||
|
)} `,
|
||||||
|
data: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let timeoutTrans: number = data.type === "lot" ? 30 : 10;
|
||||||
// get the barcode, and layoutID from the running number
|
// get the barcode, and layoutID from the running number
|
||||||
const { data: label, error: labelError } = (await tryCatch(
|
const { data: label, error: labelError } = (await tryCatch(
|
||||||
query(
|
query(
|
||||||
labelInfo.replace("[runningNr]", `${data.runnungNumber}`),
|
labelInfo.replace("[runningNr]", `${data.runningNumber}`),
|
||||||
"Get label info"
|
"Get label info"
|
||||||
)
|
)
|
||||||
)) as any;
|
)) as any;
|
||||||
@@ -56,11 +175,11 @@ export const lotMaterialTransfer = async (data: NewLotData) => {
|
|||||||
"error",
|
"error",
|
||||||
"materials",
|
"materials",
|
||||||
"ocp",
|
"ocp",
|
||||||
`${data.runnungNumber}: dose not exist or no longer in stock.`
|
`${data.runningNumber}: dose not exist or no longer in stock.`
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
message: `${data.runnungNumber}: dose not exist or no longer in stock.`,
|
message: `${data.runningNumber}: dose not exist or no longer in stock.`,
|
||||||
data: [],
|
data: [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -72,11 +191,11 @@ export const lotMaterialTransfer = async (data: NewLotData) => {
|
|||||||
"error",
|
"error",
|
||||||
"materials",
|
"materials",
|
||||||
"ocp",
|
"ocp",
|
||||||
`${data.runnungNumber}: currently in stock and not consumed to a lot.`
|
`${data.runningNumber}: currently in stock and not consumed to a lot.`
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
message: `${data.runnungNumber}: currently in stock and not consumed to a lot.`,
|
message: `${data.runningNumber}: currently in stock and not consumed to a lot.`,
|
||||||
data: [],
|
data: [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -132,11 +251,11 @@ export const lotMaterialTransfer = async (data: NewLotData) => {
|
|||||||
"error",
|
"error",
|
||||||
"materials",
|
"materials",
|
||||||
"ocp",
|
"ocp",
|
||||||
`RN:${data.runnungNumber}, Reprinting Error: ${reprint.data.data.message}`
|
`RN:${data.runningNumber}, Reprinting Error: ${reprint.data.data.message}`
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
message: `RN:${data.runnungNumber}, Reprinting Error: ${reprint.data.data.message}`,
|
message: `RN:${data.runningNumber}, Reprinting Error: ${reprint.data.data.message}`,
|
||||||
data: reprint,
|
data: reprint,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -161,11 +280,11 @@ export const lotMaterialTransfer = async (data: NewLotData) => {
|
|||||||
"error",
|
"error",
|
||||||
"materials",
|
"materials",
|
||||||
"ocp",
|
"ocp",
|
||||||
`RN:${data.runnungNumber}, Return Error ${matReturn.data.data.errors[0].message}`
|
`RN:${data.runningNumber}, Return Error ${matReturn.data.data.errors[0].message}`
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
message: `RN:${data.runnungNumber}, Return Error ${matReturn.data.data.errors[0].message}`,
|
message: `RN:${data.runningNumber}, Return Error ${matReturn.data.data.errors[0].message}`,
|
||||||
data: matReturn,
|
data: matReturn,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -175,9 +294,66 @@ export const lotMaterialTransfer = async (data: NewLotData) => {
|
|||||||
barcode: label?.data[0].Barcode,
|
barcode: label?.data[0].Barcode,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const delay =
|
||||||
|
data.type === "lot"
|
||||||
|
? timeoutTrans * 1000
|
||||||
|
: target.getTime() - now.getTime();
|
||||||
|
|
||||||
|
const transfer = await transferMaterial(delay, data, consumeLot, newQty);
|
||||||
|
|
||||||
|
if (!transfer.success) {
|
||||||
|
return {
|
||||||
|
success: transfer.success,
|
||||||
|
message: transfer.message,
|
||||||
|
data: transfer.data,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const duration = intervalToDuration({ start: now, end: target });
|
||||||
|
const pretty = formatDuration(duration, {
|
||||||
|
format: ["hours", "minutes", "seconds"],
|
||||||
|
});
|
||||||
|
|
||||||
|
if (data.type === "eom") {
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: `RN:${data.runningNumber}: qty: ${newQty}, will be transfered to lot: ${data.lotNumber}, in ${pretty} `,
|
||||||
|
data: [],
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: `RN:${data.runningNumber}: qty: ${newQty}, was transfered to lot: ${data.lotNumber}`,
|
||||||
|
data: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const transferMaterial = async (
|
||||||
|
delay: number,
|
||||||
|
data: any,
|
||||||
|
consumeLot: any,
|
||||||
|
newQty: any
|
||||||
|
) => {
|
||||||
|
//console.log(data);
|
||||||
|
if (pendingJobs.has(data.runningNumber)) {
|
||||||
|
createLog(
|
||||||
|
"error",
|
||||||
|
"materials",
|
||||||
|
"ocp",
|
||||||
|
`${data.runningNumber} is pending to be transfered already`
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: `${data.runningNumber} is pending to be transfered already`,
|
||||||
|
data: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const scheduledFor = new Date(Date.now() + delay);
|
||||||
// sets the time out based on the type of transfer sent over.
|
// sets the time out based on the type of transfer sent over.
|
||||||
setTimeout(
|
const timeoutId = setTimeout(async () => {
|
||||||
async () => {
|
try {
|
||||||
const { data: matConsume, error: matConsumeError } =
|
const { data: matConsume, error: matConsumeError } =
|
||||||
(await tryCatch(
|
(await tryCatch(
|
||||||
runProdApi({
|
runProdApi({
|
||||||
@@ -187,45 +363,59 @@ export const lotMaterialTransfer = async (data: NewLotData) => {
|
|||||||
})
|
})
|
||||||
)) as any;
|
)) as any;
|
||||||
|
|
||||||
if (!matConsume.success) {
|
if (!matConsume?.success) {
|
||||||
createLog(
|
createLog(
|
||||||
"error",
|
"error",
|
||||||
"materials",
|
"materials",
|
||||||
"ocp",
|
"ocp",
|
||||||
`RN:${data.runnungNumber}, Consume Error ${matConsume.data.data.errors[0].message}`
|
`RN:${data.runningNumber}, Consume Error ${
|
||||||
|
matConsume?.data?.data?.errors?.[0]?.message ??
|
||||||
|
"Unknown"
|
||||||
|
}`
|
||||||
);
|
);
|
||||||
return {
|
return; // still hits finally
|
||||||
success: false,
|
|
||||||
message: `RN:${data.runnungNumber}, Consume Error ${matConsume.data.data.errors[0].message}`,
|
|
||||||
data: matConsume,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
createLog(
|
createLog(
|
||||||
"info",
|
"info",
|
||||||
"materials",
|
"materials",
|
||||||
"ocp",
|
"ocp",
|
||||||
`RN:${data.runnungNumber}: qty: ${newQty}, was transfered to lot:${data.lotNumber}`
|
`RN:${data.runningNumber}: qty: ${newQty}, was transferred to lot:${data.lotNumber}`
|
||||||
);
|
);
|
||||||
},
|
} catch (err) {
|
||||||
data.type === "lot" ? timeoutTrans * 1000 : timeoutTrans * 1000 * 60
|
createLog(
|
||||||
);
|
"error",
|
||||||
|
"materials",
|
||||||
|
"ocp",
|
||||||
|
`RN:${data.runningNumber}, ${err}`
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
// Always clear the pending entry, even if error
|
||||||
|
pendingJobs.delete(data.runningNumber);
|
||||||
|
}
|
||||||
|
}, delay);
|
||||||
|
|
||||||
if (data.type === "eom") {
|
pendingJobs.set(data.runningNumber, {
|
||||||
return {
|
timeoutId,
|
||||||
success: true,
|
runningNumber: data.runningNumber,
|
||||||
message: `RN:${data.runnungNumber}: qty: ${newQty}, will be transfered to:${data.lotNumber}, in ${timeoutTrans}min`,
|
data,
|
||||||
data: [],
|
consumeLot,
|
||||||
};
|
newQty,
|
||||||
} else {
|
scheduledFor,
|
||||||
return {
|
});
|
||||||
success: true,
|
|
||||||
message: `RN:${data.runnungNumber}: qty: ${newQty}, was transfered to lot:${data.lotNumber}`,
|
// Immediately say we scheduled it
|
||||||
data: [],
|
return {
|
||||||
};
|
success: true,
|
||||||
}
|
message: `Transfer for ${data.runningNumber} scheduled`,
|
||||||
|
data: [],
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// setInterval(() => {
|
||||||
|
// console.log(pendingJobs);
|
||||||
|
// }, 5000);
|
||||||
|
|
||||||
// setTimeout(async () => {
|
// setTimeout(async () => {
|
||||||
// lotMaterialTransfer({
|
// lotMaterialTransfer({
|
||||||
// runnungNumber: 603468,
|
// runnungNumber: 603468,
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import bookInLabel from "./routes/labeling/bookIn.js";
|
|||||||
import labelRatio from "./routes/labeling/getLabelRatio.js";
|
import labelRatio from "./routes/labeling/getLabelRatio.js";
|
||||||
import resetRatio from "./routes/labeling/resetLabelRatio.js";
|
import resetRatio from "./routes/labeling/resetLabelRatio.js";
|
||||||
import materialTransferLot from "./routes/materials/lotTransfer.js";
|
import materialTransferLot from "./routes/materials/lotTransfer.js";
|
||||||
|
import pendingTransfers from "./routes/materials/currentPending.js";
|
||||||
import { zechitti1Connect } from "./controller/specialProcesses/zechettis/zechetti1.js";
|
import { zechitti1Connect } from "./controller/specialProcesses/zechettis/zechetti1.js";
|
||||||
|
|
||||||
const app = new OpenAPIHono();
|
const app = new OpenAPIHono();
|
||||||
@@ -51,6 +52,7 @@ const routes = [
|
|||||||
dycoClose,
|
dycoClose,
|
||||||
// materials
|
// materials
|
||||||
materialTransferLot,
|
materialTransferLot,
|
||||||
|
pendingTransfers,
|
||||||
] as const;
|
] as const;
|
||||||
const setting = await db.select().from(settings);
|
const setting = await db.select().from(settings);
|
||||||
|
|
||||||
|
|||||||
51
server/services/ocp/routes/materials/currentPending.ts
Normal file
51
server/services/ocp/routes/materials/currentPending.ts
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
// an external way to creating logs
|
||||||
|
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
|
||||||
|
import { responses } from "../../../../globalUtils/routeDefs/responses.js";
|
||||||
|
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
|
||||||
|
import { apiHit } from "../../../../globalUtils/apiHits.js";
|
||||||
|
|
||||||
|
import { pendingJobs } from "../../controller/materials/lotTransfer.js";
|
||||||
|
import { format, formatDuration, intervalToDuration } from "date-fns";
|
||||||
|
|
||||||
|
const app = new OpenAPIHono({ strict: false });
|
||||||
|
|
||||||
|
app.openapi(
|
||||||
|
createRoute({
|
||||||
|
tags: ["ocp"],
|
||||||
|
summary: "Returns pending transfers",
|
||||||
|
method: "get",
|
||||||
|
path: "/pendingtransfers",
|
||||||
|
|
||||||
|
responses: responses(),
|
||||||
|
}),
|
||||||
|
async (c) => {
|
||||||
|
apiHit(c, { endpoint: "/pendingtransfers" });
|
||||||
|
|
||||||
|
const pending = Array.from(pendingJobs.entries()).map(
|
||||||
|
([runningNumber, job]) => {
|
||||||
|
const duration = intervalToDuration({
|
||||||
|
start: new Date(),
|
||||||
|
end: job.scheduledFor,
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
runningNumber,
|
||||||
|
lot: job.data?.lotNumber,
|
||||||
|
newQty: job.newQty,
|
||||||
|
consumeLot: job.consumeLot,
|
||||||
|
scheduledFor: format(job.scheduledFor, "M/d/yyyy HH:mm"),
|
||||||
|
remainingMs: formatDuration(duration, {
|
||||||
|
format: ["hours", "minutes", "seconds"],
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
//console.log(pending);
|
||||||
|
return c.json({
|
||||||
|
success: true,
|
||||||
|
message: "Current Pending trnasfers",
|
||||||
|
data: [pending],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
export default app;
|
||||||
@@ -9,7 +9,7 @@ import { lotMaterialTransfer } from "../../controller/materials/lotTransfer.js";
|
|||||||
const app = new OpenAPIHono({ strict: false });
|
const app = new OpenAPIHono({ strict: false });
|
||||||
|
|
||||||
const LotTransfer = z.object({
|
const LotTransfer = z.object({
|
||||||
runnungNumber: z.number().openapi({ example: 1234 }),
|
runningNumber: z.number().openapi({ example: 1234 }),
|
||||||
lotNumber: z.number().openapi({ example: 1235 }),
|
lotNumber: z.number().openapi({ example: 1235 }),
|
||||||
originalAmount: z.number().openapi({ example: 457 }),
|
originalAmount: z.number().openapi({ example: 457 }),
|
||||||
level: z.number().openapi({ examples: [0.24, 0.5, 0.75, 0.95] }),
|
level: z.number().openapi({ examples: [0.24, 0.5, 0.75, 0.95] }),
|
||||||
@@ -45,7 +45,7 @@ app.openapi(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (transferError) {
|
if (transferError) {
|
||||||
console.log(transferError);
|
//console.log(transferError);
|
||||||
return c.json({
|
return c.json({
|
||||||
success: false,
|
success: false,
|
||||||
message:
|
message:
|
||||||
|
|||||||
4
server/services/sqlServer/querys/misc/shiftChange.ts
Normal file
4
server/services/sqlServer/querys/misc/shiftChange.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export const shiftChange = `
|
||||||
|
select top(1) convert(varchar(8) ,convert(time,startdate), 108) as shiftChange
|
||||||
|
from [test1_AlplaPROD2.0_Read].[masterData].[ShiftDefinition] where teamNumber = 1
|
||||||
|
`;
|
||||||
Reference in New Issue
Block a user