feat(notification): reprint added
All checks were successful
Build and Push LST Docker Image / docker (push) Successful in 2m6s

This commit is contained in:
2026-04-06 16:01:06 -05:00
parent 5865ac3b99
commit a17787e852
7 changed files with 198 additions and 14 deletions

View File

@@ -1,8 +1,108 @@
const reprint = (data: any, emails: string) => { import { eq } from "drizzle-orm";
// TODO: do the actual logic for the notification. import { db } from "../db/db.controller.js";
console.log(data); import { notifications } from "../db/schema/notifications.schema.js";
console.log(emails); import { prodQuery } from "../prodSql/prodSqlQuery.controller.js";
import {
type SqlQuery,
sqlQuerySelector,
} from "../prodSql/prodSqlQuerySelector.utils.js";
import { returnFunc } from "../utils/returnHelper.utils.js";
import { sendEmail } from "../utils/sendEmail.utils.js";
import { tryCatch } from "../utils/trycatch.utils.js";
const reprint = async (data: any, emails: string) => {
// TODO: do the actual logic for the notification.
const { data: l, error: le } = (await tryCatch(
db.select().from(notifications).where(eq(notifications.id, data.id)),
)) as any;
if (le) {
return returnFunc({
success: false,
level: "error",
module: "notification",
subModule: "query",
message: `${data.name} encountered an error while trying to get initial info`,
data: [le],
notify: true,
});
}
// search the query db for the query by name
const sqlQuery = sqlQuerySelector(`${data.name}`) as SqlQuery;
// create the ignore audit logs ids
const ignoreIds = l[0].options[0]?.auditId
? `${l[0].options[0]?.auditId}`
: "0";
// run the check
const { data: queryRun, error } = await tryCatch(
prodQuery(
sqlQuery.query
.replace("[intervalCheck]", l[0].interval)
.replace("[ignoreList]", ignoreIds),
`Running notification query: ${l[0].name}`,
),
);
if (error) {
return returnFunc({
success: false,
level: "error",
module: "notification",
subModule: "query",
message: `Data for: ${l[0].name} encountered an error while trying to get it`,
data: [error],
notify: true,
});
}
if (queryRun.data.length > 0) {
// update the latest audit id
const { error: dbe } = await tryCatch(
db
.update(notifications)
.set({ options: [{ auditId: `${queryRun.data[0].id}` }] })
.where(eq(notifications.id, data.id)),
);
if (dbe) {
return returnFunc({
success: false,
level: "error",
module: "notification",
subModule: "query",
message: `Data for: ${l[0].name} encountered an error while trying to get it`,
data: [dbe],
notify: true,
});
}
// send the email
const sentEmail = await sendEmail({
email: emails,
subject: "Alert! Label Reprinted",
template: "reprintLabels",
context: {
items: queryRun.data,
},
});
if (!sentEmail?.success) {
return returnFunc({
success: false,
level: "error",
module: "email",
subModule: "notification",
message: `${l[0].name} failed to send the email`,
data: [sentEmail],
notify: true,
});
}
} else {
console.log("doing nothing as there is nothing to do.");
}
// TODO send the error to systemAdmin users so they do not always need to be on the notifications. // TODO send the error to systemAdmin users so they do not always need to be on the notifications.
// these errors are defined per notification. // these errors are defined per notification.
}; };

View File

@@ -14,7 +14,7 @@ const note: NewNotification[] = [
"Monitors the labels that are printed and returns a there data, if one falls withing the time frame.", "Monitors the labels that are printed and returns a there data, if one falls withing the time frame.",
active: false, active: false,
interval: "10", interval: "10",
options: [{ prodID: 1 }], options: [{ auditId: [0] }],
}, },
]; ];

View File

