refactor(lottransfer): formatting changes

This commit is contained in:
2025-10-30 10:24:22 -05:00
parent c552b9eb1c
commit a19b03b8bf

View File

@@ -1,31 +1,31 @@
import { format, formatDuration, intervalToDuration } from "date-fns";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { success } from "zod/v4";
import { db } from "../../../../../database/dbclient.js"; import { db } from "../../../../../database/dbclient.js";
import { printerData } from "../../../../../database/schema/printers.js"; import { printerData } from "../../../../../database/schema/printers.js";
import { runProdApi } from "../../../../globalUtils/runProdApi.js"; import { runProdApi } from "../../../../globalUtils/runProdApi.js";
import { tryCatch } from "../../../../globalUtils/tryCatch.js"; 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 { format, formatDuration, intervalToDuration } from "date-fns";
import { shiftChange } from "../../../sqlServer/querys/misc/shiftChange.js"; import { shiftChange } from "../../../sqlServer/querys/misc/shiftChange.js";
import { success } from "zod/v4"; import { labelInfo } from "../../../sqlServer/querys/warehouse/labelInfo.js";
type NewLotData = { type NewLotData = {
runningNumber: number; runningNumber: number;
lotNumber: number; lotNumber: number;
originalAmount: number; originalAmount: number;
level: number; level: number;
amount: number; amount: number;
type: "lot" | "eom"; type: "lot" | "eom";
}; };
interface PendingJob { interface PendingJob {
timeoutId: NodeJS.Timeout; timeoutId: NodeJS.Timeout;
runningNumber: string | number; runningNumber: string | number;
data: any; data: any;
consumeLot: any; consumeLot: any;
newQty: any; newQty: any;
scheduledFor: Date; scheduledFor: Date;
} }
export const pendingJobs = new Map<string | number, PendingJob>(); export const pendingJobs = new Map<string | number, PendingJob>();
@@ -42,385 +42,383 @@ export const pendingJobs = new Map<string | number, PendingJob>();
* type what way are we lots * type what way are we lots
*/ */
export const lotMaterialTransfer = async (data: NewLotData) => { export const lotMaterialTransfer = async (data: NewLotData) => {
// check if we already have this running number scheduled // check if we already have this running number scheduled
if (pendingJobs.has(data.runningNumber)) { if (pendingJobs.has(data.runningNumber)) {
const job = pendingJobs.get(data.runningNumber) as PendingJob; const job = pendingJobs.get(data.runningNumber) as PendingJob;
const duration = intervalToDuration({ const duration = intervalToDuration({
start: new Date(), start: new Date(),
end: job.scheduledFor, end: job.scheduledFor,
}); });
createLog( createLog(
"error", "error",
"materials", "materials",
"ocp", "ocp",
`${ `${
data.runningNumber data.runningNumber
} is pending to be transfered already, remaining time ${formatDuration( } is pending to be transfered already, remaining time ${formatDuration(
duration, duration,
{ format: ["hours", "minutes", "seconds"] } { format: ["hours", "minutes", "seconds"] },
)}` )}`,
); );
return { return {
success: false, success: false,
message: `${ message: `${
data.runningNumber data.runningNumber
} is pending to be transfered already, remaining time ${formatDuration( } is pending to be transfered already, remaining time ${formatDuration(
duration, duration,
{ format: ["hours", "minutes", "seconds"] } { format: ["hours", "minutes", "seconds"] },
)}`, )}`,
data: [], data: [],
}; };
} }
// get the shift time // get the shift time
const { data: shift, error: shiftError } = (await tryCatch( const { data: shift, error: shiftError } = (await tryCatch(
query(shiftChange, "shift change from material.") query(shiftChange, "shift change from material."),
)) as any; )) as any;
if (shiftError) { if (shiftError) {
createLog( createLog(
"error", "error",
"materials", "materials",
"ocp", "ocp",
"There was an error getting the shift times will use fallback times" "There was an error getting the shift times will use fallback times",
); );
} }
// shift split // shift split
const shiftTimeSplit = shift?.data[0]?.shiftChange.split(":"); const shiftTimeSplit = shift?.data[0]?.shiftChange.split(":");
console.log(parseInt(shiftTimeSplit[0]) - 1); console.log(parseInt(shiftTimeSplit[0]) - 1);
// Current time // Current time
const now = new Date(); const now = new Date();
// Target time: today at 06:35 // Target time: today at 06:35
const target = new Date( const target = new Date(
now.getFullYear(), now.getFullYear(),
now.getMonth(), now.getMonth(),
1, //now.getDate(), 1, //now.getDate(),
shiftTimeSplit.length > 0 ? parseInt(shiftTimeSplit[0]) : 5, // this will parse the hour to remove teh zero shiftTimeSplit.length > 0 ? parseInt(shiftTimeSplit[0]) : 5, // this will parse the hour to remove teh zero
shiftTimeSplit.length > 0 ? parseInt(shiftTimeSplit[1]) : 3, shiftTimeSplit.length > 0 ? parseInt(shiftTimeSplit[1]) : 3,
0, 0,
0 0,
); );
console.log("target", target.toLocaleString(), "Now", now.toLocaleString()); console.log("target", target.toLocaleString(), "Now", now.toLocaleString());
// to early time // to early time
const early = new Date( const early = new Date(
now.getFullYear(), now.getFullYear(),
now.getMonth(), now.getMonth(),
1, //now.getDate(), 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[0]) - 1 : 5, // this will parse the hour to remove teh zero
shiftTimeSplit.length > 0 ? parseInt(shiftTimeSplit[1]) : 0, shiftTimeSplit.length > 0 ? parseInt(shiftTimeSplit[1]) : 0,
0, 0,
0 0,
); );
console.log("early", early.toLocaleString(), "Now", now.toLocaleString()); console.log("early", early.toLocaleString(), "Now", now.toLocaleString());
// next month just to be here // next month just to be here
const nextMonth = new Date( const nextMonth = new Date(
now.getFullYear(), now.getFullYear(),
now.getMonth() + 1, now.getMonth() + 1,
1, //now.getDate(), 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[0]) - 1 : 5, // this will parse the hour to remove teh zero
shiftTimeSplit.length > 0 ? parseInt(shiftTimeSplit[1]) : 0, shiftTimeSplit.length > 0 ? parseInt(shiftTimeSplit[1]) : 0,
0, 0,
0 0,
); );
console.log( console.log(
"nextMonth", "nextMonth",
nextMonth.toLocaleString(), nextMonth.toLocaleString(),
"Now", "Now",
now.toLocaleString() now.toLocaleString(),
); );
// console.log(early, target); // console.log(early, target);
// if we are to early return early only if we are sending over eom // if we are to early return early only if we are sending over eom
if (data.type === "eom" && (early > now || target < now)) { if (data.type === "eom" && (early > now || target < now)) {
createLog( createLog(
"error", "error",
"materials", "materials",
"ocp", "ocp",
`Eom transfers is not allowed right now please try again at ${format( `Eom transfers is not allowed right now please try again at ${format(
nextMonth, nextMonth,
"M/d/yyyy hh:mm" "M/d/yyyy hh:mm",
)} ` )} `,
); );
return { return {
success: false, success: false,
message: `Eom transfers is not allowed right now please try again at ${format( message: `Eom transfers is not allowed right now please try again at ${format(
nextMonth, nextMonth,
"M/d/yyyy hh:mm" "M/d/yyyy hh:mm",
)} `, )} `,
data: [], data: [],
}; };
} }
let timeoutTrans: number = data.type === "lot" ? 30 : 10; 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.runningNumber}`), labelInfo.replace("[runningNr]", `${data.runningNumber}`),
"Get label info" "Get label info",
) ),
)) as any; )) as any;
if (labelError) { if (labelError) {
createLog( createLog(
"error", "error",
"materials", "materials",
"ocp", "ocp",
"There was an error getting the label info" "There was an error getting the label info",
); );
return { return {
success: false, success: false,
message: "There was an error getting the label info", message: "There was an error getting the label info",
data: labelError, data: labelError,
}; };
} }
if (label.data.length === 0) { if (label.data.length === 0) {
createLog( createLog(
"error", "error",
"materials", "materials",
"ocp", "ocp",
`${data.runningNumber}: 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.runningNumber}: dose not exist or no longer in stock.`, message: `${data.runningNumber}: dose not exist or no longer in stock.`,
data: [], data: [],
}; };
} }
//console.log(label); //console.log(label);
if (label.data[0]?.stockStatus === "onStock") { if (label.data[0]?.stockStatus === "onStock") {
createLog( createLog(
"error", "error",
"materials", "materials",
"ocp", "ocp",
`${data.runningNumber}: 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.runningNumber}: currently in stock and not consumed to a lot.`, message: `${data.runningNumber}: currently in stock and not consumed to a lot.`,
data: [], data: [],
}; };
} }
// get the pdf24 printer id // get the pdf24 printer id
const { data: printer, error: printerError } = (await tryCatch( const { data: printer, error: printerError } = (await tryCatch(
db.select().from(printerData).where(eq(printerData.name, "PDF24")) db.select().from(printerData).where(eq(printerData.name, "PDF24")),
)) as any; )) as any;
if (printerError) { if (printerError) {
createLog( createLog(
"error", "error",
"materials", "materials",
"ocp", "ocp",
"There was an error the printer info" "There was an error the printer info",
); );
return { return {
success: false, success: false,
message: "There was an error the printer info", message: "There was an error the printer info",
data: printerError, data: printerError,
}; };
} }
// calculate the remaining amount bascially it will be orignal number * level sent over // calculate the remaining amount bascially it will be orignal number * level sent over
// level should be sent in a decimal .25 .5 .75 .95 the 95 will allow basically the what looks to be a full gaylord but we always want to consume something // level should be sent in a decimal .25 .5 .75 .95 the 95 will allow basically the what looks to be a full gaylord but we always want to consume something
const newQty = const newQty =
data.amount > 0 data.amount > 0
? data.amount ? data.amount
: (data.originalAmount * data.level).toFixed(0); : (data.originalAmount * data.level).toFixed(0);
//console.log(data.amount); //console.log(data.amount);
// reprint the label and send it to pdf24 // reprint the label and send it to pdf24
const reprintData = { const reprintData = {
clientId: 999, clientId: 999,
runningNo: label?.data[0].runnungNumber, runningNo: label?.data[0].runnungNumber,
printerId: printer[0].humanReadableId, printerId: printer[0].humanReadableId,
layoutId: label?.data[0].labelLayout, layoutId: label?.data[0].labelLayout,
noOfCopies: 0, noOfCopies: 0,
quantity: newQty, quantity: newQty,
} as any; } as any;
//console.log(reprintData); //console.log(reprintData);
const { data: reprint, error: reprintError } = (await tryCatch( const { data: reprint, error: reprintError } = (await tryCatch(
runProdApi({ runProdApi({
endpoint: "/public/v1.0/ProductionLabelling/ReprintLabel", endpoint: "/public/v1.0/ProductionLabelling/ReprintLabel",
data: [reprintData], data: [reprintData],
}) }),
)) as any; )) as any;
if (!reprint.success) { if (!reprint.success) {
createLog( createLog(
"error", "error",
"materials", "materials",
"ocp", "ocp",
`RN:${data.runningNumber}, Reprinting Error: ${reprint.data.data.message}` `RN:${data.runningNumber}, Reprinting Error: ${reprint.data.data.message}`,
); );
return { return {
success: false, success: false,
message: `RN:${data.runningNumber}, Reprinting Error: ${reprint.data.data.message}`, message: `RN:${data.runningNumber}, Reprinting Error: ${reprint.data.data.message}`,
data: reprint, data: reprint,
}; };
} }
// return the label back to fm1 lane id 10001 // return the label back to fm1 lane id 10001
const matReturnData = { const matReturnData = {
barcode: label?.data[0].Barcode, barcode: label?.data[0].Barcode,
laneId: 10001, laneId: 10001,
}; };
//console.log(matReturnData); //console.log(matReturnData);
const { data: matReturn, error: matReturError } = (await tryCatch( const { data: matReturn, error: matReturError } = (await tryCatch(
runProdApi({ runProdApi({
endpoint: endpoint:
"/public/v1.0/IssueMaterial/ReturnPartiallyConsumedManualMaterial", "/public/v1.0/IssueMaterial/ReturnPartiallyConsumedManualMaterial",
data: [matReturnData], data: [matReturnData],
}) }),
)) as any; )) as any;
if (!matReturn.success) { if (!matReturn.success) {
createLog( createLog(
"error", "error",
"materials", "materials",
"ocp", "ocp",
`RN:${data.runningNumber}, 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.runningNumber}, Return Error ${matReturn.data.data.errors[0].message}`, message: `RN:${data.runningNumber}, Return Error ${matReturn.data.data.errors[0].message}`,
data: matReturn, data: matReturn,
}; };
} }
// consume to the lot provided. // consume to the lot provided.
const consumeLot = { const consumeLot = {
productionLot: data.lotNumber, productionLot: data.lotNumber,
barcode: label?.data[0].Barcode, barcode: label?.data[0].Barcode,
}; };
const delay = const delay =
data.type === "lot" data.type === "lot"
? timeoutTrans * 1000 ? timeoutTrans * 1000
: target.getTime() - now.getTime(); : target.getTime() - now.getTime();
const transfer = await transferMaterial(delay, data, consumeLot, newQty); const transfer = await transferMaterial(delay, data, consumeLot, newQty);
if (!transfer.success) { if (!transfer.success) {
return { return {
success: transfer.success, success: transfer.success,
message: transfer.message, message: transfer.message,
data: transfer.data, data: transfer.data,
}; };
} }
const duration = intervalToDuration({ start: now, end: target }); const duration = intervalToDuration({ start: now, end: target });
const pretty = formatDuration(duration, { const pretty = formatDuration(duration, {
format: ["hours", "minutes", "seconds"], format: ["hours", "minutes", "seconds"],
}); });
if (data.type === "eom") { if (data.type === "eom") {
return { return {
success: true, success: true,
message: `RN:${data.runningNumber}: qty: ${newQty}, will be transfered to lot: ${data.lotNumber}, in ${pretty} `, message: `RN:${data.runningNumber}: qty: ${newQty}, will be transfered to lot: ${data.lotNumber}, in ${pretty} `,
data: [], data: [],
}; };
} else { } else {
return { return {
success: true, success: true,
message: `RN:${data.runningNumber}: qty: ${newQty}, was transfered to lot: ${data.lotNumber}`, message: `RN:${data.runningNumber}: qty: ${newQty}, was transfered to lot: ${data.lotNumber}`,
data: [], data: [],
}; };
} }
}; };
const transferMaterial = async ( const transferMaterial = async (
delay: number, delay: number,
data: any, data: any,
consumeLot: any, consumeLot: any,
newQty: any newQty: any,
) => { ) => {
//console.log(data); //console.log(data);
if (pendingJobs.has(data.runningNumber)) { if (pendingJobs.has(data.runningNumber)) {
createLog( createLog(
"error", "error",
"materials", "materials",
"ocp", "ocp",
`${data.runningNumber} is pending to be transfered already` `${data.runningNumber} is pending to be transfered already`,
); );
return { return {
success: false, success: false,
message: `${data.runningNumber} is pending to be transfered already`, message: `${data.runningNumber} is pending to be transfered already`,
data: [], data: [],
}; };
} }
const scheduledFor = new Date(Date.now() + delay); 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.
const timeoutId = setTimeout(async () => { const timeoutId = setTimeout(async () => {
try { try {
const { data: matConsume, error: matConsumeError } = const { data: matConsume, error: matConsumeError } = (await tryCatch(
(await tryCatch( runProdApi({
runProdApi({ endpoint:
endpoint: "/public/v1.0/IssueMaterial/ConsumeNonPreparedManualMaterial",
"/public/v1.0/IssueMaterial/ConsumeNonPreparedManualMaterial", data: [consumeLot],
data: [consumeLot], }),
}) )) as any;
)) as any;
if (!matConsume?.success) { if (!matConsume?.success) {
createLog( createLog(
"error", "error",
"materials", "materials",
"ocp", "ocp",
`RN:${data.runningNumber}, Consume Error ${ `RN:${data.runningNumber}, Consume Error ${
matConsume?.data?.data?.errors?.[0]?.message ?? matConsume?.data?.data?.errors?.[0]?.message ?? "Unknown"
"Unknown" }`,
}` );
); return; // still hits finally
return; // still hits finally }
}
createLog( createLog(
"info", "info",
"materials", "materials",
"ocp", "ocp",
`RN:${data.runningNumber}: qty: ${newQty}, was transferred to lot:${data.lotNumber}` `RN:${data.runningNumber}: qty: ${newQty}, was transferred to lot:${data.lotNumber}`,
); );
} catch (err) { } catch (err) {
createLog( createLog(
"error", "error",
"materials", "materials",
"ocp", "ocp",
`RN:${data.runningNumber}, ${err}` `RN:${data.runningNumber}, ${err}`,
); );
} finally { } finally {
// Always clear the pending entry, even if error // Always clear the pending entry, even if error
pendingJobs.delete(data.runningNumber); pendingJobs.delete(data.runningNumber);
} }
}, delay); }, delay);
pendingJobs.set(data.runningNumber, { pendingJobs.set(data.runningNumber, {
timeoutId, timeoutId,
runningNumber: data.runningNumber, runningNumber: data.runningNumber,
data, data,
consumeLot, consumeLot,
newQty, newQty,
scheduledFor, scheduledFor,
}); });
// Immediately say we scheduled it // Immediately say we scheduled it
return { return {
success: true, success: true,
message: `Transfer for ${data.runningNumber} scheduled`, message: `Transfer for ${data.runningNumber} scheduled`,
data: [], data: [],
}; };
}; };
// setInterval(() => { // setInterval(() => {