import { addDays, format, formatISO, isBefore, parseISO, startOfWeek, } from "date-fns"; import { db } from "../../../../../database/dbclient.js"; import { invHistoricalData } from "../../../../../database/schema/historicalINV.js"; import { tryCatch } from "../../../../globalUtils/tryCatch.js"; import { createLog } from "../../../logger/logger.js"; import { query } from "../../../sqlServer/prodSqlServer.js"; import { materialPerDay, materialPurchasesPerDay, } from "../../../sqlServer/querys/dataMart/materialPerDay.js"; import { singleArticle } from "../../../sqlServer/querys/misc/singleArticle.js"; import { sendEmail } from "../sendMail.js"; import { materialPurchases } from "./materialPurchases.js"; import { buildInventoryTimeline } from "./materialWithInv.js"; const getInv = async () => { const { data, error } = await tryCatch(db.select().from(invHistoricalData)); if (error) { return []; } return data; }; function toDate(val: any) { if (val instanceof Date) return val; if (typeof val === "string") return parseISO(val.replace(" ", "T")); return new Date(val); } function sumByMaterialAndWeek(data: any) { /** @type {Record>} */ const grouped: any = {}; for (const r of data) { const mat = String(r.MaterialHumanReadableId); const d = toDate(r.CalDate); const week = formatISO(startOfWeek(d, { weekStartsOn: 1 }), { representation: "date", }); grouped[mat] ??= {}; grouped[mat][week] ??= 0; grouped[mat][week] += Number(r.DailyMaterialDemand) || 0; } const result = []; for (const [mat, weeks] of Object.entries(grouped)) { // @ts-ignore for (const [week, total] of Object.entries(weeks)) { result.push({ MaterialHumanReadableId: mat, WeekStart: week, WeeklyDemand: Number(total).toFixed(2), }); } } return result; } export default async function materialPerDayCheck() { /** * getting the shipped pallets */ const startDate = format(new Date(Date.now()), "yyyy-MM-dd"); const endDate = format(addDays(new Date(Date.now()), 90), "yyyy-MM-dd"); const { data, error } = (await tryCatch( query( materialPerDay .replace("[startDate]", startDate) .replace("[endDate]", endDate), "material check", ), )) as any; if (error) { return { success: false, message: "Error getting the material data", error, }; } if (!data.success) { return { success: false, message: data.message, data: [], }; } // purchases const pOrders = (await materialPurchases({ startDate, endDate })) as any; //console.log(pOrders); const openingInventory: Record = {}; const inventoryRows = await getInv(); for (const row of inventoryRows) { openingInventory[row.article] = Number(row.total_QTY) || 0; } const materialsDemand = buildInventoryTimeline( sumByMaterialAndWeek(data.data) as any, openingInventory, pOrders, ); const { data: av, error: eav } = await tryCatch( query(singleArticle.replace("[av]", "107"), "single article"), ); const formattedMaterials = materialsDemand .filter((n) => n.MaterialHumanReadableId === `${av?.data[0].article}`) .map((i) => ({ ...i, OpeningInventory: i.OpeningInventory?.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2, }), Purchases: i.Purchases?.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2, }), Consumption: i.Consumption?.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2, }), ClosingInventory: i.ClosingInventory?.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2, }), })); // send the email stuff const emailSetup = { email: "blake.matthes@alpla.com", subject: `Material Week.`, template: "materialPerDay", context: { items: formattedMaterials, article: av?.data[0].combined, }, }; const { data: sentEmail, error: sendEmailError } = await tryCatch( sendEmail(emailSetup), ); if (sendEmailError) { createLog( "error", "blocking", "notify", "Failed to send email, will try again on next interval", ); return { success: false, message: "Failed to send email, will try again on next interval", }; } return { success: true, message: "material data", data: formattedMaterials, }; }