@@ -0,0 +1,28 @@
use [test1_AlplaPROD2.0_Read]
SELECT
--JSON_VALUE(content, '$.EntityId') as labelId
a.id
,ActorName
,FORMAT(PrintDate, 'yyyy-MM-dd HH:mm') as printDate
,FORMAT(CreatedDateTime, 'yyyy-MM-dd HH:mm') createdDateTime
,l.ArticleHumanReadableId as av
,l.ArticleDescription as alias
,PrintedCopies
,p.name as printerName
,RunningNumber
--,*
FROM [support].[AuditLog] (nolock) as a
left join
[labelling].[InternalLabel] (nolock) as l on
l.id = JSON_VALUE(content, '$.EntityId')
left join
[masterData].[printer] (nolock) as p on
p.id = l.PrinterId
where message like '%reprint%'
and CreatedDateTime > DATEADD(minute, -[intervalCheck], SYSDATETIMEOFFSET())
and a.id > [ignoreList]
order by CreatedDateTime desc

View File

@@ -0,0 +1,47 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{{!-- <link rel="stylesheet" href="styles/styles.css" /> --}}
{{> styles}}
</head>
<body>
<p>All,</p>
<p>The below labels have been reprinted.</p>
<table >
<thead>
<tr>
<th>AV</th>
<th>Description</th>
<th>Label Number</th>
<th>Date Added</th>
<th>Date Reprinted</th>
<th>Who printed/Updated</th>
<th>What printer it came from</th>
</tr>
</thead>
<tbody>
{{#each items}}
<tr>
<td>{{av}}</td>
<td>{{alias}}</td>
<td>{{RunningNumber}}</td>
<td>{{printDate}}</td>
<td>{{createdDateTime}}</td>
<td>{{ActorName}}</td>
<td>{{printerName}}</td>
</tr>
{{/each}}
</tbody>
</table>
<div>
<p>Thank you,</p>
<p>LST Team</p>
</div>
</body>
</html>

View File

@@ -10,7 +10,8 @@ interface Data<T = unknown[]> {
| "datamart" | "datamart"
| "utils" | "utils"
| "opendock" | "opendock"
| "notification"; | "notification"
| "email";
subModule: subModule:
| "db" | "db"
| "labeling" | "labeling"

View File

@@ -80,7 +80,7 @@ export const Route = createFileRoute("/admin/notifications")({
component: RouteComponent, component: RouteComponent,
}); });
function RouteComponent() { const NotificationTable = () => {
const { data, refetch } = useSuspenseQuery(notifications()); const { data, refetch } = useSuspenseQuery(notifications());
const { data: subs, refetch: subRefetch } = useSuspenseQuery( const { data: subs, refetch: subRefetch } = useSuspenseQuery(
notificationSubs(), notificationSubs(),
@@ -281,6 +281,19 @@ function RouteComponent() {
}), }),
]; ];
return (
<>
<TabsContent value="notifications">
<LstTable data={data} columns={column} />
</TabsContent>
<TabsContent value="subscriptions">
<LstTable data={subData} columns={subsColumn} />
</TabsContent>
</>
);
};
function RouteComponent() {
return ( return (
<div className="space-y-6"> <div className="space-y-6">
<div className="space-y-2"> <div className="space-y-2">
@@ -301,12 +314,7 @@ function RouteComponent() {
<TabsTrigger value="subscriptions">Subscriptions</TabsTrigger> <TabsTrigger value="subscriptions">Subscriptions</TabsTrigger>
</TabsList> </TabsList>
<Suspense fallback={<SkellyTable />}> <Suspense fallback={<SkellyTable />}>
<TabsContent value="notifications"> <NotificationTable />
<LstTable data={data} columns={column} />
</TabsContent>
<TabsContent value="subscriptions">
<LstTable data={subData} columns={subsColumn} />
</TabsContent>
</Suspense> </Suspense>
</Tabs> </Tabs>
</CardContent> </CardContent>

View File

@@ -46,7 +46,7 @@ const updateSettings = async (
id: string, id: string,
data: Record<string, string | number | boolean | null>, data: Record<string, string | number | boolean | null>,
) => { ) => {
console.log(id, data); //console.log(id, data);
try { try {
const res = await axios.patch(`/lst/api/settings/${id}`, data, { const res = await axios.patch(`/lst/api/settings/${id}`, data, {
withCredentials: true, withCredentials: true,