Compare commits

..

25 Commits

Author SHA1 Message Date
9f26f2334f test(ocp): working on more migrations 2025-04-04 17:13:15 -05:00
a7818b4ca3 feat(notificaitons): fixed and corrections to get them working properly 2025-04-04 17:12:48 -05:00
99477bac19 refactor(materials): moved for better sturcture 2025-04-04 17:11:57 -05:00
5eacbb5ecf fix(datamart): added some fixed some 2025-04-04 17:11:32 -05:00
8b5698a839 feat(update all): added a new function to update all servers in a row. easier to walk away 2025-04-04 17:10:55 -05:00
ad5e77028d test(frontend): work on the frontend to have better admin 2025-04-04 17:09:30 -05:00
e1973e4da6 feat(submodules): to help with submodules of course 2025-04-04 17:08:47 -05:00
8194798a37 fix(database): correction to the printer modules 2025-04-04 17:08:25 -05:00
16e5413a90 ci(release): bump build number to 169 2025-04-04 16:35:09 -05:00
6065cccbd7 ci(release): bump build number to 168 2025-04-04 15:53:27 -05:00
9a5dc980f0 ci(release): bump build number to 167 2025-04-04 14:54:24 -05:00
23fa9f09dc ci(release): bump build number to 166 2025-04-04 14:33:49 -05:00
f1c9877686 ci(release): bump build number to 165 2025-04-04 12:19:58 -05:00
6ad49b704d ci(release): bump build number to 164 2025-04-04 12:17:20 -05:00
60cd6e551a ci(release): bump build number to 163 2025-04-04 06:51:21 -05:00
74445149b7 ci(release): bump build number to 162 2025-04-04 06:31:21 -05:00
2e05f79c72 ci(release): bump build number to 161 2025-04-03 20:22:10 -05:00
13df4af860 ci(release): bump build number to 160 2025-04-03 17:31:45 -05:00
6bd1bebe33 ci(release): bump build number to 159 2025-04-03 11:49:47 -05:00
99fd875dbb ci(release): bump build number to 158 2025-04-03 11:03:05 -05:00
17d7e54b7a ci(release): bump build number to 157 2025-04-03 09:56:19 -05:00
498c1626a1 ci(release): bump build number to 156 2025-04-03 09:43:51 -05:00
6180f61d08 ci(release): bump build number to 155 2025-04-03 08:16:10 -05:00
3e4d8b260c ci(release): bump build number to 154 2025-04-03 07:44:37 -05:00
fa9e5dd70f ci(release): bump build number to 153 2025-04-03 07:32:37 -05:00
80 changed files with 14893 additions and 982 deletions

View File

@@ -0,0 +1,2 @@
ALTER TABLE "printers" ALTER COLUMN "lastTimePrinted" SET DATA TYPE timestamp;--> statement-breakpoint
ALTER TABLE "printers" ADD COLUMN "printDelay" numeric;

View File

@@ -0,0 +1,2 @@
ALTER TABLE "printers" ALTER COLUMN "lastTimePrinted" SET DEFAULT now();--> statement-breakpoint
ALTER TABLE "printers" ALTER COLUMN "lastTimePrinted" SET NOT NULL;

View File

@@ -0,0 +1 @@
ALTER TABLE "printers" ALTER COLUMN "lastTimePrinted" SET DATA TYPE timestamp with time zone;

View File

@@ -0,0 +1 @@
ALTER TABLE "printers" DROP COLUMN "lastTimePrinted";

View File

@@ -0,0 +1 @@
ALTER TABLE "printers" DROP COLUMN "printDelay";

View File

@@ -0,0 +1,19 @@
CREATE TABLE "printerData" (
"printer_id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"humanReadableId" text,
"name" text NOT NULL,
"ipAddress" text,
"port" numeric,
"status" text,
"statusText" text,
"lastTimePrinted" timestamp DEFAULT now() NOT NULL,
"assigned" boolean DEFAULT false,
"remark" text,
"printDelay" numeric,
"monitorState" boolean DEFAULT false,
"add_Date" timestamp DEFAULT now(),
"upd_date" timestamp DEFAULT now()
);
--> statement-breakpoint
DROP TABLE "printers" CASCADE;--> statement-breakpoint
CREATE UNIQUE INDEX "humanReadableId" ON "printerData" USING btree ("humanReadableId");

View File

@@ -0,0 +1,17 @@
CREATE TABLE "subModules" (
"submodule_id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"moduleName" text NOT NULL,
"name" text NOT NULL,
"description" text,
"link" text NOT NULL,
"active" boolean DEFAULT false,
"roles" jsonb DEFAULT '["systemAdmin"]'::jsonb NOT NULL,
"subSubModule" jsonb DEFAULT '[]'::jsonb,
"add_User" text DEFAULT 'LST_System' NOT NULL,
"add_Date" timestamp DEFAULT now(),
"upd_User" text DEFAULT 'LST_System' NOT NULL,
"upd_date" timestamp DEFAULT now()
);
--> statement-breakpoint
ALTER TABLE "subModules" ADD CONSTRAINT "subModules_moduleName_modules_name_fk" FOREIGN KEY ("moduleName") REFERENCES "public"."modules"("name") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
CREATE UNIQUE INDEX "subModule_name" ON "subModules" USING btree ("name");

View File

@@ -0,0 +1 @@
DROP INDEX "subModule_name";

View File

@@ -0,0 +1,3 @@
ALTER TABLE "subModules" DROP CONSTRAINT "subModules_moduleName_modules_name_fk";
--> statement-breakpoint
ALTER TABLE "subModules" ALTER COLUMN "moduleName" DROP NOT NULL;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -239,6 +239,69 @@
"when": 1743424730855,
"tag": "0033_flimsy_salo",
"breakpoints": true
},
{
"idx": 34,
"version": "7",
"when": 1743720994399,
"tag": "0034_massive_penance",
"breakpoints": true
},
{
"idx": 35,
"version": "7",
"when": 1743721140937,
"tag": "0035_even_adam_warlock",
"breakpoints": true
},
{
"idx": 36,
"version": "7",
"when": 1743721251498,
"tag": "0036_fixed_spacker_dave",
"breakpoints": true
},
{
"idx": 37,
"version": "7",
"when": 1743721424503,
"tag": "0037_cooing_orphan",
"breakpoints": true
},
{
"idx": 38,
"version": "7",
"when": 1743729665453,
"tag": "0038_lumpy_kitty_pryde",
"breakpoints": true
},
{
"idx": 39,
"version": "7",
"when": 1743771209867,
"tag": "0039_greedy_steve_rogers",
"breakpoints": true
},
{
"idx": 40,
"version": "7",
"when": 1743776921664,
"tag": "0040_luxuriant_aqueduct",
"breakpoints": true
},
{
"idx": 41,
"version": "7",
"when": 1743778410407,
"tag": "0041_wise_molten_man",
"breakpoints": true
},
{
"idx": 42,
"version": "7",
"when": 1743778477759,
"tag": "0042_big_power_pack",
"breakpoints": true
}
]
}

View File

