From c5bd5a7c0a074ac1b94fa5435992f2b9a8e65132 Mon Sep 17 00:00:00 2001 From: Blake Matthes Date: Fri, 20 Jun 2025 11:18:37 -0500 Subject: [PATCH] feat(notify): shortage bookings based on time and article type --- .../notifications/shortageBookings.ts | 109 ++++++++++++++++++ .../utils/masterNotifications.ts | 24 ++++ .../utils/views/palletBookedAsWaste.hbs | 44 +++++++ .../utils/views/shortageBookings.hbs | 60 ++++++++++ .../querys/notifications/shortageBookings.ts | 31 +++++ 5 files changed, 268 insertions(+) create mode 100644 server/services/notifications/controller/notifications/shortageBookings.ts create mode 100644 server/services/notifications/utils/views/palletBookedAsWaste.hbs create mode 100644 server/services/notifications/utils/views/shortageBookings.hbs create mode 100644 server/services/sqlServer/querys/notifications/shortageBookings.ts diff --git a/server/services/notifications/controller/notifications/shortageBookings.ts b/server/services/notifications/controller/notifications/shortageBookings.ts new file mode 100644 index 0000000..e95cc3f --- /dev/null +++ b/server/services/notifications/controller/notifications/shortageBookings.ts @@ -0,0 +1,109 @@ +import { eq, sql } from "drizzle-orm"; +import { db } from "../../../../../database/dbclient.js"; +import { notifications } from "../../../../../database/schema/notifications.js"; +import { tryCatch } from "../../../../globalUtils/tryCatch.js"; +import { createLog } from "../../../logger/logger.js"; +import { query } from "../../../sqlServer/prodSqlServer.js"; +import { sendEmail } from "../sendMail.js"; +import { format } from "date-fns-tz"; +import { shortageBookings } from "../../../sqlServer/querys/notifications/shortageBookings.js"; + +export interface Labels { + IdEtikettenHistorie?: number; +} +const notification = async (notifyData: any) => { + /** + * Pass the entire notification over + */ + createLog( + "info", + "wastebooking", + "notify", + `monitoring ${notifyData.name}` + ); + + // validate if there are any emails. + if (notifyData.emails === "") { + createLog( + "error", + "reprinting", + "notify", + `There are no emails set for ${notifyData.name}` + ); + return; + } + + //console.log(notifyData); + // update the settings so we have everything we need + let updatedQuery = shortageBookings + .replace("[time]", notifyData?.notifiySettings.time) + .replace("[type]", notifyData?.notifiySettings.type) + .replace("[avType]", notifyData?.notifiySettings.avType); + + const { data: l, error: shortageError } = await tryCatch( + query(updatedQuery, "Removed as waste check") + ); + const pallets: any = l?.data as any; + + //console.log(updatedQuery); + //console.log(pallets); + if (shortageError) { + createLog( + "error", + "reprinting", + "notify", + `Failed to get the labels: ${shortageError}` + ); + return; + } + + if (pallets.length > 0) { + //send the email :D + const emailSetup = { + email: notifyData.emails, + subject: `Alert! New shortage booking as been completed in the last ${notifyData?.notifiySettings.time} min`, + template: "shortageBookings", + context: { + items: pallets.map((i: any) => { + return { + ...i, + bookingDate: format(i.bookingDate, "M/d/yyyy"), + }; + }), + }, + }; + + const sentEmail = await sendEmail(emailSetup); + + if (!sentEmail.success) { + createLog( + "error", + "reprinting", + "notify", + "Failed to send email, will try again on next interval" + ); + return; + } + + // // update the last time we ran and the prod id + // const notifUpdate = { + // prodID: labels[0].IdEtikettenHistorie, + // lastRan: nowDate(), + // }; + + // update the last time ran + + const { data, error } = await tryCatch( + db + .update(notifications) + .set({ + lastRan: sql`NOW()`, + }) + .where(eq(notifications.name, notifyData.name)) + ); + } else { + return; + } +}; + +export default notification; diff --git a/server/services/notifications/utils/masterNotifications.ts b/server/services/notifications/utils/masterNotifications.ts index edd6057..96dbb87 100644 --- a/server/services/notifications/utils/masterNotifications.ts +++ b/server/services/notifications/utils/masterNotifications.ts @@ -117,6 +117,30 @@ export const note: any = [ active: false, notifiySettings: { processTime: 15 }, }, + { + name: "palletsRemovedAsWaste", + description: + "Validates stock to make sure, there are no pallets released that have been removed as waste already ", + checkInterval: 15, + timeType: "min", + emails: "blake.matthes@alpla.com", + active: false, + notifiySettings: { prodID: 1 }, + }, + { + name: "shortageBookings", + description: + "Checks for material shortage bookings by single av type or all types ", + checkInterval: 15, + timeType: "min", + emails: "blake.matthes@alpla.com", + active: false, + notifiySettings: { + time: 15, + type: "all", // change this to something else or leave blank to use the av type + avType: 1, + }, + }, ]; export const notificationCreate = async () => { diff --git a/server/services/notifications/utils/views/palletBookedAsWaste.hbs b/server/services/notifications/utils/views/palletBookedAsWaste.hbs new file mode 100644 index 0000000..08d9c58 --- /dev/null +++ b/server/services/notifications/utils/views/palletBookedAsWaste.hbs @@ -0,0 +1,44 @@ + + + + + + {{!-- --}} + {{> styles}} + + +

All,

+

The below labels have been brought back into the system either by relocate or by inventory taking order, please validate these labels and reblock them or reremove them.

+ + + + + + + + + + + + {{#each items}} + + + + + + + {{/each}} + +
AVDesciptionLabel NumberLast Moving Date
{{av}}{{alias}}{{runningnumber}}{{lastMovingDate}}
+ +
+

For a removal process logistcs will need to do this in lst so a reason for the removal can be added.

+
+
+ +

Thank you,

+

LST Team

+
+ + + \ No newline at end of file diff --git a/server/services/notifications/utils/views/shortageBookings.hbs b/server/services/notifications/utils/views/shortageBookings.hbs new file mode 100644 index 0000000..691e728 --- /dev/null +++ b/server/services/notifications/utils/views/shortageBookings.hbs @@ -0,0 +1,60 @@ + + + + + + {{!-- --}} + {{> styles}} + + +

All,

+

$shortage bookings were just done on the below pallet(s).

+ + + + + + + + + + + + + + + + {{#each items}} + + + + + + + + + + + {{/each}} + +
Material AVMaterial AliasProduction LotProduction Pallet Running numberMachineMachine NameQuantity ShortedShortage Date
{{materialAV}}{{materialAlias}}{{productionlot}}{{palletWithShortBookings}}{{machineNumber}}{{machineAlias}}{{qtyShortpcs}}{{bookingDate}}
+ +
+

This can be corrected by following the below simple instructions.

+
    +
  1. Bring the pallet back to PPOO
  2. +
  3. Book out the pallet
  4. +
  5. Make the corrections to stock for the above materials/packaging missing
  6. +
  7. Book the pallet back in.
  8. + +
+
+

For further instructions please reach out to regional support via helpdesk ticket

+
+
+

Thank you,

+

LST Team

+
+ + + \ No newline at end of file diff --git a/server/services/sqlServer/querys/notifications/shortageBookings.ts b/server/services/sqlServer/querys/notifications/shortageBookings.ts new file mode 100644 index 0000000..cf35713 --- /dev/null +++ b/server/services/sqlServer/querys/notifications/shortageBookings.ts @@ -0,0 +1,31 @@ +export const shortageBookings = ` + +use AlplaPROD_test1 +Declare @range int = [time] -- change this to be range in minutues you want to monitor, this shouldnt be more than the interval check so we do not see duplicates +declare @avType nvarchar(3) = '[type]' --change to blank or single to have specific ones if all the type is ignored +declare @avTypeID NVARCHAR(MAX) = '[avType]' -- this can only be 1 article now. + + select + IdArtikelVarianten as materialAV + ,IdArtikelTyp + ,ArtikelTypBez + ,ArtikelVariantenAlias as materialAlias + ,CAST(Menge as varchar) as qtyShortpcs + ,ProduktionsLos as productionlot + ,LEFT(PARSE(Right(barcode, 39) as int), LEN(PARSE(Right(barcode, 39)as int)) - 1) as palletWithShortBookings + ,m.Standort as machineNumber + ,m.Bezeichnung ,m.Bezeichnung as machineAlias + ,Buchungsdatum as bookingDate + + from [dbo].[V_LagerBuchungen] (nolock) s + + left join + + dbo.T_Maschine (nolock) as m + on m.IdMaschine = s.IdMaschine + + where beleg like '%$Sho%' and s.Add_Date > DATEADD(MINUTE, -@range, getdate()) + and (@avType = 'all' or IdArtikelTyp in (@avTypeID)) + + order by ProduktionsLos +`;