@@ -11,8 +11,8 @@ import {
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
import { z } from "zod";
export const printers = pgTable(
"printers",
export const printerData = pgTable(
"printerData",
{
printer_id: uuid("printer_id").defaultRandom().primaryKey(),
humanReadableId: text("humanReadableId"),
@@ -21,9 +21,10 @@ export const printers = pgTable(
port: numeric("port"),
status: text("status"),
statusText: text("statusText"),
lastTimePrinted: text("lastTimePrinted"),
lastTimePrinted: timestamp("lastTimePrinted").notNull().defaultNow(),
assigned: boolean("assigned").default(false),
remark: text("remark"),
printDelay: numeric("printDelay"),
monitorState: boolean("monitorState").default(false),
add_Date: timestamp("add_Date").defaultNow(),
upd_date: timestamp("upd_date").defaultNow(),
@@ -39,4 +40,4 @@ export const printers = pgTable(
// name: z.string().min(3, {message: "Role name must be more than 3 letters"}),
// });
// Schema for selecting a Expenses - can be used to validate API responses
export const selectRolesSchema = createSelectSchema(printers);
export const selectRolesSchema = createSelectSchema(printerData);

View File

@@ -0,0 +1,45 @@
import {
text,
pgTable,
timestamp,
boolean,
uuid,
uniqueIndex,
jsonb,
} from "drizzle-orm/pg-core";
import { createSelectSchema } from "drizzle-zod";
import { modules } from "./modules.js";
//import {z} from "zod";
export const subModules = pgTable(
"subModules",
{
submodule_id: uuid("submodule_id").defaultRandom().primaryKey(),
moduleName: text("moduleName"),
// .notNull()
// .references(() => modules.name),
name: text("name").notNull(),
description: text("description"),
link: text("link").notNull(),
active: boolean("active").default(false),
roles: jsonb("roles").notNull().default(["systemAdmin"]), // ["view", "technician", "supervisor","manager", "admin","systemAdmin"]
subSubModule: jsonb("subSubModule").default([]),
add_User: text("add_User").default("LST_System").notNull(),
add_Date: timestamp("add_Date").defaultNow(),
upd_user: text("upd_User").default("LST_System").notNull(),
upd_date: timestamp("upd_date").defaultNow(),
}
// (table) => [
// // uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`),
// uniqueIndex("subModule_name").on(table.name),
// ]
);
// Schema for inserting a user - can be used to validate API requests
// export const insertModuleSchema = createInsertSchema(modules, {
// name: z.string().min(3, {message: "Module name should be longer than 3 letters"}),
// });
// Schema for selecting a Expenses - can be used to validate API responses
export const selectModuleSchema = createSelectSchema(subModules);
export type Modules = typeof subModules;

View File

@@ -0,0 +1,8 @@
export default function DataMartStats() {
return (
<div>
The stats for all the data mart querys out there and whos and when
they are last used to understand if we want to keep them or not
</div>
);
}

View File

@@ -0,0 +1,8 @@
export default function NotificationMGT() {
return (
<div>
Manage all notifications from here instad of going to the db,
locking some items that are auto updated on server restarts
</div>
);
}

View File

@@ -19,6 +19,11 @@ import { adminUrlCheck } from "@/utils/adminUrlCheck";
import RestartServer from "./RestartServer";
import StopServer from "./StopServer";
import StartServer from "./StartServer";
import { Button } from "@/components/ui/button";
import { getSettings } from "@/utils/querys/settings";
import { toast } from "sonner";
import axios from "axios";
//import { useState } from "react";
export type Servers = {
server_id?: string;
@@ -33,6 +38,7 @@ export type Servers = {
export default function ServerPage() {
const { user, token } = useSessionStore();
const { modules } = useModuleStore();
//const [upgrading, setUpgrading] = useState(false);
const router = useRouter();
const { data, isError, error, isLoading } = useQuery(
@@ -51,10 +57,45 @@ export default function ServerPage() {
if (isError) {
return <div>{JSON.stringify(error)}</div>;
}
const { data: set } = useQuery(getSettings(token ?? ""));
const upgrade = async () => {
let devDir = set.filter((n: any) => n.name === "devDir");
toast.success("All Servers was just triggered.");
try {
const result = await axios.post(
`/api/server/update/localhost`,
{ devDir: devDir[0].value, all: true },
{
headers: { Authorization: `Bearer ${token}` },
}
);
if (result.data.success) {
toast.success(result.data.message);
}
if (!result.data.success) {
toast.success(result.data.message);
}
} catch (error: any) {
toast.error(
`There was an error updating the server: ${error.data.message}`
);
}
};
//console.log(data);
return (
<LstCard className="m-2 flex place-content-center w-dvh">
<div className="flex justify-end m-2">
<Button
onClick={upgrade}
disabled={data?.some((d: any) => d.isUpgrading)}
>
Update All Servers
</Button>
</div>
<Table>
<TableHeader>
<TableRow>

View File

@@ -1,3 +1,4 @@
import { LstCard } from "@/components/extendedUI/LstCard";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
@@ -10,6 +11,7 @@ import {
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { DebugButton } from "@/utils/formStuff/debugButton";
import { userFormOptions } from "@/utils/formStuff/options/userformOptions";
import { generatePassword } from "@/utils/passwordGen";
@@ -18,10 +20,16 @@ import { useForm } from "@tanstack/react-form";
import { useQuery } from "@tanstack/react-query";
import axios from "axios";
import { toast } from "sonner";
import UserRoles from "./UserRoles";
import { CardHeader } from "@/components/ui/card";
export default function UserCard(data: any) {
const token = localStorage.getItem("auth_token");
const { refetch } = useQuery(getUsers());
//console.log(modules);
//console.log(data.user);
//console.log(userRoles);
const form = useForm({
...userFormOptions(data.user),
onSubmit: async ({ value }) => {
@@ -53,7 +61,10 @@ export default function UserCard(data: any) {
},
});
return (
<div>
<div className="flex flex-row">
<div className="m-2">
<LstCard>
<CardHeader>User Profile</CardHeader>
<form
onSubmit={(e) => {
e.preventDefault();
@@ -72,18 +83,26 @@ export default function UserCard(data: any) {
children={(field) => {
return (
<div className="m-2 min-w-48 max-w-96 p-2">
<Label htmlFor="username">Username</Label>
<Label htmlFor="username">
Username
</Label>
<Input
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
//type="number"
onChange={(e) =>
field.handleChange(e.target.value)
field.handleChange(
e.target.value
)
}
/>
{field.state.meta.errors.length ? (
<em>{field.state.meta.errors.join(",")}</em>
<em>
{field.state.meta.errors.join(
","
)}
</em>
) : null}
</div>
);
@@ -108,11 +127,17 @@ export default function UserCard(data: any) {
onBlur={field.handleBlur}
//type="number"
onChange={(e) =>
field.handleChange(e.target.value)
field.handleChange(
e.target.value
)
}
/>
{field.state.meta.errors.length ? (
<em>{field.state.meta.errors.join(",")}</em>
<em>
{field.state.meta.errors.join(
","
)}
</em>
) : null}
</div>
);
@@ -124,7 +149,9 @@ export default function UserCard(data: any) {
children={(field) => {
return (
<div className="m-2 min-w-48 max-w-96 p-2">
<Label htmlFor={field.name}>Select role</Label>
<Label htmlFor={field.name}>
Select role
</Label>
<Select
value={field.state.value}
onValueChange={field.handleChange}
@@ -137,7 +164,9 @@ export default function UserCard(data: any) {
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>Roles</SelectLabel>
<SelectLabel>
Roles
</SelectLabel>
<SelectItem value="viewer">
Viewer
</SelectItem>
@@ -163,7 +192,9 @@ export default function UserCard(data: any) {
onChangeAsyncDebounceMs: 500,
onChangeAsync: ({ value }) => {
if (
window.location.pathname.includes("/users") &&
window.location.pathname.includes(
"/users"
) &&
value.length === 0
) {
return;
@@ -207,7 +238,9 @@ export default function UserCard(data: any) {
onBlur={field.handleBlur}
//type="number"
onChange={(e) =>
field.handleChange(e.target.value)
field.handleChange(
e.target.value
)
}
/>
<Button
@@ -220,19 +253,33 @@ export default function UserCard(data: any) {
>
Random password
</Button>
<DebugButton data={form.state.values} />
<DebugButton
data={form.state.values}
/>
</div>
{field.state.meta.errors.length ? (
<em>{field.state.meta.errors.join(",")}</em>
<em>
{field.state.meta.errors.join(
","
)}
</em>
) : null}
</div>
);
}}
/>
</form>
</LstCard>
<div>
<Button onClick={form.handleSubmit}>Save</Button>
</div>
</div>
<div className="m-2">
<LstCard>
<CardHeader>User Module / Role Access</CardHeader>
<UserRoles user={data.user} />
</LstCard>
</div>
</div>
);
}

View File

@@ -0,0 +1,16 @@
import { Label } from "@/components/ui/label";
import { useModuleStore } from "@/lib/store/useModuleStore";
//import { Checkbox } from "@radix-ui/react-checkbox";
export default function UserRoles(user: any) {
const { modules } = useModuleStore();
console.log(user);
return (
<div>
{modules?.map((m: any) => {
console.log(m);
return <Label>{m.name}</Label>;
})}
</div>
);
}

View File

@@ -1,4 +1,4 @@
import {Cylinder, Package, Truck} from "lucide-react";
import { Cylinder, Package, Truck } from "lucide-react";
import {
SidebarGroup,
SidebarGroupContent,
@@ -7,8 +7,8 @@ import {
SidebarMenuButton,
SidebarMenuItem,
} from "../../ui/sidebar";
import {hasPageAccess} from "@/utils/userAccess";
import {User} from "@/types/users";
import { hasPageAccess } from "@/utils/userAccess";
import { User } from "@/types/users";
// this will need to be moved to a links section the db to make it more easy to remove and add
const items = [
{
@@ -20,48 +20,64 @@ const items = [
active: true,
},
{
title: "Bulk orders",
url: "#",
name: "Bulk orders",
moduleName: "logistics",
description: "",
link: "#",
icon: Truck,
role: ["systemAdmin"],
module: "logistics",
active: true,
subSubModule: [],
},
{
title: "Forecast",
url: "#",
name: "Forecast",
moduleName: "logistics",
description: "",
link: "#",
icon: Truck,
role: ["systemAdmin"],
module: "logistics",
active: true,
subSubModule: [],
},
{
title: "Ocme cycle counts",
url: "#",
name: "Ocme cycle counts",
moduleName: "logistics",
description: "",
link: "#",
icon: Package,
role: ["technician", "supervisor", "manager", "admin", "systemAdmin"],
module: "logistics",
active: false,
subSubModule: [],
},
{
title: "Material Helper",
url: "/materialHelper/consumption",
name: "Material Helper",
moduleName: "logistics",
description: "",
link: "/materialHelper/consumption",
icon: Package,
role: ["technician", "supervisor", "manager", "admin", "systemAdmin"],
module: "logistics",
active: true,
subSubModule: [],
},
{
title: "Ocme Cyclecount",
url: "/cyclecount",
name: "Ocme Cyclecount",
moduleName: "logistics",
description: "",
link: "/cyclecount",
icon: Package,
role: ["technician", "supervisor", "manager", "admin", "systemAdmin"],
module: "logistics",
active: true,
subSubModule: [],
},
];
export function LogisticsSideBar({user, moduleID}: {user: User | null; moduleID: string}) {
export function LogisticsSideBar({
user,
moduleID,
}: {
user: User | null;
moduleID: string;
}) {
return (
<SidebarGroup>
<SidebarGroupLabel>Logistics</SidebarGroupLabel>
@@ -70,7 +86,8 @@ export function LogisticsSideBar({user, moduleID}: {user: User | null; moduleID:
{items.map((item) => (
<SidebarMenuItem key={item.title}>
<>
{hasPageAccess(user, item.role, moduleID) && item.active && (
{hasPageAccess(user, item.role, moduleID) &&
item.active && (
<SidebarMenuButton asChild>
<a href={item.url}>
<item.icon />

View File

@@ -32,7 +32,7 @@ let lotColumns = [
label: "AvDescription",
},
{
key: "LOT",
key: "lot",
label: "LotNumber",
},
{
@@ -208,10 +208,14 @@ export default function Lots() {
<TableCell className="font-medium">
{lot.Alias}
</TableCell>
<TableCell className="font-medium">
{lot.LOT}
<TableCell
className={`font-medium ${lot.ProlinkLot != lot.lot ? "text-red-500" : ""}`}
>
{lot.lot}
</TableCell>
<TableCell className="font-medium">
<TableCell
className={`font-medium ${lot.ProlinkLot != lot.lot ? "text-red-500" : ""}`}
>
{lot.ProlinkLot}
</TableCell>
<TableCell className="font-medium">

View File

@@ -1,20 +1,28 @@
import {QueryClient, QueryClientProvider} from "@tanstack/react-query";
import {useModuleStore} from "../../lib/store/useModuleStore";
import {useEffect} from "react";
import {useSettingStore} from "@/lib/store/useSettings";
//import {useGetUserRoles} from "@/lib/store/useGetRoles";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { useModuleStore } from "../../lib/store/useModuleStore";
import { useEffect } from "react";
import { useSettingStore } from "@/lib/store/useSettings";
import { useGetUserRoles } from "@/lib/store/useGetRoles";
const queryClient = new QueryClient();
export const SessionProvider = ({children}: {children: React.ReactNode}) => {
const {fetchModules} = useModuleStore();
const {fetchSettings} = useSettingStore();
//const {fetchUserRoles} = useGetUserRoles();
export const SessionProvider = ({
children,
}: {
children: React.ReactNode;
}) => {
const { fetchModules } = useModuleStore();
const { fetchSettings } = useSettingStore();
const { fetchUserRoles } = useGetUserRoles();
useEffect(() => {
fetchModules();
fetchSettings();
//fetchUserRoles();
fetchUserRoles();
}, []);
return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>;
return (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
);
};

View File

@@ -12,7 +12,7 @@ function Checkbox({
<CheckboxPrimitive.Root
data-slot="checkbox"
className={cn(
"peer border-input data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
"peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
className
)}
{...props}

View File

@@ -1,6 +1,5 @@
import {create} from "zustand";
import {useSessionStore} from "./sessionStore";
import {Modules} from "@/types/modules";
import { create } from "zustand";
import { Modules } from "@/types/modules";
import axios from "axios";
interface SettingState {
@@ -15,15 +14,17 @@ interface FetchModulesResponse {
export const useGetUserRoles = create<SettingState>()((set) => ({
userRoles: [],
setUserRoles: (userRoles) => set({userRoles}),
setUserRoles: (userRoles) => set({ userRoles }),
fetchUserRoles: async () => {
try {
//const response = await axios.get<{data: Setting[]}>(`${process.env.NEXT_PUBLIC_URL}/api/settings/client`);
const {token} = useSessionStore();
const response = await axios.get("/api/auth/getuseraccess", {headers: {Authorization: `Bearer ${token}`}});
const token = localStorage.getItem("auth_token");
const response = await axios.get("/api/auth/getuseraccess", {
headers: { Authorization: `Bearer ${token}` },
});
const data: FetchModulesResponse = response.data; //await response.json();
//console.log(data);
set({userRoles: data.data});
set({ userRoles: data.data });
} catch (error) {
console.error("Failed to fetch settings:", error);
}

View File

@@ -1,7 +1,7 @@
export type LotType = {
AV: number;
Alias: string;
LOT: number;
lot: number;
LabelOnlineID: number;
MachineDescription: string;
MachineID: number;

View File

@@ -27,7 +27,7 @@
"commit": "cz",
"prodinstall": "npm i --omit=dev && npm run db:migrate",
"checkupdates": "npx npm-check-updates",
"testingCode": "dotenvx run -f .env -- tsx watch database/testFiles/checkServerData.ts"
"testingCode": "dotenvx run -f .env -- tsx watch server/services/notifications/controller/notifications/tiIntergrationV1.ts"
},
"config": {
"commitizen": {
@@ -35,7 +35,7 @@
}
},
"admConfig": {
"build": 152,
"build": 169,
"oldBuild": "backend-0.1.3.zip"
},
"devDependencies": {

View File

@@ -12,7 +12,8 @@ type UpdateServerResponse = {
export const updateServer = async (
devApp: string,
server: string | null
server: string | null,
all?: boolean | null
): Promise<UpdateServerResponse> => {
const app = await getAppInfo(devApp);
const serverInfo = await db
@@ -34,7 +35,7 @@ export const updateServer = async (
};
}
if (serverInfo[0].isUpgrading) {
if (serverInfo[0].isUpgrading && !all) {
createLog(
"error",
"lst",
@@ -165,6 +166,9 @@ export const updateServer = async (
export async function processAllServers(devApp: string) {
const servers = await db.select().from(serverData);
//change all servers to be upgrading
await db.update(serverData).set({ isUpgrading: true });
createLog(
"info",
"lst",
@@ -176,7 +180,8 @@ export async function processAllServers(devApp: string) {
try {
const updateToServer = await updateServer(
devApp,
server.plantToken
server.plantToken,
true
);
createLog(
"info",
@@ -186,7 +191,11 @@ export async function processAllServers(devApp: string) {
);
count = count + 1;
//return {success: true, message: `${server.sName} was updated.`, data: updateToServer};
// return {
// success: true,
// message: `${server.sName} was updated.`,
// data: updateToServer,
// };
} catch (error: any) {
createLog(
"info",
@@ -194,7 +203,15 @@ export async function processAllServers(devApp: string) {
"serverUpdater",
`Error updating ${server.sName}: ${error.message}`
);
//return {success: false, message: `Error updating ${server.sName}: ${error.message}`};
// return {
// success: false,
// message: `Error updating ${server.sName}: ${error.message}`,
// };
}
}
return {
success: true,
message: `All Servers are being updated this will take some time.`,
};
}

View File

@@ -0,0 +1,29 @@
import { query } from "../../sqlServer/prodSqlServer.js";
import { customerInvNoHold } from "../../sqlServer/querys/dataMart/customerInventoryQuerys.js";
export const getCurrentCustomerInv = async (customer: any | null) => {
let updatedQuery = customerInvNoHold;
if (customer) {
//console.log(data.customer);
updatedQuery = customerInvNoHold.replaceAll(
"--and IdAdressen",
`and IdAdressen = ${customer}`
);
}
try {
const inventory = await query(updatedQuery, "Get active inventory");
return {
success: true,
message: "All customer inventory minus holds",
data: inventory,
};
} catch (error) {
return {
success: false,
message: "There was an error getting the inventory",
data: error,
};
}
};

View File

@@ -0,0 +1,66 @@
import { eq } from "drizzle-orm";
import { db } from "../../../../database/dbclient.js";
import { settings } from "../../../../database/schema/settings.js";
import { tryCatch } from "../../../globalUtils/tryCatch.js";
import { query } from "../../sqlServer/prodSqlServer.js";
import { openOrders } from "../../sqlServer/querys/dataMart/openOrders.js";
export const getOpenOrders = async (data: any | null) => {
const { data: plantToken, error: plantError } = await tryCatch(
db.select().from(settings).where(eq(settings.name, "plantToken"))
);
if (plantError) {
return {
success: false,
message: "Error getting Settings",
data: plantError,
};
}
let orders = [];
let updatedQuery = openOrders;
// start days can be sent over
if (data?.sDay) {
updatedQuery = updatedQuery.replaceAll("[sDay]", data.sDay[0]);
} else {
updatedQuery = updatedQuery.replaceAll("[sDay]", "15");
}
// end days can be sent over
if (data?.eDay) {
updatedQuery = updatedQuery.replaceAll("[eDay]", data.eDay[0]);
} else {
updatedQuery = updatedQuery.replaceAll("[eDay]", "5");
}
try {
orders = await query(updatedQuery, "Get active openorders");
} catch (error) {
return { success: false, message: "Current open orders", data: orders };
}
// add plant token in
const pOrders = orders.map((item: any) => {
// const dateCon = new Date(item.loadingDate).toLocaleString("en-US", {
// month: "numeric",
// day: "numeric",
// year: "numeric",
// hour: "2-digit",
// minute: "2-digit",
// hour12: false,
// });
//const dateCon = new Date(item.loadingDate).toISOString().replace("T", " ").split(".")[0];
const dateCon = new Date(item.loadingDate).toISOString().split("T")[0];
//const delDate = new Date(item.deliveryDate).toISOString().replace("T", " ").split(".")[0];
const delDate = new Date(item.deliveryDate).toISOString().split("T")[0];
return {
plantToken: plantToken[0].value,
...item,
loadingDate: dateCon,
deliveryDate: delDate,
};
});
return { success: true, message: "Current open orders", data: pOrders };
};

View File

@@ -1,14 +1,25 @@
import { createLog } from "../../logger/logger.js";
import { query } from "../../sqlServer/prodSqlServer.js";
import {
totalInvNoRn,
totalInvRn,
} from "../../sqlServer/querys/dataMart/totalINV.js";
export const getINV = async () => {
export const getINV = async (rn: boolean) => {
let inventory: any = [];
let updatedQuery = totalInvNoRn;
if (rn) {
createLog(
"info",
"datamart",
"datamart",
"The user requested the running numbers this could take a while."
);
updatedQuery = totalInvRn;
}
try {
inventory = await query(updatedQuery, "Gets Curruent inv");
return { success: true, message: "Current inv", data: inventory };

View File

@@ -2,10 +2,20 @@ import { OpenAPIHono } from "@hono/zod-openapi";
import activequerys from "./route/getCurrentQuerys.js";
import getArticles from "./route/getActiveArticles.js";
import currentInv from "./route/getInventory.js";
import getCustomerInv from "./route/getCustomerInv.js";
import getOpenOrders from "./route/getOpenOrders.js";
import siloAdjustments from "./route/getSiloAdjustments.js";
const app = new OpenAPIHono();
const routes = [activequerys, getArticles, currentInv] as const;
const routes = [
activequerys,
getArticles,
currentInv,
getCustomerInv,
getOpenOrders,
siloAdjustments,
] as const;
const appRoutes = routes.forEach((route) => {
app.route("/datamart", route);

View File

@@ -23,25 +23,26 @@ const current: any = [
// endpoint: "/api/v1/masterData/getMissingPKGData",
// description: "Returns all packaging data that is missing either printer, layout, or carton layout",
// },
// {
// name: "getCustomerInventory",
// endpoint: "/api/v1/masterData/getCustomerInventory",
// description: "Returns specific customer inventory based on there address ID.",
// criteria: "customer",
// },
{
name: "getCustomerInventory",
endpoint: "/api/datamart/getcustomerinventory",
description:
"Returns specific customer inventory based on there address ID.",
criteria: "customer",
},
// {
// name: "getPalletLabels",
// endpoint: "/api/v1/masterData/getPalletLabels",
// description: "Returns specific amount of pallets RN, Needs label number and printer, Specfic to Dayton.",
// criteria: "runningNumber,printerName,count",
// },
// {
// name: "getOpenOrders",
// endpoint: "/api/v1/masterData/getOpenOrders",
// description:
// "Returns open orders based on day count sent over, sDay 15 days in the past eDay 5 days in the future, can be left empty for this default days",
// criteria: "sDay,eDay",
// },
{
name: "getopenorders",
endpoint: "/api/datamart/getopenorders",
description:
"Returns open orders based on day count sent over, sDay 15 days in the past eDay 5 days in the future, can be left empty for this default days",
criteria: "sDay,eDay",
},
// {
// name: "getOpenIncoming",
// endpoint: "/api/v1/masterData/getOpenIncoming",
@@ -60,7 +61,7 @@ const current: any = [
// description: "Returns all inventory, by default excludes running numebrs, also excludes inv locations.",
description:
"Returns all inventory, excludes inv locations. no running numbers",
//criteria: "includeRunnningNumbers", // uncomment this out once the improt process can be faster
criteria: "includeRunnningNumbers", // uncomment this out once the improt process can be faster
},
// {
// name: "getOpenOrderUpdates",
@@ -69,13 +70,14 @@ const current: any = [
// description: "Returns all orders based on customer id, leaving empty will pull everythinng in.",
// criteria: "customer", // uncomment this out once the improt process can be faster
// },
// {
// name: "getSiloAdjustment",
// endpoint: "/api/v1/warehouse/getSiloAdjustment",
// // description: "Returns all inventory, by default excludes running numebrs, also excludes inv locations.",
// description: "Returns all siloadjustments in selected date range IE: 1/1/2025 to 1/31/2025",
// criteria: "startDate,endDate", // uncomment this out once the improt process can be faster
// },
{
name: "getSiloAdjustment",
endpoint: "/api/v1/warehouse/getSiloAdjustment",
// description: "Returns all inventory, by default excludes running numebrs, also excludes inv locations.",
description:
"Returns all siloadjustments in selected date range IE: 1/1/2025 to 1/31/2025",
criteria: "startDate,endDate", // uncomment this out once the improt process can be faster
},
];
app.openapi(
@@ -95,6 +97,7 @@ app.openapi(
return c.json({
success: true,
message: "All Current Active Querys.",
sheetVersion: 2.5,
data: current,
});
}

View File

@@ -0,0 +1,53 @@
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { responses } from "../../../globalUtils/routeDefs/responses.js";
import { tryCatch } from "../../../globalUtils/tryCatch.js";
import { getINV } from "../controller/getinventory.js";
import { getCurrentCustomerInv } from "../controller/getCustomerInventory.js";
const app = new OpenAPIHono({ strict: false });
const Body = z.object({
includeRunnningNumbers: z.string().openapi({ example: "x" }),
});
app.openapi(
createRoute({
tags: ["dataMart"],
summary: "Returns All customer minus holds.",
method: "get",
path: "/getcustomerinventory",
request: {
body: {
content: {
"application/json": { schema: Body },
},
},
},
responses: responses(),
}),
async (c) => {
const customer: string = c.req.query("customer") ?? "";
// make sure we have a vaid user being accessed thats really logged in
//apiHit(c, { endpoint: `api/logger/logs/id` });
const { data, error } = await tryCatch(
getCurrentCustomerInv(customer ? customer : null)
);
if (error) {
return c.json(
{
success: false,
message: "There was an error getting the inv.",
data: error,
},
400
);
}
return c.json({
success: data.success,
message: data.message,
data: data.data,
});
}
);
export default app;

View File

@@ -4,34 +4,33 @@ import { tryCatch } from "../../../globalUtils/tryCatch.js";
import { getINV } from "../controller/getinventory.js";
const app = new OpenAPIHono({ strict: false });
const Body = z.object({
includeRunnningNumbers: z.string().openapi({ example: "x" }),
});
app.openapi(
createRoute({
tags: ["dataMart"],
summary: "Returns All current inventory.",
method: "get",
path: "/getinventory",
// request: {
// body: {
// content: {
// "application/json": { schema: Body },
// },
// },
// },
request: {
body: {
content: {
"application/json": { schema: Body },
},
},
},
responses: responses(),
}),
async (c) => {
// const { data: body, error } = await c.req.json();
const includeRunnningNumbers: string =
c.req.query("includeRunnningNumbers") ?? "";
// if (error) {
// return c.json({
// success: false,
// message: "Missing data please try again.",
// });
// }
// make sure we have a vaid user being accessed thats really logged in
//apiHit(c, { endpoint: `api/logger/logs/id` });
const { data, error } = await tryCatch(getINV());
const { data, error } = await tryCatch(
getINV(includeRunnningNumbers?.length > 0 ? true : false)
);
if (error) {
return c.json(

View File

@@ -0,0 +1,52 @@
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { responses } from "../../../globalUtils/routeDefs/responses.js";
import { tryCatch } from "../../../globalUtils/tryCatch.js";
import { getOpenOrders } from "../controller/getOpenOrders.js";
const app = new OpenAPIHono({ strict: false });
// const Body = z.object({
// includeRunnningNumbers: z.string().openapi({ example: "x" }),
// });
app.openapi(
createRoute({
tags: ["dataMart"],
summary: "Returns All open orders.",
method: "get",
path: "/getopenorders",
// request: {
// body: {
// content: {
// "application/json": { schema: Body },
// },
// },
// },
responses: responses(),
}),
async (c) => {
const customer: any = c.req.queries();
// make sure we have a vaid user being accessed thats really logged in
//apiHit(c, { endpoint: `api/logger/logs/id` });
const { data, error } = await tryCatch(
getOpenOrders(customer ? customer : null)
);
if (error) {
return c.json(
{
success: false,
message: "There was an error getting the inv.",
data: error,
},
400
);
}
return c.json({
success: data.success,
message: data.message,
data: data.data,
});
}
);
export default app;

View File

@@ -0,0 +1,69 @@
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { responses } from "../../../globalUtils/routeDefs/responses.js";
import { tryCatch } from "../../../globalUtils/tryCatch.js";
import { getOpenOrders } from "../controller/getOpenOrders.js";
import axios from "axios";
const app = new OpenAPIHono({ strict: false });
// const Body = z.object({
// includeRunnningNumbers: z.string().openapi({ example: "x" }),
// });
app.openapi(
createRoute({
tags: ["dataMart"],
summary: "Returns All open orders.",
method: "get",
path: "/getsilosdjustment",
// request: {
// body: {
// content: {
// "application/json": { schema: Body },
// },
// },
// },
responses: responses(),
}),
async (c) => {
const customer: any = c.req.queries();
// make sure we have a vaid user being accessed thats really logged in
//apiHit(c, { endpoint: `api/logger/logs/id` });
// const { data, error } = await tryCatch(
// getOpenOrders(customer ? customer : null)
// );
// if (error) {
// return c.json(
// {
// success: false,
// message: "There was an error getting the inv.",
// data: error,
// },
// 400
// );
// }
const dates: any = c.req.queries();
const { data, error } = await tryCatch(
axios.get(
`http://localhost:4400/api/v1/warehouse/getSilosAdjustment?startDate=${dates.startDate[0]}&endDate=${dates.endDate[0]}`
)
);
if (error) {
return c.json({
success: false,
message: "Error running query",
data: error,
});
}
return c.json({
success: data?.data.success,
message: data?.data.message,
data: data?.data.data,
});
}
);
export default app;

View File

@@ -1,16 +1,17 @@
import {ConsoleLogWriter} from "drizzle-orm";
import {prodEndpointCreation} from "../../../globalUtils/createUrl.js";
import {createLog} from "../../logger/logger.js";
import {query} from "../../sqlServer/prodSqlServer.js";
import {labelData} from "../../sqlServer/querys/materialHelpers/labelInfo.js";
import axios from "axios";
import { labelData } from "../../../sqlServer/querys/materialHelpers/labelInfo.js";
import { query } from "../../../sqlServer/prodSqlServer.js";
import { createLog } from "../../../logger/logger.js";
import { prodEndpointCreation } from "../../../../globalUtils/createUrl.js";
type Data = {
runningNr: string;
lotNum: number;
};
export const consumeMaterial = async (data: Data, prod: any) => {
const {runningNr, lotNum} = data;
const { runningNr, lotNum } = data;
// replace the rn
const rnReplace = labelData.replaceAll("[rn]", runningNr);
@@ -21,7 +22,12 @@ export const consumeMaterial = async (data: Data, prod: any) => {
barcode = await query(rnReplace, "labelData");
} catch (error) {
console.log(error);
createLog("error", prod.user.username, "logistics", `Error getting barcode: ${error}`);
createLog(
"error",
prod.user.username,
"logistics",
`Error getting barcode: ${error}`
);
}
if (barcode.length === 0) {
@@ -32,7 +38,9 @@ export const consumeMaterial = async (data: Data, prod: any) => {
//throw Error("The provided runningNr is not in stock");
}
// create the url to post
const url = await prodEndpointCreation("/public/v1.0/IssueMaterial/ConsumeNonPreparedManualMaterial");
const url = await prodEndpointCreation(
"/public/v1.0/IssueMaterial/ConsumeNonPreparedManualMaterial"
);
const consumeSomething = {
productionLot: lotNum,
@@ -47,8 +55,16 @@ export const consumeMaterial = async (data: Data, prod: any) => {
},
});
//console.log(results);
return {success: true, message: "Material was consumed", status: results.status};
return {
success: true,
message: "Material was consumed",
status: results.status,
};
} catch (error: any) {
return {success: false, status: 200, message: error.response?.data.errors[0].message};
return {
success: false,
status: 200,
message: error.response?.data.errors[0].message,
};
}
};

View File

@@ -1,12 +1,10 @@
import { ConsoleLogWriter } from "drizzle-orm";
import { prodEndpointCreation } from "../../../globalUtils/createUrl.js";
import { createLog } from "../../logger/logger.js";
import { query } from "../../sqlServer/prodSqlServer.js";
import { labelData } from "../../sqlServer/querys/materialHelpers/labelInfo.js";
import axios from "axios";
import { laneInfo } from "../../sqlServer/querys/materialHelpers/laneInfo.js";
import { tryCatch } from "../../../globalUtils/tryCatch.js";
import { labelData } from "../../../sqlServer/querys/materialHelpers/labelInfo.js";
import { laneInfo } from "../../../sqlServer/querys/materialHelpers/laneInfo.js";
import { query } from "../../../sqlServer/prodSqlServer.js";
import { createLog } from "../../../logger/logger.js";
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
import { prodEndpointCreation } from "../../../../globalUtils/createUrl.js";
type Data = {
runningNr: string;
laneName: string;

View File

@@ -1,14 +1,15 @@
import {createRoute, OpenAPIHono, z} from "@hono/zod-openapi";
import {authMiddleware} from "../../auth/middleware/authMiddleware.js";
import {apiHit} from "../../../globalUtils/apiHits.js";
import {consumeMaterial} from "../controller/consumeMaterial.js";
import {verify} from "hono/jwt";
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { authMiddleware } from "../../auth/middleware/authMiddleware.js";
import { apiHit } from "../../../globalUtils/apiHits.js";
import { verify } from "hono/jwt";
import { consumeMaterial } from "../controller/materials/consumeMaterial.js";
const app = new OpenAPIHono();
const responseSchema = z.object({
success: z.boolean().optional().openapi({example: true}),
message: z.string().optional().openapi({example: "user access"}),
success: z.boolean().optional().openapi({ example: true }),
message: z.string().optional().openapi({ example: "user access" }),
});
app.openapi(
@@ -18,24 +19,25 @@ app.openapi(
method: "post",
path: "/consume",
middleware: authMiddleware,
description: "Provided a running number and lot number you can consume material.",
description:
"Provided a running number and lot number you can consume material.",
responses: {
200: {
content: {"application/json": {schema: responseSchema}},
content: { "application/json": { schema: responseSchema } },
description: "stopped",
},
400: {
content: {"application/json": {schema: responseSchema}},
content: { "application/json": { schema: responseSchema } },
description: "Failed to stop",
},
401: {
content: {"application/json": {schema: responseSchema}},
content: { "application/json": { schema: responseSchema } },
description: "Failed to stop",
},
},
}),
async (c) => {
apiHit(c, {endpoint: "api/sqlProd/close"});
apiHit(c, { endpoint: "api/sqlProd/close" });
const authHeader = c.req.header("Authorization");
const token = authHeader?.split("Bearer ")[1] || "";
@@ -45,14 +47,24 @@ app.openapi(
//return apiReturn(c, true, access?.message, access?.data, 200);
const data = await c.req.json();
const consume = await consumeMaterial(data, payload);
return c.json({success: consume?.success, message: consume?.message}, 200);
return c.json(
{ success: consume?.success, message: consume?.message },
200
);
} catch (error) {
//console.log(error);
//return apiReturn(c, false, "Error in setting the user access", error, 400);
return c.json({success: false, message: "Missing data please try again", error}, 400);
return c.json(
{
success: false,
message: "Missing data please try again",
error,
},
400
);
}
} catch (error) {
return c.json({success: false, message: "Unauthorized"}, 401);
return c.json({ success: false, message: "Unauthorized" }, 401);
}
}
);

View File

@@ -2,7 +2,7 @@ import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { authMiddleware } from "../../auth/middleware/authMiddleware.js";
import { apiHit } from "../../../globalUtils/apiHits.js";
import { verify } from "hono/jwt";
import { returnMaterial } from "../controller/returnMaterial.js";
import { returnMaterial } from "../controller/materials/returnMaterial.js";
const app = new OpenAPIHono();

View File

@@ -92,7 +92,7 @@ export default async function reprintLabelMonitor(notifyData: any) {
) {
//send the email :D
const emailSetup = {
emailTo: notifyData.emails,
email: notifyData.emails,
subject: `Alert! Downtime recorded greater than ${
notifyData.notifiySettings?.duration
}min ${

View File

@@ -65,7 +65,10 @@ export default async function reprintLabelMonitor(notifyData: any) {
`;
//update the time check
notifyQuery = notifyQuery.replaceAll("[timeCheck]", notifyData.checkTime);
notifyQuery = notifyQuery.replaceAll(
"[timeCheck]",
notifyData.checkInterval
);
notifyQuery = notifyQuery.replaceAll(
"[locations]",
notifyData.notifiySettings.locations
@@ -82,13 +85,13 @@ export default async function reprintLabelMonitor(notifyData: any) {
// update the count with the result
const emailSetup = {
emailTo: notifyData.emails,
email: notifyData.emails,
subject: `Alert! Pallets in production greater than ${notifyData.checkTime} ${notifyData.timeType}`,
template: "productionCheck",
context: {
items: prod,
count: prod.length,
checkTime: notifyData.checkTime,
checkTime: notifyData.checkInterval,
timeCheck: notifyData.timeType,
},
};

View File

@@ -1,5 +1,3 @@
// SELECT count(*) FROM V_EtikettenGedruckt where AnzahlGedruckterKopien > 2 and CONVERT(varchar(5), Add_Date,108) not like CONVERT(varchar(5), Upd_Date,108) and Upd_Date > DATEADD(SECOND, -30,getdate()) and VpkVorschriftBez not like '%$%'
import { eq, sql } from "drizzle-orm";
import { db } from "../../../../../database/dbclient.js";
import { notifications } from "../../../../../database/schema/notifications.js";
@@ -7,90 +5,56 @@ import { tryCatch } from "../../../../globalUtils/tryCatch.js";
import { createLog } from "../../../logger/logger.js";
import { query } from "../../../sqlServer/prodSqlServer.js";
import { sendEmail } from "../sendMail.js";
export interface Blocking {
HumanReadableId?: number;
subject?: string;
}
import { blockQuery } from "../../../sqlServer/querys/notifications/blocking.js";
export default async function qualityBlockingMonitor(notifyData: any) {
createLog("info", "notify", "notify", `monitoring ${notifyData.name}`);
createLog("info", "blcoking", "notify", `monitoring ${notifyData.name}`);
if (notifyData.emails === "") {
createLog(
"error",
"notify",
"blocking",
"notify",
`There are no emails set for ${notifyData.name}`
);
return;
return {
success: false,
message: `There are no emails set for ${notifyData.name}`,
};
}
let blockQuery = `
SELECT
'Alert! new blocking order: #' + cast(HumanReadableId as varchar) + ' - ' + ArticleVariantDescription as subject,
cast([HumanReadableId] as varchar) as blockingNumber,
[ArticleVariantDescription] as article,
cast([CustomerHumanReadableId] as varchar) + ' - ' + [CustomerDescription] as customer,
convert(varchar(10), [test1_AlplaPROD2.0_Reporting].[reporting_blocking].[BlockingOrder].[BlockingDate], 101) + ' - ' + convert(varchar(5), [test1_AlplaPROD2.0_Reporting].[reporting_blocking].[BlockingOrder].[BlockingDate], 108) as blockingDate,
cast(ArticleVariantHumanReadableId as varchar) + ' - ' + ArticleVariantDescription as av,
case when [test1_AlplaPROD2.0_Reporting].[reporting_blocking].[BlockingOrder].Remark = '' or [test1_AlplaPROD2.0_Reporting].[reporting_blocking].[BlockingOrder].Remark is NULL then 'Please reach out to quality for the reason this was placed on hold as a remark was not entered during the blocking processs' else [test1_AlplaPROD2.0_Reporting].[reporting_blocking].[BlockingOrder].Remark end as remark,
cast(FORMAT(TotalAmountOfPieces, '###,###') as varchar) + ' / ' + cast(LoadingUnit as varchar) as peicesAndLoadingUnits,
[test1_AlplaPROD2.0_Reporting].[reporting_blocking].[BlockingOrder].ProductionLotHumanReadableId as lotNumber,
cast(IdGlobalBlockingDefectsGroup as varchar) + ' - ' + BD.Description as mainDefectGroup,
cast(IdGlobalBlockingDefect as varchar) + ' - ' + MD.Description as mainDefect,
sent=0,
lot.MachineLocation as line,
HumanReadableId
FROM [test1_AlplaPROD2.0_Reporting].[reporting_blocking].[BlockingOrder] (nolock)
/*** Join 1.0 table to get correct id info to link ***/
join
[AlplaPROD_test1].[dbo].[T_BlockingOrders] (nolock) AS BO
on [HumanReadableId] = BO.[IdBlockingOrder]
/*** Get the main defect info ***/
Inner join
[AlplaPROD_test1].[dbo].[T_BlockingDefectsGroups] (nolock) as BD
ON BO.IdMainDefectGroup = BD.IdBlockingDefectsGroup
INNER join
[AlplaPROD_test1].[dbo].[T_BlockingDefects] as MD
ON BO.IdMainDefect = MD.IdBlockingDefect
/*** get lot info ***/
left join
(SELECT [MachineLocation]
,[MachineDescription]
,[ProductionLotHumanReadableId]
FROM [test1_AlplaPROD2.0_Reporting].[reporting_productionControlling].[ProducedLot]) as lot
on [test1_AlplaPROD2.0_Reporting].[reporting_blocking].[BlockingOrder].ProductionLotHumanReadableId = lot.ProductionLotHumanReadableId
where [test1_AlplaPROD2.0_Reporting].[reporting_blocking].[BlockingOrder].[BlockingDate] between getdate() - 1 and getdate() + 1
and [test1_AlplaPROD2.0_Reporting].[reporting_blocking].[BlockingOrder].BlockingTrigger = 1
and HumanReadableId NOT IN ([sentBlockingOrders])
`;
//add the blocking orders in.
blockQuery = blockQuery.replaceAll(
"[sentBlockingOrders]",
notifyData.sentBlocking[0].sentBlockingOrders
const { data: noti, error: notiError } = await tryCatch(
db
.select()
.from(notifications)
.where(eq(notifications.name, notifyData.name))
);
let blocking: any;
try {
blocking = await query(blockQuery, "Quality Blocking");
//console.log(labels.length);
// const now = Date.now()
//console.log(blocking);
// console.log(blocking[0].blockingNumber > data.prodID);
if (
blocking.length > 0 &&
blocking[0].HumanReadableId > notifyData.notifiySettings.prodID
) {
//send the email :D
const notiData: any = noti;
const blockingOrders = notiData[0]?.notifiySettings.sentBlockingOrders.map(
(l: any) => {
return l.blockingOrder;
}
);
let blockingQuery = blockQuery.replaceAll(
"[sentBlockingOrders]",
blockingOrders
);
const { data: blocking, error: blockingError } = await tryCatch(
query(blockingQuery, "Quality Blocking")
);
if (blockingError) {
return {
success: false,
message: "Error getting blocking orders",
data: blockingError,
};
}
if (blocking.length > 0) {
const emailSetup = {
emailTo: notifyData.emails,
email: notifyData.emails,
subject:
blocking.length > 0
? `Alert! New blocking orders.`
@@ -101,38 +65,36 @@ export default async function qualityBlockingMonitor(notifyData: any) {
},
};
const sentEmail = await sendEmail(emailSetup);
if (!sentEmail.success) {
const { data: sentEmail, error: sendEmailError } = await tryCatch(
sendEmail(emailSetup)
);
if (sendEmailError) {
createLog(
"error",
"nofity",
"blocking",
"notify",
"Failed to send email, will try again on next interval"
);
return;
return {
success: false,
message:
"Failed to send email, will try again on next interval",
};
}
// add the new blocking order to this
const newBlockingOrders = blocking.map(
(b: any) => b.HumanReadableId
);
//console.log(newBlockingOrders);
//console.log(sentBlocking[0].sentBlockingOrders);
// Ensure no duplicates
const newBlockingOrders = blocking.map((b: any) => {
return {
blockingOrder: b.HumanReadableId,
timeStamp: new Date(Date.now()),
};
});
const uniqueOrders = Array.from(
new Set([
...notifyData.sentBlocking[0].sentBlockingOrders,
...notifyData.notifiySettings.sentBlockingOrders,
...newBlockingOrders,
])
);
// Update sentBlockingOrders
notifyData.sentBlocking[0].sentBlockingOrders = uniqueOrders;
//console.log(notifUpdate);
const { data, error } = await tryCatch(
db
.update(notifications)
@@ -146,13 +108,18 @@ export default async function qualityBlockingMonitor(notifyData: any) {
})
.where(eq(notifications.name, notifyData.name))
);
if (error) {
return {
success: false,
message: "Error updating the blocking orders",
data: error,
};
}
} catch (err) {
createLog(
"error",
"notify",
"notify",
`Error from running the blocking query: ${err}`
);
}
return {
success: true,
message: "Blocking query ran successfully",
blocking,
};
}

View File

@@ -13,13 +13,13 @@ const notification = async (notifyData: any) => {
/**
* Pass the entire notification over
*/
createLog("info", "notify", "notify", `monitoring ${notifyData.name}`);
createLog("debug", "reprinting", "notify", `monitoring ${notifyData.name}`);
// validate if there are any emails.
if (notifyData.emails === "") {
createLog(
"error",
"notify",
"reprinting",
"notify",
`There are no emails set for ${notifyData.name}`
);
@@ -31,13 +31,14 @@ const notification = async (notifyData: any) => {
// set the time of getting the label
if (notifyData.timeType === "sec") {
timeCheck = `DATEADD(SECOND, -${notifyData.checkTime}, getdate()) `;
timeCheck = `DATEADD(SECOND, -${notifyData.checkInterval}, getdate()) `;
} else if (notifyData.timeType === "min") {
timeCheck = `DATEADD(MINUTE, -${notifyData.checkTime}, getdate()) `;
timeCheck = `DATEADD(MINUTE, -${notifyData.checkInterval}, getdate()) `;
}
let reprintQuery = `
SELECT
IdEtikettenHistorie,
IdArtikelvarianten as av,
ArtikelVariantenBez as alias,
LfdNr as runningNumber,
@@ -55,6 +56,7 @@ const notification = async (notifyData: any) => {
`;
//update the time check
reprintQuery = reprintQuery.replaceAll(
"DATEADD(SECOND, -30, getdate()) ",
timeCheck
@@ -66,10 +68,20 @@ const notification = async (notifyData: any) => {
query(reprintQuery, "Label Reprints")
);
if (labelError) {
createLog(
"error",
"reprinting",
"notify",
`Failed to get the labels: ${labelError}`
);
return;
}
if (labels.length > 0) {
//send the email :D
const emailSetup = {
emailTo: notifyData.emails,
email: notifyData.emails,
subject: "Alert! Label Reprinted",
template: "reprintLabels",
context: {
@@ -82,7 +94,7 @@ const notification = async (notifyData: any) => {
if (!sentEmail.success) {
createLog(
"error",
"notify",
"reprinting",
"notify",
"Failed to send email, will try again on next interval"
);
@@ -96,7 +108,6 @@ const notification = async (notifyData: any) => {
// };
// update the last time ran
const updateSettings = notifyData.notifiySettings;
const { data, error } = await tryCatch(
db
@@ -104,7 +115,7 @@ const notification = async (notifyData: any) => {
.set({
lastRan: sql`NOW()`,
notifiySettings: {
...updateSettings,
...notifyData.notifiySettings,
prodID: labels[0].IdEtikettenHistorie,
},
})

View File

@@ -64,7 +64,7 @@ export default async function reprintLabelMonitor(notifyData: any) {
//update the time check
noteQuery = noteQuery
.replaceAll("[timeCheck]", notifyData.checkTime)
.replaceAll("[timeCheck]", notifyData.checkInterval)
.replaceAll("[locations]", notifyData.notifiySettings.locations);
let stage: PPOO[];
@@ -78,13 +78,13 @@ export default async function reprintLabelMonitor(notifyData: any) {
// update the count with the result
const emailSetup = {
emailTo: notifyData.emails,
subject: `Alert! Pallets in staging greater than ${notifyData.checkTime} ${notifyData.timeType}`,
email: notifyData.emails,
subject: `Alert! Pallets in staging greater than ${notifyData.checkInterval} ${notifyData.timeType}`,
template: "stagingCheck",
context: {
items: stage,
count: stage.length,
checkTime: notifyData.checkTime,
checkTime: notifyData.checkInterval,
timeCheck: notifyData.timeType,
},
};

View File

@@ -0,0 +1,20 @@
export const dateCorrection = async (newDate: Date) => {
/**
* corrects the date format to be what ti is expecting
*/
const newDateFormat = new Date(newDate)
.toLocaleString("en-US", {
timeZone: "UTC",
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
hourCycle: "h23", // Ensures 24-hour format
})
.replace(",", "");
return newDateFormat;
};

View File

@@ -0,0 +1,23 @@
const requestUser = process.env.REQUESTUSER || "";
export const headerUpdate = async (data: any, plantToken: any) => {
// update the header
let webHeader = `
<request-id>[requestID]</request-id>
<data>
<WebImport>
<WebImportHeader>
<FileName>[requestID].XML</FileName>
<Type>SOTransportLoader</Type>
<UserName>[requestUser]</UserName>
</WebImportHeader>
`;
webHeader = webHeader
.replaceAll(
"[requestID]",
`${data[0].releaseNumber}-${plantToken[0].value}`
)
.replaceAll("[requestUser]", requestUser);
return webHeader;
};

View File

@@ -0,0 +1,54 @@
import { freightClass } from "../../../../../globalUtils/freightClass.js";
export const loadItems = async (data: any) => {
let itemGroups = "";
for (let i = 0; i < data.length; i++) {
let newItem = `
<ItemGroup id="" isShipUnit="false" isHandlingUnit="false" sequence="${
i + 1
}">
<ContainedBy id=""/>
<LineItem lineNumber="${i + 1}"/>
<Dimensions>
<Dimension type="Length" uom="IN">${(
data[i].pkgLengh / 25.4
).toFixed(2)}</Dimension>
<Dimension type="Width" uom="IN">${(
data[i].pkgWidth / 25.4
).toFixed(2)}</Dimension>
<Dimension type="Height" uom="IN">${Math.round(
data[i].pkgHeight / 25.4
).toFixed(2)}</Dimension>
</Dimensions>
<Description>${`av ${data[i].article} ${data[i].articleAlias}`}</Description>
<FreightClasses>
<FreightClass type="">${freightClass(
data[i].pkgWeight,
data[i].pkgLengh,
data[i].pkgWidth,
data[i].pkgHeight
)}</FreightClass>
</FreightClasses>
<Commodity/>
<NmfcCode/>
<HazardousMaterial>false</HazardousMaterial>
<HazMatDetail/>
<Weights>
<Weight type="actual" uom="KG">${
data[i].pkgWeight * data[i].Pallets
}</Weight>
</Weights>
<Quantities>
<Quantity type="actual" uom="pallet">${
data[i].Pallets
}</Quantity>
</Quantities>
</ItemGroup>
`;
itemGroups += newItem;
}
return itemGroups;
};

View File

@@ -0,0 +1,40 @@
import axios from "axios";
import querystring from "querystring";
import { createLog } from "../../../../logger/logger.js";
//tiCreds
const userid = process.env.USERID || "";
const password = process.env.PASSWORD || "";
export const postToTi = async (data: string) => {
const formBody = querystring.stringify({
userid,
password,
request: data,
});
axios
.post(
"https://t-insightws.mercurygate.net/MercuryGate/common/remoteService.jsp",
formBody,
{
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
}
)
.then((response) => {
//console.log(response.data)
createLog("info", "ti", "notify", "Data was sent over to TI");
return {
success: true,
message: "Data was sent over to TI",
};
})
.catch((error) => {
createLog("error", "ti", "notify", error);
return {
success: false,
message: "Error sending data to TI",
data: error,
};
});
};

View File

@@ -0,0 +1,33 @@
import { createLog } from "../../../../logger/logger.js";
export const scacCheck = async (data: any) => {
createLog(
"info",
"ti",
"notify",
`Checking if ${data[0].addressAlias} has scac: ${
data[0].remark.split(",")[0] ? "there was one" : "no scac"
}`
);
const priceSheet = `
<PriceSheets>
<PriceSheet type="Carrier" isSelected="${
data[0].remark.split(",")[0] ? "true" : "false"
}">
<ContractId/>
${
data[0].remark.split(",")[0]
? `<SCAC>${data[0].remark
.split(",")[0]
.split(":")[1]
.toUpperCase()}</SCAC>`
: `<SCAC/>`
}
<Mode/>
</PriceSheet>
</PriceSheets>
`;
return priceSheet;
};

View File

@@ -0,0 +1,301 @@
import { eq, sql } from "drizzle-orm";
import { db } from "../../../../../../database/dbclient.js";
import { serverData } from "../../../../../../database/schema/serverData.js";
import { settings } from "../../../../../../database/schema/settings.js";
import { tryCatch } from "../../../../../globalUtils/tryCatch.js";
import { notifications } from "../../../../../../database/schema/notifications.js";
import { getHeaders } from "../../../../sqlServer/querys/notifications/ti/getHeaders.js";
import { query } from "../../../../sqlServer/prodSqlServer.js";
import { createLog } from "../../../../logger/logger.js";
import { getOrderToSend } from "../../../../sqlServer/querys/notifications/ti/getOrderToSend.js";
import { xmlPayloadTI } from "./tiXmlPayload.js";
import { headerUpdate } from "./headerUpdate.js";
import { loadItems } from "./loadItems.js";
import { dateCorrection } from "./dateCorrection.js";
import { scacCheck } from "./scacCodeCheck.js";
import { postToTi } from "./postToTI.js";
export const tiImport = async () => {
// get the plant token
let payload = xmlPayloadTI;
const { data: plantData, error: plantError } = await tryCatch(
db.select().from(settings)
);
if (plantError)
return {
success: false,
message: "Error Getting Plant Data.",
data: plantError,
};
const plantToken = plantData?.filter((n) => n.name === "plantToken");
const { data: plantInfo, error: plantEr } = await tryCatch(
db
.select()
.from(serverData)
.where(eq(serverData.plantToken, plantToken[0].value))
);
if (plantEr)
return {
success: false,
message: "Error Getting Plant Data.",
data: plantEr,
};
// parsing posting window
const plantI = plantInfo!;
// order notifications
const { data: notificationSet, error: notificationSettingsErr } =
await tryCatch(
db
.select()
.from(notifications)
.where(eq(notifications.name, "tiIntergration"))
);
if (notificationSettingsErr)
return {
success: false,
message: "Notification missing.",
data: notificationSettingsErr,
};
const notiSet: any = notificationSet;
const customerAccountNum = plantI[0].customerTiAcc as string; // tiIntergration
// get current releaes not in the already sent oders
const releaseString = notiSet[0].notifiySettings.releases
.map((num: any) => `'${num.releaseNumber}'`)
.join(", ");
let orders = getHeaders
.replaceAll("[from]", notiSet[0]?.notifiySettings.start)
.replaceAll("[to]", notiSet[0]?.notifiySettings.end)
.replaceAll("[exclude]", releaseString);
// get the headers pending
const { data: header, error: headerError } = await tryCatch(
query(orders, "Ti get open headers")
);
if (headerError) {
createLog(
"error",
"ti",
"notify",
`Error getting headers: ${headerError}`
);
return {
success: false,
message: "Error getting headers",
data: headerError,
};
}
if (header.length === 0) {
createLog(
"info",
"ti",
"notify",
"There are no pending orders to be sent over to ti."
);
return {
success: true,
message: "There are no pending orders to be sent over to ti.",
};
}
createLog(
"info",
"tiIntergration",
"notify",
`There are a total of ${header.length} to send over`
);
/**
* Update the query to get only the first header
*/
// update query to have the correct plant token
let orderToSend = getOrderToSend
.replaceAll("test1", plantToken[0].value)
.replaceAll("[releaseToProcess]", `'${header[0].releaseNumber}'`)
.replaceAll("[from]", notiSet[0].notifiySettings.start)
.replaceAll("[to]", notiSet[0].notifiySettings.end);
// get the headers pending
const { data: orderData, error: ordersError } = await tryCatch(
query(orderToSend, "Ti get open headers")
);
if (ordersError)
return {
success: false,
message: "Error getting getting orders",
data: ordersError,
};
// update the special instructions section
const otherSettings = plantI[0]?.otherSettings as {
specialInstructions: string;
active: boolean;
}[];
const specialInfo = otherSettings[0].specialInstructions.replaceAll(
"[header]",
orderData[0].Header
);
// add the full amount of pallets sending over
let fullPalToSend = orderData.reduce(
(acc: any, o: any) => acc + o.Pallets,
0
);
//console.log("payload", payload);
payload = payload
.replaceAll(
`[WebImportHeader]`,
await headerUpdate(orderData, plantToken)
)
.replaceAll(`[items]`, await loadItems(orderData))
.replaceAll(`[customerAccountNum]`, customerAccountNum)
.replaceAll("[fullTotalPal]", fullPalToSend)
// add in release info
.replaceAll(`[shipNumber]`, orderData[0].releaseNumber)
.replaceAll(`[loadNumber]`, orderData[0].releaseNumber);
// add in the multi release numbers
let multiRelease = ``;
if (orderData.length > 0) {
for (let i = 0; i < orderData.length; i++) {
const newRelease = `
<ReferenceNumber type="Release Number" isPrimary="false">${orderData[i].releaseNumber}</ReferenceNumber>`;
multiRelease += newRelease;
}
payload = payload.replaceAll("[multieReleaseNumber]", multiRelease);
} else {
payload = payload.replaceAll("[multieReleaseNumber]", "");
}
// add the correct date stuff
payload = payload
.replaceAll(
"[loadingDate]",
await dateCorrection(orderData[0].LoadingDate)
)
.replaceAll(
"[deliveryDate]",
await dateCorrection(orderData[0].DeliveryDate)
);
// shipping ours corrections
const formattedDate = orderData[0].LoadingDate.toLocaleDateString("en-US", {
month: "2-digit",
day: "2-digit",
year: "numeric",
});
const shippingHours = JSON.parse(plantI[0]?.shippingHours!);
payload = payload
.replaceAll(
"[shippingHoursEarly]",
`${formattedDate} ${shippingHours[0].early}`
)
.replaceAll(
"[shippingHoursLate]",
`${formattedDate} ${shippingHours[0].late}`
);
// special instructions
if (otherSettings[0].specialInstructions.length != 0) {
payload = payload.replaceAll("[specialInstructions]", specialInfo);
} else {
payload = payload.replaceAll("[specialInstructions]", "");
}
// shipper info
payload = payload
.replaceAll("[plantName]", `Alpla ${plantI[0]?.sName!}`)
.replaceAll("[plantStreetAddress]", plantI[0]?.streetAddress!)
.replaceAll("[plantCity]", plantI[0]?.cityState!.split(",")[0])
.replaceAll("[plantState]", plantI[0]?.cityState!.split(",")[1])
.replaceAll("[plantZipCode]", plantI[0]?.zipcode!)
.replaceAll("[contactNum]", plantI[0]?.contactPhone!)
.replaceAll("[contactEmail]", plantI[0]?.contactEmail!)
// customer info
.replaceAll("[customerName]", orderData[0].addressAlias)
.replaceAll("[customerStreetAddress]", orderData[0].streetAddress)
.replaceAll("[customerCity]", orderData[0].city.split(",")[0])
.replaceAll("[customerState]", orderData[0].city.split(",")[1])
.replaceAll("[customerZip]", orderData[0].zipCode)
.replaceAll("[customerPO]", orderData[0].Header)
.replaceAll(
"[glCoding]",
`52410-${
orderData[0].artileType.toLowerCase() === "preform" ||
orderData[0].artileType.toLowerCase() === "metalCage"
? 31
: plantI[0].greatPlainsPlantCode
}`
) // {"52410 - " + (artileType.toLowerCase() === "preform" || artileType.toLowerCase() === "metalCage" ? 31: plantInfo[0].greatPlainsPlantCode)}
.replaceAll(
"[pfc]",
`${
orderData[0].artileType.toLowerCase() === "preform" ||
orderData[0].artileType.toLowerCase() === "metalCage"
? 40
: orderData[0].costCenter
}`
)
.replaceAll("[priceSheet]", await scacCheck(orderData));
//send over to be processed
//console.log("payload", payload);
const { data: tiPost, error: tiError } = await tryCatch(postToTi(payload));
if (tiError) {
return {
success: false,
message: "Error posting to TI",
error: tiError,
};
}
/**
* Update the db so we dont try to pull the next one
*/
const uniqueOrders = Array.from(
new Set([
...notiSet[0].notifiySettings.releases,
{
releaseNumber: header[0].releaseNumber,
timeStamp: new Date(Date.now()),
},
])
);
const { data, error } = await tryCatch(
db
.update(notifications)
.set({
lastRan: sql`NOW()`,
notifiySettings: {
...notiSet[0].notifiySettings,
releases: uniqueOrders,
},
})
.where(eq(notifications.name, "tiIntergration"))
);
createLog("info", "ti", "notify", "done with this order");
return { message: "done with this order" };
};

View File

@@ -1,9 +1,6 @@
export let xmlPayloadTI = `
<service-request>
<service-id>ImportWeb</service-id>
<request-id>[requestID]</request-id>
<data>
<WebImport>
[WebImportHeader]
<WebImportFile>
<MercuryGate>
@@ -35,19 +32,18 @@ export let xmlPayloadTI = `
</Address>
</BillTo>
</Payment>
<PriceSheets>
<PriceSheet type="Carrier" isSelected="false"> // get this from the price sheet
<ContractId/>
<SCAC/>
<Mode/>
</PriceSheet>
</PriceSheets>
[priceSheet]
<!-- Comments here -->
<Comments>
<Comment type="SpecialInstructions">[specialInstructions]</Comment>
</Comments>
<Plan>
<Events count="2">
<Event type="Pickup" sequenceNum="1">
<Dates>
<Date type="earliest">[loadingDate]</Date>
<Date type="latest">[deliveryDate]</Date>
<Date type="earliest">[shippingHoursEarly]</Date>
<Date type="latest">[shippingHoursLate]</Date>
</Dates>
<Address type="" isResidential="" isPrimary="false">
<LocationCode/>
@@ -119,24 +115,20 @@ export let xmlPayloadTI = `
</ReferenceNumbers>
<Services/>
<EquipmentList/>
6
<Dimensions>
<Dimension type="RatingCount">[fullTotalPal]</Dimension>
</Dimensions>
<Dates>
<Pickup>
<Date type="earliest">[loadingDate]</Date>
<Date type="latest">[loadingDate]</Date>
<Date type="earliest">[shippingHoursEarly]</Date>
<Date type="latest">[shippingHoursLate]</Date>
</Pickup>
<Drop>
<Date type="earliest">[deliveryDate]</Date>
<Date type="latest">[deliveryDate]</Date>
</Drop>
</Dates>
<PriceSheets>
<PriceSheet type="Carrier" isSelected="false">
<ContractId/>
<SCAC/>
<Mode/>
</PriceSheet>
</PriceSheets>
[priceSheet]
<Shipper>
<Address type="" isResidential="" isPrimary="false">
<LocationCode/>
@@ -160,7 +152,7 @@ export let xmlPayloadTI = `
<Consignee>
<Address type="" isResidential="" isPrimary="false">
<LocationCode/>
<Name>[customer]</Name>
<Name>[customerName]</Name>
<AddrLine1>[customerStreetAddress]</AddrLine1>
<AddrLine2/>
<City>[customerCity]</City>
@@ -168,6 +160,17 @@ export let xmlPayloadTI = `
<PostalCode>[customerZip]</PostalCode>
<CountryCode>USA</CountryCode>
<Contacts />
<!-- Location contacts are optional -->
<Contacts>
<Contact type="">
<Name>Alpla</Name>
<ContactMethods>
<!-- Valid contactMethod types are phone, fax, and email -->
<ContactMethod sequenceNum="1" type="phone">[contactNum]</ContactMethod>
<ContactMethod sequenceNum="1" type="email">[contactEmail]</ContactMethod>
</ContactMethods>
</Contact>
</Contacts>
</Address>
</Consignee>

View File

@@ -1,413 +1,10 @@
import { xmlPayloadTI } from "./tiFullFlow/tiXmlPayload.js";
import axios from "axios";
import querystring from "querystring";
import { getOrderToSend } from "../../../sqlServer/querys/notifications/ti/getOrderToSend.js";
import { getHeaders } from "../../../sqlServer/querys/notifications/ti/getHeaders.js";
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
import { db } from "../../../../../database/dbclient.js";
import { settings } from "../../../../../database/schema/settings.js";
import { serverData } from "../../../../../database/schema/serverData.js";
import { eq, sql } from "drizzle-orm";
import { notifications } from "../../../../../database/schema/notifications.js";
import { query } from "../../../sqlServer/prodSqlServer.js";
import { createLog } from "../../../logger/logger.js";
import { freightClass } from "../../../../globalUtils/freightClass.js";
import { delay } from "../../../../globalUtils/delay.js";
const dateCorrection = (newDate: any) => {
return new Date(newDate)
.toLocaleString("en-US", {
timeZone: "UTC",
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
hourCycle: "h23", // Ensures 24-hour format
})
.replace(",", "");
};
const tiImport = async () => {
//await initializePool();
// get the plant token
const { data: plantData, error: plantError } = await tryCatch(
db.select().from(settings)
);
//await initializePool();
if (plantError) return;
const plantToken = plantData?.filter((n) => n.name === "plantToken");
const { data: plantInfo, error: plantEr } = await tryCatch(
db
.select()
.from(serverData)
.where(eq(serverData.plantToken, plantToken[0].value))
);
// parsing posting window
const plantI = plantInfo!;
//const postTime = JSON.parse(plantI[0]?.tiPostTime!);
// order notifications
const { data: notificationSet, error: notificationSettingsErr } =
await tryCatch(
db
.select()
.from(notifications)
.where(eq(notifications.name, "tiIntergration"))
);
if (notificationSettingsErr) return;
const notiSet: any = notificationSet;
//creds
const userid = "ALPLAWSTEST";
const password = "oe39U1LuLX9ZdY0XKobG";
// const requestID = `ALPLAPBTEST1`; // production will be alpla01-dateTime - this will be the time it was sent over.
const requestUser = "ALPLAWSTEST"; // if alplaprod_rs -- confirm we can use a user name vs the AlplapIMPORT // needs to stay the same as provied
const customerAccountNum = plantI[0].customerTiAcc as string; // ti
// it we dont get anything here we want to make sure we add it in
// get current releaes not in the already sent oders
let orders = getHeaders;
orders = orders
.replaceAll("test1", plantToken[0].value)
.replaceAll("[from]", notiSet?.notifiySettings.start)
.replaceAll("[to]", notiSet?.notifiySettings.end)
.replaceAll(
"[exclude]",
notiSet.notifiySettings.processed
.map((num: any) => `'${num}'`)
.join(", ")
);
//console.log(orders);
let headerPending = [];
try {
headerPending = await query(orders, "Ti get open headers");
} catch (error) {
console.log(error);
}
if (headerPending.length === 0) {
createLog(
"info",
"notification",
"notify",
"There are no pending orders to be sent over to ti."
);
return {
success: true,
code: 1,
message: "There are no pending orders to be sent over to ti.",
};
}
createLog(
"info",
"notification",
"notify",
`There are a total of ${headerPending.length} to send over`
);
// update query to have the correct plant token
let orderToSend = getOrderToSend;
orderToSend = orderToSend
.replaceAll("test1", plantToken[0].value)
.replaceAll("[releaseToProcess]", `'${headerPending[0].releaseNumber}'`)
.replaceAll("[from]", notiSet.notifiySettings.start)
.replaceAll("[to]", notiSet.notifiySettings.end);
// console.log(orderToSend);
let records = [];
try {
records = await query(orderToSend, "Ti send order");
} catch (error) {
console.log(error);
}
//console.log(headerPending.length);
// update the header
let webHeader = `
<request-id>[requestID]</request-id>
<data>
<WebImport>
<WebImportHeader>
<FileName>[requestID].XML</FileName>
<Type>SOTransportLoader</Type>
<UserName>[requestUser]</UserName>
</WebImportHeader>
`;
webHeader = webHeader.replaceAll(
"[requestID]",
`${records[0].releaseNumber}-${plantToken[0].value}`
);
webHeader = webHeader.replaceAll("[requestUser]", requestUser);
// update the special instructions section
const otherSettings = plantI[0]?.otherSettings as {
specialInstructions: string;
active: boolean;
}[];
const specialInfo = otherSettings[0].specialInstructions.replaceAll(
"[header]",
records[0].Header
);
// this part will link into the <ItemGroups></ItemGroups>
let itemGroups = "";
for (let i = 0; i < records.length; i++) {
let newItem = `
<ItemGroup id="" isShipUnit="false" isHandlingUnit="false" sequence="${
i + 1
}">
<ContainedBy id=""/>
<LineItem lineNumber="${i + 1}"/>
<Dimensions>
<Dimension type="Length" uom="IN">${(
records[i].pkgLengh / 25.4
).toFixed(2)}</Dimension>
<Dimension type="Width" uom="IN">${(
records[i].pkgWidth / 25.4
).toFixed(2)}</Dimension>
<Dimension type="Height" uom="IN">${Math.round(
records[i].pkgHeight / 25.4
).toFixed(2)}</Dimension>
</Dimensions>
<Description>${`av ${records[i].article} ${records[i].articleAlias}`}</Description>
<FreightClasses>
<FreightClass type="">${freightClass(
records[i].pkgWeight,
records[i].pkgLengh,
records[i].pkgWidth,
records[i].pkgHeight
)}</FreightClass>
</FreightClasses>
<Commodity/>
<NmfcCode/>
<HazardousMaterial>false</HazardousMaterial>
<HazMatDetail/>
<Weights>
<Weight type="actual" uom="KG">${
records[i].pkgWeight * records[i].Pallets
}</Weight>
</Weights>
<Quantities>
<Quantity type="actual" uom="pallet">${
records[i].Pallets
}</Quantity>
</Quantities>
</ItemGroup>
`;
itemGroups += newItem;
}
// add the full amount of pallets sending over
let fullPalToSend = records.reduce(
(acc: any, o: any) => acc + o.Pallets,
0
);
// rebuild the xml to be properly
let payload = xmlPayloadTI;
payload = payload
.replaceAll(`[WebImportHeader]`, webHeader)
.replaceAll(`[items]`, itemGroups)
.replaceAll(`[customerAccountNum]`, customerAccountNum)
.replaceAll("[fullTotalPal]", fullPalToSend);
// update the main release
//[loadNumber],[shipNumber]
payload = payload.replaceAll(`[shipNumber]`, records[0].releaseNumber);
payload = payload.replaceAll(`[loadNumber]`, records[0].releaseNumber);
// do the multie release if needed
// <ReferenceNumber type="Release Number" isPrimary="false">[multieReleaseNumber]</ReferenceNumber>
let multiRelease = ``;
if (records.length > 0) {
for (let i = 0; i < records.length; i++) {
const newRelease = `
<ReferenceNumber type="Release Number" isPrimary="false">${records[i].releaseNumber}</ReferenceNumber>`;
multiRelease += newRelease;
}
payload = payload.replaceAll("[multieReleaseNumber]", multiRelease);
} else {
payload = payload.replaceAll("[multieReleaseNumber]", "");
}
//update the delivery section
payload = payload.replaceAll(
"[loadingDate]",
dateCorrection(records[0].LoadingDate)
);
payload = payload.replaceAll(
"[deliveryDate]",
dateCorrection(records[0].DeliveryDate)
);
// shipping hours
//<Date type="earliest">[shippingHoursEarly]</Date>
//<Date type="latest">[shippingHoursLate]</Date>
// update teh shipping hours
const now = new Date();
const formattedDate = records[0].LoadingDate.toLocaleDateString("en-US", {
month: "2-digit",
day: "2-digit",
year: "numeric",
});
const shippingHours = JSON.parse(plantI[0]?.shippingHours!);
//console.log(shippingHours);
payload = payload
.replaceAll(
"[shippingHoursEarly]",
`${formattedDate} ${shippingHours[0].early}`
)
.replaceAll(
"[shippingHoursLate]",
`${formattedDate} ${shippingHours[0].late}`
);
payload = payload
.replaceAll("[plantName]", `Alpla ${plantI[0]?.sName!}`)
.replaceAll("[plantStreetAddress]", plantI[0]?.streetAddress!)
.replaceAll("[plantCity]", plantI[0]?.cityState!.split(",")[0])
.replaceAll("[plantState]", plantI[0]?.cityState!.split(",")[1])
.replaceAll("[plantZipCode]", plantI[0]?.zipcode!)
.replaceAll("[contactNum]", plantI[0]?.contactPhone!)
.replaceAll("[contactEmail]", plantI[0]?.contactEmail!)
// customer info
.replaceAll("[customerName]", records[0].addressAlias)
.replaceAll("[customerStreetAddress]", records[0].streetAddress)
.replaceAll("[customerCity]", records[0].city.split(",")[0])
.replaceAll("[customerState]", records[0].city.split(",")[1])
.replaceAll("[customerZip]", records[0].zipCode)
.replaceAll("[customerPO]", records[0].Header)
.replaceAll(
"[glCoding]",
`52410-${
records[0].artileType.toLowerCase() === "preform" ||
records[0].artileType.toLowerCase() === "metalCage"
? 31
: plantI[0].greatPlainsPlantCode
}`
) // {"52410 - " + (artileType.toLowerCase() === "preform" || artileType.toLowerCase() === "metalCage" ? 31: plantInfo[0].greatPlainsPlantCode)}
.replaceAll(
"[pfc]",
`${
records[0].artileType.toLowerCase() === "preform" ||
records[0].artileType.toLowerCase() === "metalCage"
? 40
: records[0].costCenter
}`
);
// special instructions
if (otherSettings[0].specialInstructions.length != 0) {
payload = payload.replaceAll("[specialInstructions]", specialInfo);
}
// update the carrier info if any is needed.
// check the address has a real carrier on it and change to true and put the sacs code in
const hasCarrier = true;
console.log(
`Checking if ${records[0].addressAlias} has scac: ${
records[0].remark.split(",")[0] ? "there was one" : "no scac"
}`
);
const priceSheet = `
<PriceSheets>
<PriceSheet type="Carrier" isSelected="${
records[0].remark.split(",")[0] ? "true" : "false"
}">
<ContractId/>
${
records[0].remark.split(",")[0]
? `<SCAC>${records[0].remark
.split(",")[0]
.split(":")[1]
.toUpperCase()}</SCAC>`
: `<SCAC/>`
}
<Mode/>
</PriceSheet>
</PriceSheets>
`;
payload = payload.replaceAll("[priceSheet]", priceSheet);
// console.log(payload);
//await closePool();
//put the xml into a form
const formBody = querystring.stringify({
userid,
password,
request: payload,
});
axios
.post(
"https://t-insightws.mercurygate.net/MercuryGate/common/remoteService.jsp",
formBody,
{
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
}
)
.then((response) => {
//console.log(response.data)
console.log("Data was sent over to TI");
})
.catch((error) => console.error(error));
// console.log(payload);
// the order is done so we want to update the processed.
// add the new processed order to this
let notiSettingArray = notiSet.notifiySettings;
if (
!notiSettingArray[0].processed.includes(headerPending[0].releaseNumber)
) {
notiSettingArray[0].processed.push(headerPending[0].releaseNumber);
}
const { data, error } = await tryCatch(
db
.update(notifications)
.set({
lastRan: sql`NOW()`,
notifiySettings: {
...notiSettingArray,
prodID: 1,
},
})
.where(eq(notifications.name, "tiIntergration"))
);
createLog("info", "ti", "notify", "done with this order");
return { success: true, code: 0, message: "done with this order" };
};
import { createLog } from "../../../logger/logger.js";
import { tiImport } from "./tiFullFlow/tiImport.js";
// add a running check so we cant flag it twice
export let tiExportRunning = false;
export const runTiImport = async () => {
let finished = false;
let test: any;
@@ -420,14 +17,20 @@ export const runTiImport = async () => {
"info",
"ti",
"notify",
`Still more to process? ${test.code === 1 ? "No" : "Yes"}`
`Still more to process? ${test.success ? "No" : "Yes"}`
);
if (test.code === 1) {
if (test.success) {
finished = true;
}
if (!test.success) {
//errors are handled in the tiImport function
tiExportRunning = false;
}
await delay(1000 * 5);
} while (!finished);
tiExportRunning = false;
return { success: true, message: "Finished processing all data." };
};
export default tiImport;
export default runTiImport;

View File

@@ -9,10 +9,12 @@ import { createLog } from "../logger/logger.js";
import { note, notificationCreate } from "./utils/masterNotifications.js";
import { startNotificationMonitor } from "./utils/processNotifications.js";
import notifyStats from "./routes/getActiveNotifications.js";
import tiTrigger from "./routes/manualTiggerTi.js";
import blocking from "./routes/qualityBlocking.js";
const app = new OpenAPIHono();
const routes = [sendemail, notifyStats] as const;
const routes = [sendemail, notifyStats, tiTrigger, blocking] as const;
const appRoutes = routes.forEach((route) => {
app.route("/notify", route);
@@ -41,21 +43,9 @@ if (notesError) {
);
}
if (note.length != notes?.length) {
setTimeout(() => {
notificationCreate();
createLog("info", "notify", "notify", `New notifcations being added.`);
setTimeout(() => {
startNotificationMonitor();
}, 5 * 1000);
} else {
createLog(
"info",
"notify",
"notify",
`There are know new notifcations. no need to run the update. reminder all changes happen per server.`
);
setTimeout(() => {
startNotificationMonitor();
}, 5 * 1000);
}
}, 5 * 1000);
export default app;

View File

@@ -1,22 +1,26 @@
// import {Router} from "express";
// import {tiExportRunning, runTiImport} from "../../notification/notification/tiFullFlow/tiImports.js";
// an external way to creating logs
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { responses } from "../../../globalUtils/routeDefs/responses.js";
// const router = Router();
import runTiImport from "../controller/notifications/tiIntergration.js";
// router.get("/tiTrigger", async (req, res): Promise<void> => {
// if (tiExportRunning) {
// res.status(200).json({
// success: false,
// message: "There is already a current sesion of the Export running please try again later.",
// });
// }
const app = new OpenAPIHono({ strict: false });
// // trigger the import
// runTiImport();
// res.status(200).json({
// success: true,
// message: "The Ti Export has been manually started and will continue to run in the background.",
// });
// });
// export default router;
app.openapi(
createRoute({
tags: ["notify"],
summary: "Manually trigger TI intergrations.",
method: "get",
path: "/tiTrigger",
//middleware: authMiddleware,
responses: responses(),
}),
async (c) => {
const tiImport = await runTiImport();
return c.json({
success: tiImport?.success,
message: tiImport?.message,
});
}
);
export default app;

View File

@@ -0,0 +1,50 @@
// an external way to creating logs
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { responses } from "../../../globalUtils/routeDefs/responses.js";
import qualityBlockingMonitor from "../controller/notifications/qualityBlocking.js";
import { tryCatch } from "../../../globalUtils/tryCatch.js";
import { notifications } from "../../../../database/schema/notifications.js";
import { db } from "../../../../database/dbclient.js";
import { eq } from "drizzle-orm";
const app = new OpenAPIHono({ strict: false });
app.openapi(
createRoute({
tags: ["notify"],
summary: "Manually trigger TI intergrations.",
method: "get",
path: "/blockingTrigger",
//middleware: authMiddleware,
responses: responses(),
}),
async (c) => {
/**
* get the blocking notification stuff
*/
const { data, error } = await tryCatch(
db
.select()
.from(notifications)
.where(eq(notifications.name, "qualityBlocking"))
);
if (error) {
return c.json({
success: false,
message: "Error Getting Notification Settings.",
data: error,
});
}
const blocking = await qualityBlockingMonitor(data[0]);
return c.json({
success: blocking?.success,
message: blocking?.message,
});
}
);
export default app;

View File

@@ -31,7 +31,10 @@ export const note: any = [
timeType: "min",
emails: "",
active: false,
notifiySettings: { prodID: 1, sentBlockingOrders: [1] },
notifiySettings: {
prodID: 1,
sentBlockingOrders: [{ timeStamp: "0", blockingOrder: 1 }],
},
},
{
name: "productionCheck",
@@ -72,8 +75,8 @@ export const note: any = [
notifiySettings: {
prodID: 1,
start: 36,
end: 720,
releases: [1, 2, 3],
end: 36,
releases: [{ timeStamp: "0", releaseNumber: 1 }],
},
},
{
@@ -86,7 +89,7 @@ export const note: any = [
notifiySettings: {
prodID: 1,
start: 36,
end: 720,
end: 36,
releases: [1, 2, 3],
},
},
@@ -98,7 +101,14 @@ export const notificationCreate = async () => {
const notify = await db
.insert(notifications)
.values(note[i])
.onConflictDoNothing();
.onConflictDoUpdate({
target: notifications.name,
set: {
name: note[i].name,
description: note[i].description,
//notifiySettings: note[i].notifiySettings,
},
});
} catch (error) {
createLog(
"error",
@@ -110,4 +120,10 @@ export const notificationCreate = async () => {
);
}
}
createLog(
"info",
"lst",
"nofity",
"notifications were just added/updated due to server startup"
);
};

View File

@@ -43,24 +43,44 @@ export const startNotificationMonitor = async () => {
if (
!note.active ||
note.emails === "" ||
// note.emails === "" ||
runningNotifications[note.name]
) {
//console.log(`Skipping ${note.name} hes already scheduled`);
continue;
}
if (!runningNotifications[note.name] && note.active) {
createLog(
"info",
"notify",
"notify",
`${note.name} Is active and not already running.`
);
}
let time = `*/30 * * * *`; // default to be every 30 min
if (note.timeType === "min") {
console.log(`Creating the min mark here`);
//console.log(`Creating the min mark here`);
const totalMinutes = note.checkInterval;
if (note.checkInterval > 60) {
const hours = Math.floor(totalMinutes / 60); // 1 hour
const minutes = totalMinutes % 60; // 45 minutes
time = `*/${minutes} */${hours} * * *`;
} else {
time = `*/${note.checkInterval} * * * *`;
}
}
if (note.timeType === "hour") {
console.log(`Creating the hour mark here`);
const totalHours = note.checkInterval;
if (note.checkInterval > 60) {
const days = Math.floor(totalHours / 24); // 1 hour
const hours = totalHours % 24; // 45 minutes
time = `* */${hours} */${days} * *`;
} else {
time = `* */${note.checkInterval} * * *`;
}
}
createJob(note.name, time, async () => {
try {

View File

@@ -1,6 +1,3 @@
import { db } from "../../../../database/dbclient.js";
import { settings } from "../../../../database/schema/settings.js";
import { tryCatch } from "../../../globalUtils/tryCatch.js";
import type { User } from "../../../types/users.js";
import { alplaStockInv } from "./cycleCount/alplaStockInventory.js";
import { emptyCount } from "./cycleCount/emptyCycleCount.js";

View File

@@ -1,6 +1,6 @@
import { eq, gte, sql } from "drizzle-orm";
import { db } from "../../../../../database/dbclient.js";
import { printers } from "../../../../../database/schema/printers.js";
import { printerData } from "../../../../../database/schema/printers.js";
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
import { createLog } from "../../../logger/logger.js";
import { prodEndpointCreation } from "../../../../globalUtils/createUrl.js";
@@ -15,8 +15,8 @@ export const createLabel = async (data: any, userPrinted: any) => {
const { data: printer, error: printerError } = await tryCatch(
db
.select()
.from(printers)
.where(eq(printers.humanReadableId, data.printerID))
.from(printerData)
.where(eq(printerData.humanReadableId, data.printerID))
);
const { data: settingsData, error: settingsError } = await tryCatch(
db.select().from(settings)

View File

@@ -1,12 +1,10 @@
import { db } from "../../../../../database/dbclient.js";
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
import { printers } from "../../../../../database/schema/printers.js";
import { printerData } from "../../../../../database/schema/printers.js";
export const getPrinters = async () => {
const currentTime = new Date(Date.now());
const { data: printerData, error: printerError } = await tryCatch(
db.select().from(printers)
const { data: printers, error: printerError } = await tryCatch(
db.select().from(printerData)
);
if (printerError) {
@@ -17,5 +15,5 @@ export const getPrinters = async () => {
};
}
return { success: true, message: "Printers", data: printerData };
return { success: true, message: "Printers", data: printers };
};

View File

@@ -0,0 +1,20 @@
import { getPrinters } from "./getPrinters.js";
export const printerCycle = async () => {
/**
* We will cycle through the printers to check there states.
*/
let printers = await getPrinters();
/**
* if the last timeprinted would be greater than x well just change the status to idle and extended based on the 2 times.
*
* to get a printer going again label will need to come from the front end as that will just unpause the printer and start the labeling, or the api for manual print
* well need to adjust this to actually print the label then unpause it.
*
* it will be
*
* less than x since time printed run the printer status
* greater than x but less than y change the status to idle, but ping to make sure its online,
* if greater than y change to extended idle but stil also ping to make sure its online.
*/
};

View File

@@ -1,6 +1,5 @@
import { printers } from "../../../../../database/schema/printers.js";
import axios from "axios";
import { printerData } from "../../../../../database/schema/printers.js";
import { sql } from "drizzle-orm";
import { prodEndpointCreation } from "../../../../globalUtils/createUrl.js";
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
@@ -47,10 +46,10 @@ export const updatePrinters = async () => {
};
const { data, error } = await tryCatch(
db
.insert(printers)
.insert(printerData)
.values(printerStuff)
.onConflictDoUpdate({
target: printers.humanReadableId,
target: printerData.humanReadableId,
set: {
//humanReadableId: prodPrinterInfo[i].humanReadableId,
name: prodPrinterInfo[i].name,

View File

@@ -0,0 +1,87 @@
import { delay } from "../../../globalUtils/delay.js";
import { tryCatch } from "../../../globalUtils/tryCatch.js";
import { getLots } from "../controller/lots/lots.js";
import { getPrinters } from "../controller/printers/getPrinters.js";
export const assignedPrinters = async () => {
const { data: l, error: lotError } = await tryCatch(getLots());
if (lotError) {
return {
success: false,
message: "Error getting lots",
data: lotError,
};
}
const { data: print, error: printerError } = await tryCatch(getPrinters());
if (printerError) {
return {
success: false,
message: "Error getting lots",
data: printerError,
};
}
const printers: any = print;
const lots: any = l;
for (let i = 0; i < printers.data.length; i++) {
// is the printer assinged in alplalabel online?
const assigned = lots.data.filter(
(p: any) => p.printerID === printers[i].humanReadableId
);
let assignedPrinter = false;
// if true update the assigned field to true
if (assigned.length >= 1) {
assignedPrinter = true;
}
// if the last time printed is greater than 5 min change the status to 10
// const lastTime = new Date(printers[i].lastTimePrinted);
// let status = printers[i].status;
// let statusText = printers[i].statusText;
// // states we consider idle
// const printerStateCheck = [1, 2, 3, 4, 5, 6, 10];
// if (
// differenceInMinutes(currentTime, lastTime) >= 60 &&
// printerStateCheck.includes(printers[i].status) &&
// printers[i].assigned
// ) {
// createLog(
// "printerState",
// "info",
// `${printers[i].name} has been idle for more than 60 min, doing a heartbeat check`
// );
// status = 11;
// statusText = "idle";
// // printerState({printerCheck: printers[i]});
// } else if (differenceInMinutes(currentTime, lastTime) > 5 && printers[i].status === 7) {
// createLog(
// "printerState",
// "info",
// `${printers[i].name} has been errored for more 5 min changing to idle until, until it gets checked at the hour heartbeat.`
// );
// status = 10;
// statusText = "idle";
// }
// const updatePrinter = await prisma.printers.update({
// where: {
// humanReadableId: printers[i].humanReadableId,
// },
// data: {
// assigned: assignedPrinter,
// // status,
// // statusText,
// upd_date: new Date(Date.now()).toISOString(),
// },
// });
//delaying 250ms
await delay(250);
}
};

View File

@@ -0,0 +1,52 @@
import net from "net";
import { createLog } from "../../logger/logger.js";
export const pausePrinter = async (printerData: any) => {
const pause = new net.Socket();
if (printerData.name) {
createLog(
"debug",
"printerState",
"ocp",
`${printerData.name}: paused printed`
);
} else {
createLog(
"error",
"printerState",
"ocp",
`Unknown name on printer was just paused, Body sent over: ${printerData.name}`
);
}
return new Promise((resolve, reject) => {
pause.connect(printerData.port, printerData.ipAddress, async () => {
// console.log("Connected to printer");
pause.write("~PP");
pause.end();
});
pause.on("error", (error) => {
createLog(
"error",
"printerState",
"ocp",
`There was an error pausing the printer: ${JSON.stringify(
error
)}`
);
reject({
success: true,
message: "There was an error pausing the printer",
data: error,
});
});
resolve({
success: true,
message: `${
printerData?.name || printerData.ipAddress
} Printer was paused`,
});
});
};

View File

@@ -0,0 +1,55 @@
import net from "net";
import { createLog } from "../../logger/logger.js";
export const unPausePrinter = async (printerData: any) => {
const pause = new net.Socket();
if (printerData.name) {
createLog(
"debug",
"printerState",
"ocp",
`${printerData.name}: unpaused printed`
);
} else {
createLog(
"error",
"printerState",
"ocp",
`Unknown name on printer was just unpaused, Body sent over: ${JSON.stringify(
printerData
)}`
);
}
return new Promise((resolve, reject) => {
pause.connect(printerData.port, printerData.ipAddress, async () => {
// console.log("Connected to printer");
pause.write("~PS");
pause.end();
});
pause.on("error", (error) => {
createLog(
"error",
"printerState",
"ocp",
`There was an error unpausing the printer: ${JSON.stringify(
error
)}`
);
reject({
success: true,
message: "There was an error unpausing the printer",
data: error,
});
});
resolve({
success: true,
message: `${
printerData?.name || printerData.ipAddress
} Printer was unpaused`,
});
});
};

View File

@@ -1,6 +1,9 @@
import {z, createRoute, OpenAPIHono} from "@hono/zod-openapi";
import {authMiddleware} from "../../../auth/middleware/authMiddleware.js";
import {updateServer} from "../../../../scripts/updateServers.js";
import { z, createRoute, OpenAPIHono } from "@hono/zod-openapi";
import { authMiddleware } from "../../../auth/middleware/authMiddleware.js";
import {
processAllServers,
updateServer,
} from "../../../../scripts/updateServers.js";
// Define the request body schema
const requestSchema = z.object({
@@ -13,10 +16,16 @@ const requestSchema = z.object({
// Define the response schema
const responseSchema = z.object({
message: z.string().optional(),
module_id: z.string().openapi({example: "6c922c6c-7de3-4ec4-acb0-f068abdc"}).optional(),
name: z.string().openapi({example: "Production"}).optional(),
active: z.boolean().openapi({example: true}).optional(),
roles: z.string().openapi({example: `["viewer","technician"]`}).optional(),
module_id: z
.string()
.openapi({ example: "6c922c6c-7de3-4ec4-acb0-f068abdc" })
.optional(),
name: z.string().openapi({ example: "Production" }).optional(),
active: z.boolean().openapi({ example: true }).optional(),
roles: z
.string()
.openapi({ example: `["viewer","technician"]` })
.optional(),
});
const ParamsSchema = z.object({
@@ -32,7 +41,8 @@ const ParamsSchema = z.object({
}),
});
const UpdateServer = z.object({
devDir: z.string().openapi({example: "C:\\something\\Something"}),
devDir: z.string().openapi({ example: "C:\\something\\Something" }),
all: z.boolean().optional().openapi({ example: true }),
});
const app = new OpenAPIHono();
@@ -48,30 +58,38 @@ app.openapi(
params: ParamsSchema,
body: {
content: {
"application/json": {schema: UpdateServer},
"application/json": { schema: UpdateServer },
},
},
},
responses: {
200: {
content: {
"application/json": {schema: responseSchema},
"application/json": { schema: responseSchema },
},
description: "Response message",
},
400: {
content: {
"application/json": {schema: responseSchema},
"application/json": { schema: responseSchema },
},
description: "Response message",
},
},
}),
async (c) => {
const {server} = c.req.valid("param");
const { server } = c.req.valid("param");
const body = await c.req.json();
// fire off the update we wont make this way
if (body.all) {
const update = await processAllServers(body.devDir);
return c.json({
success: update?.success ?? false,
message: update?.message,
data: [],
});
}
try {
const update = await updateServer(body.devDir, server);

View File

@@ -13,7 +13,8 @@ import { serversCheckPoint } from "./utils/serverData.js";
import getServers from "./route/servers/getServers.js";
import updateServer from "./route/updates/updateServer.js";
import { setPerms } from "./utils/testServerPerms.js";
import serviceControl from './route/servers/serverContorl.js'
import serviceControl from "./route/servers/serverContorl.js";
import { areSubModulesIn } from "./utils/subModuleCheck.js";
// making sure all modules are in properly
setTimeout(async () => {
@@ -21,6 +22,7 @@ setTimeout(async () => {
await areModulesIn();
await serversCheckPoint();
await setPerms();
await areSubModulesIn();
}, 5000);
const app = new OpenAPIHono();
@@ -36,7 +38,7 @@ const routes = [
// serverData
getServers,
updateServer,
serviceControl
serviceControl,
] as const;
// app.route("/server", modules);

View File

@@ -20,7 +20,12 @@ export const serversCheckPoint = async () => {
const serverData = JSON.parse(data);
servers = serverData.servers;
} catch (err) {
console.error("Error reading JSON file:", err);
createLog(
"error",
"server",
"server",
`Error reading JSON file: ${JSON.stringify(err)}`
);
}
// get the roles

View File

@@ -0,0 +1,177 @@
/**
* check if the modules are in and if not add them.
* this will only run on a server start up
*/
import { db } from "../../../../database/dbclient.js";
import { subModules } from "../../../../database/schema/subModules.js";
import { createLog } from "../../logger/logger.js";
// "view", "technician", "supervisor","manager", "admin", "systemAdmin"
const newSubModules = [
{
name: "Silo Adjustmnet",
moduleName: "logistics",
description: "Do a silo adjustmnet",
link: "/sa",
icon: "Cylinder",
active: false,
roles: ["tester", "systemAdmin"],
subSubModule: [],
},
{
name: "Bulk orders",
moduleName: "logistics",
description: "",
link: "#",
icon: "Truck",
role: ["systemAdmin"],
active: false,
subSubModule: [],
},
{
name: "Forecast",
moduleName: "logistics",
description: "",
link: "#",
icon: "Truck",
role: ["systemAdmin"],
active: false,
subSubModule: [],
},
{
name: "Ocme cycle counts",
moduleName: "logistics",
description: "",
link: "#",
icon: "Package",
role: ["technician", "supervisor", "manager", "admin", "systemAdmin"],
active: false,
subSubModule: [],
},
{
name: "Material Helper",
moduleName: "logistics",
description: "",
link: "/materialHelper/consumption",
icon: "Package",
role: ["technician", "supervisor", "manager", "admin", "systemAdmin"],
active: false,
subSubModule: [],
},
{
name: "Ocme Cyclecount",
moduleName: "logistics",
description: "",
link: "/cyclecount",
icon: "Package",
role: ["technician", "supervisor", "manager", "admin", "systemAdmin"],
active: false,
subSubModule: [],
},
// admin module
{
name: "Servers",
moduleName: "admin",
description: "Do a silo adjustmnet",
link: "/servers",
icon: "Server",
roles: ["tester", "systemAdmin"],
isActive: true,
subSubModule: [],
},
{
name: "Admin",
moduleName: "admin",
description: "Do a silo adjustmnet",
link: "#", // when link is # this will mean its a button
icon: "ShieldCheck",
active: true,
roles: ["tester", "systemAdmin"],
subSubModule: [
{
name: "Settings",
link: "/settings",
icon: "Settings",
newWindow: false,
isActive: true,
},
{
name: "Modules",
link: "/modules",
icon: "Settings",
newWindow: false,
isActive: false,
},
{
name: "Swagger",
link: "#",
icon: "Webhook",
newWindow: false,
isActive: true,
},
{
name: "Logs",
link: "#",
icon: "Logs",
newWindow: false,
isActive: false,
},
{
name: "Users",
link: "/users",
icon: "Users",
newWindow: false,
isActive: true,
},
{
name: "UCD",
link: "https://ucd.alpla.net:8443/",
icon: "Atom",
newWindow: false,
isActive: true,
},
{
name: "Lst Api",
link: "/api/docs",
icon: "Webhook",
newWindow: false,
isActive: true,
},
],
},
];
export const areSubModulesIn = async () => {
try {
for (let i = 0; i < newSubModules.length; i++) {
const subModuleUpdate = await db
.insert(subModules)
.values(newSubModules[i])
.onConflictDoUpdate({
target: subModules.name,
set: {
name: newSubModules[i].name,
moduleName: newSubModules[i].moduleName,
description: newSubModules[i].description,
roles: newSubModules[i].roles,
link: newSubModules[i].link,
subSubModule: newSubModules[i].subSubModule,
},
}) // this will only update the ones that are new :D
.returning({ name: subModules.name });
}
createLog(
"info",
"lst",
"server",
"SubModules were just added due to missing them on server startup"
);
} catch (error) {
createLog(
"error",
"lst",
"server",
"There was an error adding new subModules to the db"
);
}
};

View File

@@ -0,0 +1,45 @@
export const customerInvNoHold = `
select x.idartikelVarianten as av
,ArtikelVariantenAlias as Alias
--x.Lfdnr as RunningNumber,
--,round(sum(EinlagerungsMengeVPKSum),0) as Total_Pallets
--,sum(EinlagerungsMengeSum) as Total_PalletQTY
,round(sum(VerfuegbareMengeVPKSum),0) as Avalible_Pallets
,sum(VerfuegbareMengeSum) as Avaliable_PalletQTY
,sum(case when c.Description LIKE '%COA%' then GesperrteMengeVPKSum else 0 end) as COA_Pallets
,sum(case when c.Description LIKE '%COA%' then GesperrteMengeSum else 0 end) as COA_QTY
--,sum(case when c.Description NOT LIKE '%COA%' then GesperrteMengeVPKSum else 0 end) as Held_Pallets
--,sum(case when c.Description NOT LIKE '%COA%' then GesperrteMengeSum else 0 end) as Held_QTY
,IdProdPlanung as Lot
--,IdAdressen
--,x.AdressBez
--,*
from [AlplaPROD_test1].dbo.[V_LagerPositionenBarcodes] (nolock) x
left join
[AlplaPROD_test1].dbo.T_EtikettenGedruckt (nolock) on
x.Lfdnr = T_EtikettenGedruckt.Lfdnr AND T_EtikettenGedruckt.Lfdnr > 1
left join
(SELECT *
FROM [AlplaPROD_test1].[dbo].[T_BlockingDefects] (nolock) where Active = 1) as c
on x.IdMainDefect = c.IdBlockingDefect
/*
The data below will be controlled by the user in excell by default everything will be passed over
IdAdressen = 3
*/
where IdArtikelTyp = 1
and x.IdWarenlager not in (6, 1)
--and IdAdressen
group by x.IdArtikelVarianten
,ArtikelVariantenAlias
,IdProdPlanung
--,c.Description
,IdAdressen
,x.AdressBez
--, x.Lfdnr
order by x.IdArtikelVarianten
`;

View File

@@ -0,0 +1,27 @@
export const openOrders = `
Select LEFT(ArtikelVariantenAlias, charindex(' ', ArtikelVariantenAlias) - 1) customerItemNumber,
x.IdArtikelVarianten AS article,
ArtikelVariantenAlias AS articleDescription,
IdAuftragsAbruf as releaseNumber,
AuftragsNummer AS header,
AuftragsNummer as customerLineItemNo,
AbrufNummer AS customerReleaseNumber,
AbrufMengeVPK AS pallets,
AbrufMenge AS qty,
y.TradeUnits AS cartons,
IdAdresse AS customerID,
LieferAdressBez as DeliveryAddressDescription,
AbrufLadeDatum AS loadingDate,
AbrufLiefertermin AS deliveryDate
--,OrderStatus = 'loading'
--,*
FROM alplaprod_test1.dbo.V_TrackerAuftragsAbrufe (nolock) x
left join
[test1_AlplaPROD2.0_Read].[order].[Release] (nolock) y on
x.IdAuftragsAbruf = y.ReleaseNumber
--WHERE AbrufStatus = 1 AND AbrufLiefertermin < getdate() + 5 AND GelieferteMenge = 0
WHERE AbrufStatus = 1 AND AbrufLiefertermin between getDate() + -[sDay] and getdate() + [eDay] AND GelieferteMenge = 0
ORDER BY AbrufLiefertermin
`;

View File

@@ -0,0 +1,45 @@
export const blockQuery = `
SELECT
'Alert! new blocking order: #' + cast(HumanReadableId as varchar) + ' - ' + ArticleVariantDescription as subject,
cast([HumanReadableId] as varchar) as blockingNumber,
[ArticleVariantDescription] as article,
cast([CustomerHumanReadableId] as varchar) + ' - ' + [CustomerDescription] as customer,
convert(varchar(10), [test1_AlplaPROD2.0_Reporting].[reporting_blocking].[BlockingOrder].[BlockingDate], 101) + ' - ' + convert(varchar(5), [test1_AlplaPROD2.0_Reporting].[reporting_blocking].[BlockingOrder].[BlockingDate], 108) as blockingDate,
cast(ArticleVariantHumanReadableId as varchar) + ' - ' + ArticleVariantDescription as av,
case when [test1_AlplaPROD2.0_Reporting].[reporting_blocking].[BlockingOrder].Remark = '' or [test1_AlplaPROD2.0_Reporting].[reporting_blocking].[BlockingOrder].Remark is NULL then 'Please reach out to quality for the reason this was placed on hold as a remark was not entered during the blocking processs' else [test1_AlplaPROD2.0_Reporting].[reporting_blocking].[BlockingOrder].Remark end as remark,
cast(FORMAT(TotalAmountOfPieces, '###,###') as varchar) + ' / ' + cast(LoadingUnit as varchar) as peicesAndLoadingUnits,
[test1_AlplaPROD2.0_Reporting].[reporting_blocking].[BlockingOrder].ProductionLotHumanReadableId as lotNumber,
cast(IdGlobalBlockingDefectsGroup as varchar) + ' - ' + BD.Description as mainDefectGroup,
cast(IdGlobalBlockingDefect as varchar) + ' - ' + MD.Description as mainDefect,
sent=0,
lot.MachineLocation as line,
HumanReadableId
FROM [test1_AlplaPROD2.0_Reporting].[reporting_blocking].[BlockingOrder] (nolock)
/*** Join 1.0 table to get correct id info to link ***/
join
[AlplaPROD_test1].[dbo].[T_BlockingOrders] (nolock) AS BO
on [HumanReadableId] = BO.[IdBlockingOrder]
/*** Get the main defect info ***/
Inner join
[AlplaPROD_test1].[dbo].[T_BlockingDefectsGroups] (nolock) as BD
ON BO.IdMainDefectGroup = BD.IdBlockingDefectsGroup
INNER join
[AlplaPROD_test1].[dbo].[T_BlockingDefects] as MD
ON BO.IdMainDefect = MD.IdBlockingDefect
/*** get lot info ***/
left join
(SELECT [MachineLocation]
,[MachineDescription]
,[ProductionLotHumanReadableId]
FROM [test1_AlplaPROD2.0_Reporting].[reporting_productionControlling].[ProducedLot]) as lot
on [test1_AlplaPROD2.0_Reporting].[reporting_blocking].[BlockingOrder].ProductionLotHumanReadableId = lot.ProductionLotHumanReadableId
where [test1_AlplaPROD2.0_Reporting].[reporting_blocking].[BlockingOrder].[BlockingDate] between getdate() - 1 and getdate() + 1
and [test1_AlplaPROD2.0_Reporting].[reporting_blocking].[BlockingOrder].BlockingTrigger = 1
and HumanReadableId NOT IN ([sentBlockingOrders])
`;