Compare commits

...

32 Commits

Author SHA1 Message Date
6665b77e09 feat(cyclecountcheck): added i cycle count check this is in mem right now
if this becomes a resource hog we will move it to the db. no need for it to really be presitant
2025-04-09 17:50:06 -05:00
2e2699ab3c refactor(ocp): change the way logs are brought in and other changes to clean the code up 2025-04-09 17:49:03 -05:00
bad390ec17 feat(silo): added in charts and historical data 2025-04-09 17:48:03 -05:00
efc630f5f8 refactor(auth): added module and submodule access to the user 2025-04-09 17:47:02 -05:00
ded074a1ce refactor(serverpage): added in linke to server by clicking the name 2025-04-09 17:46:12 -05:00
ca0b027e67 refactor(database): removed the createAt as it was a duplicate 2025-04-09 17:45:39 -05:00
1282f5efe4 ci(release): bump build number to 207 2025-04-09 14:05:37 -05:00
77988477f6 ci(release): bump build number to 206 2025-04-09 13:17:17 -05:00
37b26c4c92 ci(release): bump build number to 205 2025-04-09 13:00:20 -05:00
72e2c6ea6a ci(release): bump build number to 204 2025-04-09 12:49:17 -05:00
ffe80d6a58 ci(release): bump build number to 203 2025-04-09 12:31:25 -05:00
9dcd07bf2a ci(release): bump build number to 202 2025-04-09 12:26:47 -05:00
4a36107ebb ci(release): bump build number to 201 2025-04-09 12:15:02 -05:00
fb03fc83e6 ci(release): bump build number to 200 2025-04-09 12:13:28 -05:00
8c522c5b72 ci(release): bump build number to 199 2025-04-09 11:49:22 -05:00
e9c9a84a82 ci(release): bump build number to 198 2025-04-09 11:25:55 -05:00
ff2ecff146 ci(release): bump build number to 197 2025-04-09 08:28:03 -05:00
3757b367d5 ci(release): bump build number to 196 2025-04-09 08:24:14 -05:00
4d979089cb ci(release): bump build number to 195 2025-04-08 21:07:26 -05:00
b1e611c7b8 ci(release): bump build number to 194 2025-04-08 21:05:08 -05:00
02fdc14769 ci(release): bump build number to 193 2025-04-08 21:03:11 -05:00
a794943740 ci(release): bump build number to 192 2025-04-08 21:01:20 -05:00
c2ad046fb0 ci(release): bump build number to 191 2025-04-08 20:56:40 -05:00
ba2b8036b8 ci(release): bump build number to 190 2025-04-08 20:36:42 -05:00
26aa9d8f80 ci(release): bump build number to 189 2025-04-08 20:30:12 -05:00
663f2f436c ci(release): bump build number to 188 2025-04-08 19:26:01 -05:00
88f05eaf65 ci(release): bump build number to 187 2025-04-08 17:36:30 -05:00
b84d6f5186 ci(release): bump build number to 186 2025-04-08 17:32:57 -05:00
410790e693 ci(release): bump build number to 185 2025-04-08 16:00:46 -05:00
f847ce423d ci(release): bump build number to 184 2025-04-08 13:42:46 -05:00
27126cca35 ci(release): bump build number to 183 2025-04-08 11:11:09 -05:00
04f524419d ci(release): bump build number to 182 2025-04-08 11:02:14 -05:00
54 changed files with 1476 additions and 453 deletions

View File

@@ -1,6 +1,15 @@
import {text, pgTable, numeric, index, timestamp, boolean, uuid, uniqueIndex} from "drizzle-orm/pg-core"; import {
import {createInsertSchema, createSelectSchema} from "drizzle-zod"; text,
import {z} from "zod"; pgTable,
numeric,
index,
timestamp,
boolean,
uuid,
uniqueIndex,
} from "drizzle-orm/pg-core";
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
import { z } from "zod";
export const logs = pgTable( export const logs = pgTable(
"logs", "logs",
@@ -11,7 +20,7 @@ export const logs = pgTable(
service: text("service").notNull().default("system"), service: text("service").notNull().default("system"),
message: text("message").notNull(), message: text("message").notNull(),
checked: boolean("checked").default(false), checked: boolean("checked").default(false),
checkedAt: timestamp("checkedAt"), //checkedAt: timestamp("checkedAt"),
created_at: timestamp("add_Date").defaultNow(), created_at: timestamp("add_Date").defaultNow(),
}, },
(table) => [ (table) => [

View File

@@ -33,6 +33,7 @@ export type Servers = {
idAddress: string; idAddress: string;
lastUpdated: string; lastUpdated: string;
isUpgrading: boolean; isUpgrading: boolean;
lstServerPort: string;
}; };
export default function ServerPage() { export default function ServerPage() {
@@ -144,7 +145,12 @@ export default function ServerPage() {
return ( return (
<TableRow key={server.server_id}> <TableRow key={server.server_id}>
<TableCell className="font-medium"> <TableCell className="font-medium">
{server.sName} <a
href={`http://${server.serverDNS}:${server.lstServerPort}`}
target={"_blank"}
>
<span>{server.sName}</span>
</a>
</TableCell> </TableCell>
<TableCell className="font-medium"> <TableCell className="font-medium">
{server.serverDNS} {server.serverDNS}

View File

@@ -1,9 +1,3 @@
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
import { getUsers } from "@/utils/querys/admin/users"; import { getUsers } from "@/utils/querys/admin/users";
import { useQuery } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query";
import UserCard from "./components/UserCard"; import UserCard from "./components/UserCard";
@@ -22,22 +16,13 @@ export default function UserPage() {
return ( return (
<div className="m-2 w-dvw"> <div className="m-2 w-dvw">
<Accordion type="single" collapsible> {data.map((u: any) => {
{data.map((u: any) => { return (
return ( <div>
<AccordionItem key={u.user_id} value={u.user_id}> <UserCard user={u} />
<AccordionTrigger> </div>
<span>{u.username}</span> );
</AccordionTrigger> })}
<AccordionContent>
<div>
<UserCard user={u} />
</div>
</AccordionContent>
</AccordionItem>
);
})}
</Accordion>
</div> </div>
); );
} }

View File

@@ -19,11 +19,13 @@ export default function ModuleAccess(data: any) {
<div className="flex flex-row flex-wrap"> <div className="flex flex-row flex-wrap">
{modules?.map((m: any) => { {modules?.map((m: any) => {
return ( return (
<ModuleForm <div key={m.module_id}>
key={m.module_id} <ModuleForm
i={m} module={m}
username={data.user.username} user={data.user}
/> refetch={data.refetch}
/>
</div>
); );
})} })}
</div> </div>

View File

@@ -1,4 +1,3 @@
import { LstCard } from "@/components/extendedUI/LstCard";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import { import {
@@ -10,21 +9,26 @@ import {
SelectTrigger, SelectTrigger,
SelectValue, SelectValue,
} from "@/components/ui/select"; } from "@/components/ui/select";
import { getUserRoles } from "@/utils/querys/admin/userRoles";
import { useForm } from "@tanstack/react-form"; import { useForm } from "@tanstack/react-form";
import { useQuery } from "@tanstack/react-query";
import axios from "axios"; import axios from "axios";
import { toast } from "sonner"; import { toast } from "sonner";
export default function ModuleForm(props: any) { export default function ModuleForm(props: any) {
const { refetch } = useQuery(getUserRoles());
const token = localStorage.getItem("auth_token"); const token = localStorage.getItem("auth_token");
const role =
props.user?.moduleRoles?.filter(
(m: any) => m.module_id === props.module.module_id
)[0]?.role ?? " ";
const form = useForm({ const form = useForm({
defaultValues: { role: props.i.role }, defaultValues: {
role: role,
},
onSubmit: async ({ value }) => { onSubmit: async ({ value }) => {
const data = { const data: any = {
username: props.username, username: props.user.username,
module: props.i.name, module: props.module.name,
role: value.role, role: value.role,
}; };
console.log(data); console.log(data);
@@ -37,7 +41,7 @@ export default function ModuleForm(props: any) {
if (res.data.success) { if (res.data.success) {
toast.success(res.data.message); toast.success(res.data.message);
refetch(); props.refetch();
form.reset(); form.reset();
} else { } else {
res.data.message; res.data.message;
@@ -49,71 +53,67 @@ export default function ModuleForm(props: any) {
}); });
return ( return (
<div className="m-2 p-1"> <div className="">
<LstCard> <form
<p className="text-center">Module: {props.i.name}</p> onSubmit={(e) => {
e.preventDefault();
<p className="p-1">Current role: </p> e.stopPropagation();
<form }}
onSubmit={(e) => { className="flex flex-row"
e.preventDefault(); >
e.stopPropagation(); <form.Field
name="role"
//listeners={{onChange: ({value})=>{}}}
children={(field) => {
return (
<div className="m-2 min-w-48 max-w-96 p-2">
<Label htmlFor={field.name}>
Module: {props.module.name}
</Label>
<Select
value={field.state.value}
onValueChange={field.handleChange}
>
<SelectTrigger className="w-[180px]">
<SelectValue
id={field.name}
placeholder="Select Role"
/>
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>Roles</SelectLabel>
<SelectItem value="viewer">
Viewer
</SelectItem>
<SelectItem value="technician">
Technician
</SelectItem>
<SelectItem value="supervisor">
Supervisor
</SelectItem>
<SelectItem value="manager">
Manager
</SelectItem>
<SelectItem value="tester">
Tester
</SelectItem>
<SelectItem value="admin">
Admin
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
);
}} }}
> />
<form.Field <div className="mt-4">
name="role" <Button type="submit" onClick={form.handleSubmit}>
//listeners={{onChange: ({value})=>{}}} Save
children={(field) => { </Button>
return ( </div>
<div className="m-2 min-w-48 max-w-96 p-2"> </form>
<Label htmlFor={field.name}>
Select role
</Label>
<Select
value={field.state.value}
onValueChange={field.handleChange}
>
<SelectTrigger className="w-[180px]">
<SelectValue
id={field.name}
placeholder="Select Role"
/>
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>Roles</SelectLabel>
<SelectItem value="viewer">
Viewer
</SelectItem>
<SelectItem value="technician">
Technician
</SelectItem>
<SelectItem value="supervisor">
Supervisor
</SelectItem>
<SelectItem value="manager">
Manager
</SelectItem>
<SelectItem value="tester">
Tester
</SelectItem>
<SelectItem value="admin">
Admin
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
);
}}
/>
<div className="mt-4">
<Button type="submit" onClick={form.handleSubmit}>
Save
</Button>
</div>
</form>
</LstCard>
</div> </div>
); );
} }

View File

@@ -22,13 +22,12 @@ import axios from "axios";
import { toast } from "sonner"; import { toast } from "sonner";
import { CardHeader } from "@/components/ui/card"; import { CardHeader } from "@/components/ui/card";
import ModuleAccess from "./ModuleAccess";
export default function UserCard(data: any) { export default function UserCard(data: any) {
const token = localStorage.getItem("auth_token"); const token = localStorage.getItem("auth_token");
const { refetch } = useQuery(getUsers()); const { refetch } = useQuery(getUsers());
//console.log(modules);
//console.log(data.user);
//console.log(userRoles); //console.log(userRoles);
const form = useForm({ const form = useForm({
...userFormOptions(data.user), ...userFormOptions(data.user),
@@ -268,13 +267,17 @@ export default function UserCard(data: any) {
); );
}} }}
/> />
<div className="mt-4 ml-4">
<Button onClick={form.handleSubmit}>Save</Button>
</div>
</form> </form>
</LstCard> </LstCard>
<div className="mt-4">
<Button onClick={form.handleSubmit}>Save</Button>
</div>
</div> </div>
<div className="flex flex-col"></div> <div>
<LstCard>
<ModuleAccess user={data.user} refetch={refetch} />
</LstCard>
</div>
</div> </div>
); );
} }

View File

@@ -1,19 +1,24 @@
import {Sidebar, SidebarContent, SidebarFooter, SidebarTrigger} from "../ui/sidebar"; import {
import {ProductionSideBar} from "./side-components/production"; Sidebar,
import {Header} from "./side-components/header"; SidebarContent,
import {LogisticsSideBar} from "./side-components/logistics"; SidebarFooter,
import {QualitySideBar} from "./side-components/quality"; SidebarTrigger,
import {ForkliftSideBar} from "./side-components/forklift"; } from "../ui/sidebar";
import {EomSideBar} from "./side-components/eom"; import { ProductionSideBar } from "./side-components/production";
import {AdminSideBar} from "./side-components/admin"; import { Header } from "./side-components/header";
import {useSessionStore} from "../../lib/store/sessionStore"; import { LogisticsSideBar } from "./side-components/logistics";
import {hasAccess} from "../../utils/userAccess"; import { QualitySideBar } from "./side-components/quality";
import {moduleActive} from "../../utils/moduleActive"; import { ForkliftSideBar } from "./side-components/forklift";
import {useModuleStore} from "../../lib/store/useModuleStore"; import { EomSideBar } from "./side-components/eom";
import { AdminSideBar } from "./side-components/admin";
import { useSessionStore } from "../../lib/store/sessionStore";
import { hasAccess } from "../../utils/userAccess";
import { moduleActive } from "../../utils/moduleActive";
import { useModuleStore } from "../../lib/store/useModuleStore";
export function AppSidebar() { export function AppSidebar() {
const {user} = useSessionStore(); const { user } = useSessionStore();
const {modules} = useModuleStore(); const { modules } = useModuleStore();
return ( return (
<Sidebar collapsible="icon"> <Sidebar collapsible="icon">
@@ -22,19 +27,31 @@ export function AppSidebar() {
{moduleActive("production") && ( {moduleActive("production") && (
<ProductionSideBar <ProductionSideBar
user={user} user={user}
moduleID={modules.filter((n) => n.name === "production")[0].module_id as string} moduleID={
modules.filter((n) => n.name === "production")[0]
.module_id as string
}
/> />
)} )}
{moduleActive("logistics") && ( {moduleActive("logistics") && (
<LogisticsSideBar <LogisticsSideBar
user={user} user={user}
moduleID={modules.filter((n) => n.name === "logistics")[0].module_id as string} moduleID={
modules.filter((n) => n.name === "logistics")[0]
.module_id as string
}
/> />
)} )}
{moduleActive("forklift") && hasAccess(user, "forklift", modules) && <ForkliftSideBar />} {moduleActive("forklift") &&
{moduleActive("eom") && hasAccess(user, "eom", modules) && <EomSideBar />} hasAccess(user, "forklift", modules) && <ForkliftSideBar />}
{moduleActive("quality") && hasAccess(user, "quality", modules) && <QualitySideBar />} {moduleActive("eom") && hasAccess(user, "eom", modules) && (
{moduleActive("admin") && hasAccess(user, "admin", modules) && <AdminSideBar />} <EomSideBar />
)}
{moduleActive("quality") &&
hasAccess(user, "quality", modules) && <QualitySideBar />}
{moduleActive("admin") && hasAccess(user, "admin", modules) && (
<AdminSideBar />
)}
</SidebarContent> </SidebarContent>
<SidebarFooter> <SidebarFooter>
<SidebarTrigger /> <SidebarTrigger />

View File

@@ -0,0 +1,113 @@
import { Area, AreaChart, CartesianGrid, XAxis } from "recharts";
import { CardContent } from "@/components/ui/card";
import {
ChartConfig,
ChartContainer,
ChartTooltip,
ChartTooltipContent,
} from "@/components/ui/chart";
import { useQuery } from "@tanstack/react-query";
import { getAdjustments } from "@/utils/querys/logistics/siloAdjustments/getAdjustments";
import { LstCard } from "@/components/extendedUI/LstCard";
import { format } from "date-fns";
export default function ChartData(props: any) {
const { data, isError, isLoading } = useQuery(getAdjustments());
const chartConfig = {
stock: {
label: "Stock",
color: "rgb(255, 99, 132)",
},
actual: {
label: "Actual",
color: "rgb(53, 162, 235)",
},
} satisfies ChartConfig;
if (isLoading) return <div>Loading chart data</div>;
if (isError) return <div>Error in loading chart data</div>;
let adjustments: any = data.filter(
(l: any) => l.locationID === props.laneId
);
adjustments = adjustments.splice(0, 10).map((s: any) => {
return {
date: format(s.dateAdjusted.replace("Z", ""), "M/d/yyyy hh:mm"),
stock: s.currentStockLevel,
actual: s.newLevel,
};
});
return (
<LstCard className="w-[425px] h-[250px] m-1">
<CardContent>
{adjustments.length === 0 ? (
<span>No silo data has been entered for this silo.</span>
) : (
<ChartContainer config={chartConfig}>
<AreaChart
accessibilityLayer
data={adjustments}
margin={{
left: 35,
right: 45,
bottom: 50,
}}
>
<CartesianGrid vertical={false} />
<XAxis
dataKey="date"
tickLine={false}
axisLine={false}
tickMargin={14}
angle={-45}
textAnchor="end"
dy={10}
tickFormatter={(value) =>
format(value, "M/d/yyyy")
}
/>
<ChartTooltip
cursor={false}
content={
<ChartTooltipContent indicator="dot" />
}
/>
<Area
dataKey="stock"
type="natural"
fill="rgba(53, 162, 235, 0.5)"
fillOpacity={0.4}
stroke="rgba(53, 162, 235, 0.5)"
stackId="a"
/>
<Area
dataKey="actual"
type="natural"
fill="rgba(255, 99, 132, 0.5)"
fillOpacity={0.4}
stroke="rgba(255, 99, 132, 0.5)"
stackId="a"
/>
</AreaChart>
</ChartContainer>
)}
</CardContent>
{/* <CardFooter>
<div className="flex w-full items-start gap-2 text-sm">
<div className="grid gap-2">
<div className="flex items-center gap-2 font-medium leading-none">
Trending up by 5.2% this month{" "}
<TrendingUp className="h-4 w-4" />
</div>
<div className="flex items-center gap-2 leading-none text-muted-foreground">
January - June 2024
</div>
</div>
</div>
</CardFooter> */}
</LstCard>
);
}

View File

@@ -0,0 +1,28 @@
import { getAdjustments } from "@/utils/querys/logistics/siloAdjustments/getAdjustments";
import { columns } from "@/utils/tableData/siloAdjustmentHist/siloAdjHist";
import { DataTable } from "@/utils/tableData/siloAdjustmentHist/siloDate";
import { useQuery } from "@tanstack/react-query";
export default function HistoricalData(props: any) {
const { data, isError, isLoading } = useQuery(getAdjustments());
if (isLoading) return <div>Loading adjustmnet data...</div>;
if (isError) {
return (
<div>
<p>There was an error getting the adjustments.</p>
</div>
);
}
//console.log(data[0].locationID, parseInt(props.laneId));
const adjustments: any = data.filter(
(l: any) => l.locationID === parseInt(props.laneId)
);
console.log(adjustments);
return (
<div className="container mx-auto py-10">
<DataTable columns={columns} data={adjustments} />
</div>
);
}

View File

@@ -12,11 +12,13 @@ import {
import { getStockSilo } from "@/utils/querys/logistics/siloAdjustments/getStockSilo"; import { getStockSilo } from "@/utils/querys/logistics/siloAdjustments/getStockSilo";
import { useForm } from "@tanstack/react-form"; import { useForm } from "@tanstack/react-form";
import { useQuery } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query";
import { Link } from "@tanstack/react-router";
import axios from "axios"; import axios from "axios";
import { format } from "date-fns"; import { format } from "date-fns";
import { CircleAlert } from "lucide-react"; import { CircleAlert } from "lucide-react";
import { useState } from "react"; import { useState } from "react";
import { toast } from "sonner"; import { toast } from "sonner";
import ChartData from "./ChartData";
export default function SiloCard(data: any) { export default function SiloCard(data: any) {
const token = localStorage.getItem("auth_token"); const token = localStorage.getItem("auth_token");
@@ -183,9 +185,17 @@ export default function SiloCard(data: any) {
)} )}
</div> </div>
</LstCard> </LstCard>
<div className="grow max-w-[400px]"> <div className="grow max-w-[600px]">
<LstCard className="m-1 ">charts go here</LstCard> <ChartData laneId={silo.LocationID} />
<LstCard className="m-1">extra options here</LstCard>
<div className="flex justify-end m-1">
<Link
to={"/siloAdjustments/$hist"}
params={{ hist: silo.LocationID }}
>
Historical Data
</Link>
</div>
</div> </div>
</div> </div>
</LstCard> </LstCard>

View File

@@ -12,23 +12,28 @@ import {
TableRow, TableRow,
} from "../ui/table"; } from "../ui/table";
import { toast } from "sonner"; import { toast } from "sonner";
import { getOcmeInfo } from "@/utils/querys/production/getOcmeInfo";
import { useQuery } from "@tanstack/react-query";
import { format } from "date-fns";
import { Trash } from "lucide-react";
const currentPallets = [ const currentPallets = [
{ key: "line", label: "Line" }, { key: "line", label: "Line" },
{ key: "runningNr", label: "Running #" }, { key: "runningNumber", label: "Running #" },
{ key: "upd_date", label: "Date Scanned" }, { key: "upd_date", label: "Date Scanned" },
{ key: "waitingfor", label: "Waiting For" }, { key: "waitingfor", label: "Waiting For" },
{ key: "clear", label: "Clear" }, { key: "clear", label: "Clear" },
]; ];
const currentTags = [ // const currentTags = [
{ key: "line", label: "Line" }, // { key: "line", label: "Line" },
{ key: "printerName", label: "Printer" }, // { key: "printerName", label: "Printer" },
{ key: "runningNr", label: "Running #" }, // { key: "runningNr", label: "Running #" },
{ key: "upd_date", label: "Label date" }, // { key: "upd_date", label: "Label date" },
{ key: "status", label: "Label Status" }, // { key: "status", label: "Label Status" },
]; // ];
export default function WrapperManualTrigger() { export default function WrapperManualTrigger() {
const { data, isError, isLoading } = useQuery(getOcmeInfo());
const cameraTrigger = async () => { const cameraTrigger = async () => {
try { try {
const res = await axios.get("/ocme/api/v1/manualCameraTrigger"); const res = await axios.get("/ocme/api/v1/manualCameraTrigger");
@@ -46,6 +51,42 @@ export default function WrapperManualTrigger() {
//stoast.success(error.data.message); //stoast.success(error.data.message);
} }
}; };
const clearLabel = async (d: any) => {
const data = {
runningNr: d.runningNr,
};
try {
const res = await axios.patch("/ocme/api/v1/pickedUp", data);
if (res.data.success) {
toast.success(
`${d.runningNr} was just removed from being picked up.`
);
return;
}
if (!res.data.success) {
toast.error(res.data.message);
}
} catch (error) {
console.log(error);
//stoast.success(error.data.message);
}
};
if (isError) {
return (
<div>
<p className="text-center text-pretty">
There was an error getting wrapper scans
</p>
</div>
);
}
const info = data?.filter((r: any) => r.areaFrom === "wrapper_1");
return ( return (
<LstCard className="m-2 p-2"> <LstCard className="m-2 p-2">
<ScrollArea className="max-h-[200px]"> <ScrollArea className="max-h-[200px]">
@@ -59,71 +100,66 @@ export default function WrapperManualTrigger() {
))} ))}
</TableRow> </TableRow>
</TableHeader> </TableHeader>
<TableBody> {isLoading ? (
{Array(3) <TableBody>
.fill(0) {Array(3)
.map((_, i) => ( .fill(0)
<TableRow key={i}> .map((_, i) => (
<TableRow key={i}>
<TableCell className="font-medium">
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
</TableRow>
))}
</TableBody>
) : (
<TableBody>
{info.map((i: any) => (
<TableRow key={i.runningNr}>
<TableCell className="font-medium"> <TableCell className="font-medium">
<Skeleton className="h-4" /> {i.lineNum}
</TableCell> </TableCell>
<TableCell>{i.runningNr}</TableCell>
<TableCell> <TableCell>
<Skeleton className="h-4" /> {format(
i?.upd_date.replace("Z", ""),
"M/d/yyyy hh:mm"
)}
</TableCell> </TableCell>
<TableCell>{i.waitingFor}</TableCell>
<TableCell> <TableCell>
<Skeleton className="h-4" /> <Button
</TableCell> variant="destructive"
<TableCell> size="icon"
<Skeleton className="h-4" /> onClick={() => clearLabel(i)}
</TableCell> >
<TableCell> <Trash />
<Skeleton className="h-4" /> </Button>
</TableCell> </TableCell>
</TableRow> </TableRow>
))} ))}
</TableBody> </TableBody>
</Table> )}
</ScrollArea>
<ScrollArea className="max-h-[200px]">
<Table>
<TableHeader>
<TableRow>
{currentTags.map((l) => (
<TableHead key={l.key}>{l.label}</TableHead>
))}
</TableRow>
</TableHeader>
<TableBody>
{Array(3)
.fill(0)
.map((_, i) => (
<TableRow key={i}>
<TableCell className="font-medium">
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
</TableRow>
))}
</TableBody>
</Table> </Table>
</ScrollArea> </ScrollArea>
<div> <div>
<hr /> <hr />
<p className="text-center mb-3">Manual Triggers</p> <p className="text-center mb-3">Manual Trigger</p>
<div className="flex flex-row justify-between"> <div className="flex flex-row justify-between">
<Button onClick={cameraTrigger}>Camera</Button> <Button onClick={cameraTrigger}>Camera</Button>
<Button>Rfid</Button>
</div> </div>
</div> </div>
</LstCard> </LstCard>

View File

@@ -184,7 +184,7 @@ export default function OcmeCycleCount() {
{data.map((i: any) => { {data.map((i: any) => {
let classname = ``; let classname = ``;
if ( if (
i.info === "Quality Check Required" i.info === "Validate pallet is ok."
) { ) {
classname = `bg-red-500`; classname = `bg-red-500`;
} }

View File

@@ -5,7 +5,6 @@ import {
Table, Table,
TableBody, TableBody,
TableCell, TableCell,
TableFooter,
TableHead, TableHead,
TableHeader, TableHeader,
TableRow, TableRow,
@@ -26,17 +25,13 @@ const labelLogs = [
]; ];
export default function LabelLog() { export default function LabelLog() {
const { data, isError, isLoading } = useQuery(getlabels("4")); const { data, isError, isLoading } = useQuery(getlabels("4"));
//const {user} = useSessionStore();
//const {settings} = useSettingStore();
//const server = settings.filter((n) => n.name === "server")[0]?.value || "";
//const roles = ["admin", "manager", "operator"];
if (isError) { if (isError) {
return ( return (
<div className="m-2 p-2 min-h-2/5"> <div className="m-2 p-2 min-h-2/5">
<LstCard> <LstCard>
<p className="text-center">Labels for the last 2 hours</p> <p className="text-center">Labels for the last 2 hours</p>
<Table> <Table>
<TableHeader> <TableHeader>
<TableRow> <TableRow>
@@ -77,7 +72,13 @@ export default function LabelLog() {
const labelData = data ? data : []; const labelData = data ? data : [];
return ( return (
<LstCard className="m-2 p-2 min-h-2/5"> <LstCard className="m-2 p-2 min-h-2/5">
<p className="text-center">Labels for the last 2 hours</p> <p className="text-center">
{labelData.length === 0 ? (
<span>No labels have been printed in the last 2 hours</span>
) : (
<span>Labels for the last 2 hours</span>
)}
</p>
<Table> <Table>
<TableHeader> <TableHeader>
<TableRow> <TableRow>
@@ -115,7 +116,7 @@ export default function LabelLog() {
) : ( ) : (
<TableBody> <TableBody>
{labelData.map((label: any) => ( {labelData.map((label: any) => (
<TableRow key={label.runningNr}> <TableRow key={label.label_id}>
<TableCell className="font-medium"> <TableCell className="font-medium">
{label.line} {label.line}
</TableCell> </TableCell>
@@ -139,15 +140,15 @@ export default function LabelLog() {
</TableBody> </TableBody>
)} )}
<TableFooter> {/* <TableFooter>
{labelData.length === 0 && ( {labelData.length === 0 && (
<div> <div className="flex justify-center">
<h2 className="text-center text-2xl"> <h2 className="text-center text-2xl">
No labels have been printed in the last 2 hours No labels have been printed in the last 2 hours
</h2> </h2>
</div> </div>
)} )}
</TableFooter> </TableFooter> */}
</Table> </Table>
</LstCard> </LstCard>
); );

View File

@@ -1,31 +1,43 @@
import {Button} from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import {useSessionStore} from "@/lib/store/sessionStore"; import { useSessionStore } from "@/lib/store/sessionStore";
//import {useSettingStore} from "@/lib/store/useSettings"; //import {useSettingStore} from "@/lib/store/useSettings";
import {LotType} from "@/types/lots"; import { LotType } from "@/types/lots";
import {Tag} from "lucide-react"; import { Tag } from "lucide-react";
import {toast} from "sonner"; import { toast } from "sonner";
import {manualPrintLabels} from "./ManualPrintLabel"; import { manualPrintLabels } from "./ManualPrintLabel";
import { useState } from "react";
export default function ManualPrint({lot}: {lot: LotType}) { export default function ManualPrint({ lot }: { lot: LotType }) {
const {user} = useSessionStore(); const { user } = useSessionStore();
const [printing, setPrinting] = useState(false);
//const {settings} = useSettingStore(); //const {settings} = useSettingStore();
//const server = settings.filter((n) => n.name === "server")[0]?.value; //const server = settings.filter((n) => n.name === "server")[0]?.value;
//const serverPort = settings.filter((n) => n.name === "serverPort")[0]?.value; //const serverPort = settings.filter((n) => n.name === "serverPort")[0]?.value;
//const serverUrl = `http://${server}:${serverPort}`; //const serverUrl = `http://${server}:${serverPort}`;
const handlePrintLabel = async (lot: LotType) => { const handlePrintLabel = async (lot: LotType) => {
//console.log(lot);
const labels: any = await manualPrintLabels(lot, user); const labels: any = await manualPrintLabels(lot, user);
if (labels.success) { if (labels.success) {
toast.success(labels.message); toast.success(labels.message);
setTimeout(() => {
setPrinting(false);
}, 5 * 1000);
setPrinting(true);
} else { } else {
toast.error(labels.message); toast.error(labels.message);
setTimeout(() => {
setPrinting(false);
}, 5 * 1000);
} }
}; };
return ( return (
<Button variant="outline" size="icon" onClick={() => handlePrintLabel(lot)}> <Button
variant="outline"
size="icon"
onClick={() => handlePrintLabel(lot)}
disabled={printing}
>
<Tag className="h-[16px] w-[16px]" /> <Tag className="h-[16px] w-[16px]" />
</Button> </Button>
); );

View File

@@ -86,7 +86,13 @@ export default function OcpLogs() {
return ( return (
<LstCard className="m-2 p-2 min-h-2/5"> <LstCard className="m-2 p-2 min-h-2/5">
<p className="text-center">Labels for the last 2 hours</p> <p className="text-center">
{data?.length === 0 ? (
<span>No errors in the last 4 hours</span>
) : (
<span>Logs for the last 4 hours</span>
)}
</p>
<Table> <Table>
<TableHeader> <TableHeader>
<TableRow> <TableRow>

View File

@@ -1,19 +1,19 @@
import WrapperManualTrigger from "@/components/ocme/WrapperCard"; import WrapperManualTrigger from "@/components/ocme/WrapperCard";
import LabelLog from "./LabelLog";
import Lots from "./Lots"; import Lots from "./Lots";
import OcpLogs from "./OcpLogs"; import OcpLogs from "./OcpLogs";
import PrinterStatus from "./PrinterStatus"; import PrinterStatus from "./PrinterStatus";
import { useSettingStore } from "@/lib/store/useSettings"; import { useSettingStore } from "@/lib/store/useSettings";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import LabelLog from "./LabelLog";
export default function OCPPage() { export default function OCPPage() {
const { settings } = useSettingStore(); const { settings } = useSettingStore();
const server = settings.filter((n) => n.plantToken === "usday1"); let server = settings.filter((n) => n.name === "server");
console.log(server);
return ( return (
<div className="h-screen w-full "> <div className="h-screen w-full ">
<div className="flex flex-wrap gap-2"> <div className="flex flex-row gap-2">
<div className="flex flex-col w-4/5 h-dvh"> <div className="flex flex-col w-4/5 h-dvh">
<div className=""> <div className="">
<Lots /> <Lots />
@@ -33,15 +33,18 @@ export default function OCPPage() {
</div> </div>
</TabsContent> </TabsContent>
<TabsContent value="labels"> <TabsContent value="labels">
<div className="w-full"> <LabelLog />
<LabelLog />
</div>
</TabsContent> </TabsContent>
</Tabs> </Tabs>
</div> </div>
</div> </div>
<div className="w-1/6 flex flex-col"> <div className="flex flex-col">
{server.length >= 1 && ( {server[0].value === "usday1vms006" && (
<div>
<WrapperManualTrigger />
</div>
)}
{server[0].value === "localhost" && (
<div> <div>
<WrapperManualTrigger /> <WrapperManualTrigger />
</div> </div>

View File

@@ -81,7 +81,7 @@ export default function PrinterStatus() {
<TableHead key={l.key}>{l.label}</TableHead> <TableHead key={l.key}>{l.label}</TableHead>
))} ))}
</TableRow> </TableRow>
</TableHeader>{" "} </TableHeader>
{isLoading ? ( {isLoading ? (
<TableBody> <TableBody>
{Array(5) {Array(5)

View File

@@ -19,12 +19,18 @@ export const useGetUserRoles = create<SettingState>()((set) => ({
try { try {
//const response = await axios.get<{data: Setting[]}>(`${process.env.NEXT_PUBLIC_URL}/api/settings/client`); //const response = await axios.get<{data: Setting[]}>(`${process.env.NEXT_PUBLIC_URL}/api/settings/client`);
const token = localStorage.getItem("auth_token"); const token = localStorage.getItem("auth_token");
const response = await axios.get("/api/auth/getuseraccess", { if (token) {
headers: { Authorization: `Bearer ${token}` }, const response = await axios.get("/api/auth/getuseraccess", {
}); headers: { Authorization: `Bearer ${token}` },
const data: FetchModulesResponse = response.data; //await response.json(); });
//console.log(data); const data: FetchModulesResponse = response.data; //await response.json();
set({ userRoles: data.data });
//console.log(data);
set({ userRoles: data.data });
} else {
//console.log(data);
set({ userRoles: [] });
}
} catch (error) { } catch (error) {
console.error("Failed to fetch settings:", error); console.error("Failed to fetch settings:", error);
} }

View File

@@ -1,3 +1,4 @@
import HistoricalData from "@/components/logistics/siloAdjustments/HistoricalData";
import { createFileRoute, redirect } from "@tanstack/react-router"; import { createFileRoute, redirect } from "@tanstack/react-router";
export const Route = createFileRoute("/(logistics)/siloAdjustments/$hist")({ export const Route = createFileRoute("/(logistics)/siloAdjustments/$hist")({
@@ -22,10 +23,10 @@ export const Route = createFileRoute("/(logistics)/siloAdjustments/$hist")({
}); });
function RouteComponent() { function RouteComponent() {
const { hist } = Route.useParams();
return ( return (
<div> <div>
Hello "/(logistics)/siloAdjustments/$hist"! where the historical <HistoricalData laneId={hist} />
data will be shown in a table alone with a graph
</div> </div>
); );
} }

View File

@@ -8,7 +8,7 @@ export function getUsers() {
queryFn: () => fetchUsers(token), queryFn: () => fetchUsers(token),
enabled: !!token, // Prevents query if token is null enabled: !!token, // Prevents query if token is null
staleTime: 1000, staleTime: 1000,
//refetchInterval: 2 * 2000, refetchInterval: 2 * 2000,
refetchOnWindowFocus: true, refetchOnWindowFocus: true,
}); });
} }

View File

@@ -1,14 +1,14 @@
import { queryOptions } from "@tanstack/react-query"; import { queryOptions } from "@tanstack/react-query";
import axios from "axios"; import axios from "axios";
export function getStockSilo() { export function getAdjustments() {
const token = localStorage.getItem("auth_token"); const token = localStorage.getItem("auth_token");
return queryOptions({ return queryOptions({
queryKey: ["getUsers"], queryKey: ["getAdjustments"],
queryFn: () => fetchStockSilo(token), queryFn: () => fetchStockSilo(token),
enabled: !!token, // Prevents query if token is null enabled: !!token, // Prevents query if token is null
staleTime: 1000, staleTime: 1000,
//refetchInterval: 2 * 2000, refetchInterval: 2 * 2000,
refetchOnWindowFocus: true, refetchOnWindowFocus: true,
}); });
} }

View File

@@ -0,0 +1,19 @@
import { queryOptions } from "@tanstack/react-query";
import axios from "axios";
export function getOcmeInfo() {
return queryOptions({
queryKey: ["ocmeInfo"],
queryFn: () => fetchSettings(),
staleTime: 1000,
refetchInterval: 2 * 2000,
refetchOnWindowFocus: true,
});
}
const fetchSettings = async () => {
const { data } = await axios.get(`/ocme/api/v1/getInfo`);
// if we are not localhost ignore the devDir setting.
//const url: string = window.location.host.split(":")[0];
return data.data ?? [];
};

View File

@@ -6,7 +6,7 @@ export function getlabels(hours: string) {
queryKey: ["labels"], queryKey: ["labels"],
queryFn: () => fetchSettings(hours), queryFn: () => fetchSettings(hours),
staleTime: 1000, //staleTime: 1000,
refetchInterval: 2 * 2000, refetchInterval: 2 * 2000,
refetchOnWindowFocus: true, refetchOnWindowFocus: true,
}); });

View File

@@ -14,7 +14,7 @@ export function getOcpLogs(hours: string) {
const fetchSettings = async (hours: string) => { const fetchSettings = async (hours: string) => {
const { data } = await axios.get( const { data } = await axios.get(
`/api/logger/logs?service=ocp&service=rfid&level=error&level=warn&hours=${hours}` `/api/logger/logs?service=ocp&service=rfid&service=dyco&level=error&level=warn&hours=${hours}`
); );
// if we are not localhost ignore the devDir setting. // if we are not localhost ignore the devDir setting.
//const url: string = window.location.host.split(":")[0]; //const url: string = window.location.host.split(":")[0];

View File

@@ -0,0 +1,84 @@
import { ColumnDef } from "@tanstack/react-table";
import { format } from "date-fns";
// This type is used to define the shape of our data.
// You can use a Zod schema here if you want.
export type Adjustmnets = {
siloAdjust_id: string;
currentStockLevel: string;
newLevel: number;
dateAdjusted: string;
lastDateAdjusted: string;
comment: string;
commentAddedBy: string;
commentDate: string;
add_user: string;
};
export const columns: ColumnDef<Adjustmnets>[] = [
{
accessorKey: "currentStockLevel",
header: () => <div className="text-right">Stock At Post</div>,
},
{
accessorKey: "newLevel",
header: "Level Entered",
},
{
accessorKey: "dateAdjusted",
header: "Adjustmnet",
cell: ({ row }) => {
if (row.getValue("dateAdjusted")) {
const correctDate = format(
row.original.dateAdjusted?.replace("Z", ""),
"M/d/yyyy hh:mm"
);
return (
<div className="text-right font-medium">{correctDate}</div>
);
}
},
},
{
accessorKey: "lastDateAdjusted",
header: "Last Adjusted",
cell: ({ row }) => {
if (row.getValue("lastDateAdjusted")) {
const correctDate = format(
row.original.lastDateAdjusted?.replace("Z", ""),
"M/d/yyyy hh:mm"
);
return (
<div className="text-right font-medium">{correctDate}</div>
);
}
},
},
{
accessorKey: "comment",
header: "Comment",
},
{
accessorKey: "commentAddedBy",
header: "Commenter ",
},
{
accessorKey: "commentDate",
header: "Comment Date ",
cell: ({ row }) => {
if (row.getValue("commentDate")) {
const correctDate = format(
row.original.commentDate?.replace("Z", ""),
"M/d/yyyy hh:mm"
);
return (
<div className="text-right font-medium">{correctDate}</div>
);
}
},
},
{
accessorKey: "add_user",
header: "Creator",
},
];

View File

@@ -0,0 +1,110 @@
import {
ColumnDef,
flexRender,
getCoreRowModel,
useReactTable,
getPaginationRowModel,
} from "@tanstack/react-table";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Button } from "@/components/ui/button";
interface DataTableProps<TData, TValue> {
columns: ColumnDef<TData, TValue>[];
data: TData[];
}
export function DataTable<TData, TValue>({
columns,
data,
}: DataTableProps<TData, TValue>) {
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
});
//console.log(data);
return (
<div className="rounded-md border w-[1028px]">
<div>
<Table>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef
.header,
header.getContext()
)}
</TableHead>
);
})}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={
row.getIsSelected() && "selected"
}
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(
cell.column.columnDef.cell,
cell.getContext()
)}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell
colSpan={columns.length}
className="h-24 text-center"
>
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
<div className="flex items-center justify-end space-x-2 py-4">
<Button
variant="outline"
size="sm"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
>
Previous
</Button>
<Button
variant="outline"
size="sm"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
>
Next
</Button>
</div>
</div>
);
}

View File

@@ -1,25 +1,44 @@
import {Modules} from "@/types/modules"; import { Modules } from "@/types/modules";
import {User} from "@/types/users"; import { User } from "@/types/users";
// user will need access to the module. // user will need access to the module.
// users role will determine there visual access // users role will determine there visual access
export function hasAccess(user: User | null, moduleName: string | null, modules: Modules[]): boolean { export function hasAccess(
user: User | null,
moduleName: string | null,
modules: Modules[]
): boolean {
// get the modules for the id // get the modules for the id
const filteredModule = modules?.filter((f) => f.name === moduleName); const filteredModule = modules?.filter((f) => f.name === moduleName);
//console.log(filteredModule[0].module_id); //console.log(filteredModule[0]);
// userroles and filter out by the module id, // userroles and filter out by the module id,
return user?.roles.find((role) => role.module_id === filteredModule[0].module_id) ? true : false; const roleCheck: any = user?.roles.find(
(role) => role.module_id === filteredModule[0].module_id
);
if (filteredModule[0].roles.includes(roleCheck?.role)) {
return true;
}
//if(filteredModule[0].roles.includes(roleCheck.))
return false;
} }
export function hasPageAccess(user: User | null, role: any, module_id: string): boolean { export function hasPageAccess(
user: User | null,
role: any,
module_id: string
): boolean {
if (role.includes("viewer")) return true; if (role.includes("viewer")) return true;
if (!user) return false; if (!user) return false;
// get only the module in the user profile // get only the module in the user profile
//console.log(user);
const userRole = user?.roles.filter((role) => role.module_id === module_id); const userRole = user?.roles.filter((role) => role.module_id === module_id);
console.log(userRole[0]?.role);
// if (role.includes(userRole[0]?.role)) {
if (role.includes(userRole[0]?.role)) return true; // return true};
if (userRole.length !== 0) return true;
return false; return false;
} }

34
package-lock.json generated
View File

@@ -13,6 +13,7 @@
"@hono/zod-openapi": "^0.19.2", "@hono/zod-openapi": "^0.19.2",
"@scalar/hono-api-reference": "^0.7.2", "@scalar/hono-api-reference": "^0.7.2",
"@tanstack/react-form": "^1.2.1", "@tanstack/react-form": "^1.2.1",
"@tanstack/react-table": "^8.21.2",
"@types/jsonwebtoken": "^9.0.9", "@types/jsonwebtoken": "^9.0.9",
"@types/nodemailer-express-handlebars": "^4.0.5", "@types/nodemailer-express-handlebars": "^4.0.5",
"adm-zip": "^0.5.16", "adm-zip": "^0.5.16",
@@ -1788,6 +1789,26 @@
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
} }
}, },
"node_modules/@tanstack/react-table": {
"version": "8.21.2",
"resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.21.2.tgz",
"integrity": "sha512-11tNlEDTdIhMJba2RBH+ecJ9l1zgS2kjmexDPAraulc8jeNA4xocSNeyzextT0XJyASil4XsCYlJmf5jEWAtYg==",
"license": "MIT",
"dependencies": {
"@tanstack/table-core": "8.21.2"
},
"engines": {
"node": ">=12"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
},
"peerDependencies": {
"react": ">=16.8",
"react-dom": ">=16.8"
}
},
"node_modules/@tanstack/store": { "node_modules/@tanstack/store": {
"version": "0.7.0", "version": "0.7.0",
"resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.7.0.tgz", "resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.7.0.tgz",
@@ -1798,6 +1819,19 @@
"url": "https://github.com/sponsors/tannerlinsley" "url": "https://github.com/sponsors/tannerlinsley"
} }
}, },
"node_modules/@tanstack/table-core": {
"version": "8.21.2",
"resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.21.2.tgz",
"integrity": "sha512-uvXk/U4cBiFMxt+p9/G7yUWI/UbHYbyghLCjlpWZ3mLeIZiUBSKcUnw9UnKkdRz7Z/N4UBuFLWQdJCjUe7HjvA==",
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
}
},
"node_modules/@tediousjs/connection-string": { "node_modules/@tediousjs/connection-string": {
"version": "0.5.0", "version": "0.5.0",
"resolved": "https://registry.npmjs.org/@tediousjs/connection-string/-/connection-string-0.5.0.tgz", "resolved": "https://registry.npmjs.org/@tediousjs/connection-string/-/connection-string-0.5.0.tgz",

View File

@@ -1,91 +1,92 @@
{ {
"name": "lstv2", "name": "lstv2",
"version": "2.13.0", "version": "2.13.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "concurrently -n \"server,frontend\" -c \"#007755,#2f6da3\" \"npm run dev:server\" \"cd frontend && npm run dev\"", "dev": "concurrently -n \"server,frontend\" -c \"#007755,#2f6da3\" \"npm run dev:server\" \"cd frontend && npm run dev\"",
"dev:server": "dotenvx run -f .env -- tsx watch server/index.ts", "dev:server": "dotenvx run -f .env -- tsx watch server/index.ts",
"dev:frontend": "cd frontend && npm run dev", "dev:frontend": "cd frontend && npm run dev",
"dev:dbgen": " drizzle-kit generate --config=drizzle-dev.config.ts", "dev:dbgen": " drizzle-kit generate --config=drizzle-dev.config.ts",
"dev:dbmigrate": " drizzle-kit migrate --config=drizzle-dev.config.ts", "dev:dbmigrate": " drizzle-kit migrate --config=drizzle-dev.config.ts",
"build": "npm run build:server && npm run build:frontend", "build": "npm run build:server && npm run build:frontend",
"build:server": "rimraf dist && tsc --build && npm run copy:scripts && xcopy server\\services\\notifications\\utils\\views\\ dist\\server\\services\\notifications\\utils\\views\\ /E /I /Y", "build:server": "rimraf dist && tsc --build && npm run copy:scripts && xcopy server\\services\\notifications\\utils\\views\\ dist\\server\\services\\notifications\\utils\\views\\ /E /I /Y",
"build:frontend": "cd frontend && npm run build", "build:frontend": "cd frontend && npm run build",
"copy:scripts": "tsx server/scripts/copyScripts.ts", "copy:scripts": "tsx server/scripts/copyScripts.ts",
"copy:servers": "xcopy server\\services\\server\\utils\\serverData.json dist\\server\\services\\server\\utils /E /I /Y", "copy:servers": "xcopy server\\services\\server\\utils\\serverData.json dist\\server\\services\\server\\utils /E /I /Y",
"start": "set NODE_ENV=production && npm run start:server", "start": "set NODE_ENV=production && npm run start:server",
"start:server": "dotenvx run -f .env -- node dist/server/index.js", "start:server": "dotenvx run -f .env -- node dist/server/index.js",
"db:generate": "npx drizzle-kit generate", "db:generate": "npx drizzle-kit generate",
"db:migrate": "npx drizzle-kit push", "db:migrate": "npx drizzle-kit push",
"db:dev": "npm run build && npm run db:generate && npm run db:migrate", "db:dev": "npm run build && npm run db:generate && npm run db:migrate",
"deploy": "standard-version --conventional-commits && npm run prodBuild", "deploy": "standard-version --conventional-commits && npm run prodBuild",
"zipServer": "dotenvx run -f .env -- tsx server/scripts/zipUpBuild.ts \"C:\\Users\\matthes01\\Documents\\lstv2\"", "zipServer": "dotenvx run -f .env -- tsx server/scripts/zipUpBuild.ts \"C:\\Users\\matthes01\\Documents\\lstv2\"",
"v1Build": "cd C:\\Users\\matthes01\\Documents\\logisticsSupportTool && npm run oldBuilder", "v1Build": "cd C:\\Users\\matthes01\\Documents\\logisticsSupportTool && npm run oldBuilder",
"scriptBuild": "powershell -ExecutionPolicy Bypass -File server/scripts/build.ps1 -dir \"C:\\Users\\matthes01\\Documents\\lstv2\"", "scriptBuild": "powershell -ExecutionPolicy Bypass -File server/scripts/build.ps1 -dir \"C:\\Users\\matthes01\\Documents\\lstv2\"",
"removeOld": "rimraf dist && rimraf frontend/dist", "removeOld": "rimraf dist && rimraf frontend/dist",
"prodBuild": "npm run v1Build && npm run build && npm run zipServer && npm run dev", "prodBuild": "npm run v1Build && npm run build && npm run zipServer && npm run dev",
"commit": "cz", "commit": "cz",
"prodinstall": "npm i --omit=dev && npm run db:migrate", "prodinstall": "npm i --omit=dev && npm run db:migrate",
"checkupdates": "npx npm-check-updates", "checkupdates": "npx npm-check-updates",
"testingCode": "dotenvx run -f .env -- tsx watch server/services/logistics/controller/siloAdjustments/migrateAdjustments.ts" "testingCode": "dotenvx run -f .env -- tsx watch server/services/logistics/controller/warehouse/cycleCountChecks/cyclecountCheck.ts"
}, },
"config": { "config": {
"commitizen": { "commitizen": {
"path": "./node_modules/cz-conventional-changelog" "path": "./node_modules/cz-conventional-changelog"
}
},
"admConfig": {
"build": 207,
"oldBuild": "backend-0.1.3.zip"
},
"devDependencies": {
"@types/adm-zip": "^0.5.7",
"@types/bcrypt": "^5.0.2",
"@types/fs-extra": "^11.0.4",
"@types/js-cookie": "^3.0.6",
"@types/mssql": "^9.1.7",
"@types/node": "^22.13.11",
"@types/node-cron": "^3.0.11",
"@types/nodemailer": "^6.4.17",
"@types/pg": "^8.11.11",
"@types/ws": "^8.18.0",
"concurrently": "^9.1.2",
"cz-conventional-changelog": "^3.3.0",
"standard-version": "^9.5.0",
"tsx": "^4.19.3",
"typescript": "^5.8.2"
},
"dependencies": {
"@dotenvx/dotenvx": "^1.39.0",
"@hono/node-server": "^1.14.0",
"@hono/zod-openapi": "^0.19.2",
"@scalar/hono-api-reference": "^0.7.2",
"@tanstack/react-form": "^1.2.1",
"@tanstack/react-table": "^8.21.2",
"@types/jsonwebtoken": "^9.0.9",
"@types/nodemailer-express-handlebars": "^4.0.5",
"adm-zip": "^0.5.16",
"axios": "^1.8.4",
"bcryptjs": "^3.0.2",
"croner": "^9.0.0",
"date-fns": "^4.1.0",
"date-fns-tz": "^3.2.0",
"drizzle-kit": "^0.30.5",
"drizzle-orm": "^0.41.0",
"drizzle-zod": "^0.7.0",
"fast-xml-parser": "^5.0.9",
"fs-extra": "^11.3.0",
"jsonwebtoken": "^9.0.2",
"mssql": "^11.0.1",
"nodemailer": "^6.10.0",
"nodemailer-express-handlebars": "^7.0.0",
"pg": "^8.14.1",
"pino": "^9.6.0",
"pino-abstract-transport": "^2.0.0",
"pino-pretty": "^13.0.0",
"postgres": "^3.4.5",
"rimraf": "^6.0.1",
"st-ethernet-ip": "^2.7.3",
"ws": "^8.18.1",
"zod": "^3.24.2"
} }
},
"admConfig": {
"build": 181,
"oldBuild": "backend-0.1.3.zip"
},
"devDependencies": {
"@types/adm-zip": "^0.5.7",
"@types/bcrypt": "^5.0.2",
"@types/fs-extra": "^11.0.4",
"@types/js-cookie": "^3.0.6",
"@types/mssql": "^9.1.7",
"@types/node": "^22.13.11",
"@types/node-cron": "^3.0.11",
"@types/nodemailer": "^6.4.17",
"@types/pg": "^8.11.11",
"@types/ws": "^8.18.0",
"concurrently": "^9.1.2",
"cz-conventional-changelog": "^3.3.0",
"standard-version": "^9.5.0",
"tsx": "^4.19.3",
"typescript": "^5.8.2"
},
"dependencies": {
"@dotenvx/dotenvx": "^1.39.0",
"@hono/node-server": "^1.14.0",
"@hono/zod-openapi": "^0.19.2",
"@scalar/hono-api-reference": "^0.7.2",
"@tanstack/react-form": "^1.2.1",
"@types/jsonwebtoken": "^9.0.9",
"@types/nodemailer-express-handlebars": "^4.0.5",
"adm-zip": "^0.5.16",
"axios": "^1.8.4",
"bcryptjs": "^3.0.2",
"croner": "^9.0.0",
"date-fns": "^4.1.0",
"date-fns-tz": "^3.2.0",
"drizzle-kit": "^0.30.5",
"drizzle-orm": "^0.41.0",
"drizzle-zod": "^0.7.0",
"fast-xml-parser": "^5.0.9",
"fs-extra": "^11.3.0",
"jsonwebtoken": "^9.0.2",
"mssql": "^11.0.1",
"nodemailer": "^6.10.0",
"nodemailer-express-handlebars": "^7.0.0",
"pg": "^8.14.1",
"pino": "^9.6.0",
"pino-abstract-transport": "^2.0.0",
"pino-pretty": "^13.0.0",
"postgres": "^3.4.5",
"rimraf": "^6.0.1",
"st-ethernet-ip": "^2.7.3",
"ws": "^8.18.1",
"zod": "^3.24.2"
}
} }

View File

@@ -1,24 +1,42 @@
import { db } from "../../../../../database/dbclient.js"; import { db } from "../../../../../database/dbclient.js";
import { userRoles } from "../../../../../database/schema/userRoles.js";
import { users } from "../../../../../database/schema/users.js"; import { users } from "../../../../../database/schema/users.js";
import { returnRes } from "../../../../globalUtils/routeDefs/returnRes.js"; import { returnRes } from "../../../../globalUtils/routeDefs/returnRes.js";
import { tryCatch } from "../../../../globalUtils/tryCatch.js"; import { tryCatch } from "../../../../globalUtils/tryCatch.js";
import { createLog } from "../../../logger/logger.js"; import { createLog } from "../../../logger/logger.js";
export const getAllUsers = async () => { export const getAllUsers = async () => {
/** /**
* returns all users that are in lst * returns all users that are in lst
*/ */
createLog("info", "apiAuthedRoute", "auth", "Get all users"); createLog("info", "apiAuthedRoute", "auth", "Get all users");
const { data, error } = await tryCatch(db.select().from(users));
if (error) { // get all users
returnRes( const { data, error } = await tryCatch(db.select().from(users));
false,
"There was an error getting users",
new Error("No user exists.")
);
}
returnRes(true, "All users.", data); // add there modules they are in
return { success: true, message: "All users", data }; const { data: m, error: em } = await tryCatch(db.select().from(userRoles));
const user: any = data;
const userData = user.map((i: any) => {
// module in
const module = m?.filter((x: any) => x.user_id === i.user_id);
if (module) {
return { ...i, moduleRoles: module };
} else {
return;
}
});
if (error) {
returnRes(
false,
"There was an error getting users",
new Error("No user exists.")
);
}
//returnRes(true, "All users.", data);
return { success: true, message: "All users", data: userData };
}; };

View File

@@ -54,12 +54,18 @@ export const setUserAccess = async (
// set the user // set the user
try { try {
const userRole = await db.insert(userRoles).values({ const userRole = await db
user_id: user[0].user_id, .insert(userRoles)
role_id: role[0].role_id, .values({
module_id: module[0].module_id, user_id: user[0].user_id,
role: roleName, role_id: role[0].role_id,
}); module_id: module[0].module_id,
role: roleName,
})
.onConflictDoUpdate({
target: userRoles.user_id,
set: { role_id: role[0].role_id, role: roleName },
});
//.returning({user: users.username, email: users.email}); //.returning({user: users.username, email: users.email});
// return c.json({message: "User Registered", user}, 200); // return c.json({message: "User Registered", user}, 200);

View File

@@ -59,7 +59,7 @@ app.openapi(
{ {
success: access.success, success: access.success,
message: access.message, message: access.message,
data: access.data, data: [], //access?.data,
}, },
200 200
); );

View File

@@ -1,7 +1,7 @@
import {eq, sql} from "drizzle-orm"; import { eq, sql } from "drizzle-orm";
import {db} from "../../../../database/dbclient.js"; import { db } from "../../../../database/dbclient.js";
import {logs} from "../../../../database/schema/logs.js"; import { logs } from "../../../../database/schema/logs.js";
import {createLog} from "../logger.js"; import { createLog } from "../logger.js";
export const clearLog = async (id: string) => { export const clearLog = async (id: string) => {
/** /**
@@ -10,13 +10,21 @@ export const clearLog = async (id: string) => {
try { try {
const clear = await db const clear = await db
.update(logs) .update(logs)
.set({checked: true, checkedAt: sql`NOW()`}) .set({ checked: true, created_at: sql`NOW()` })
.where(eq(logs.log_id, id)); .where(eq(logs.log_id, id));
createLog("info", "lst", "logger", "Log just cleared."); createLog("info", "lst", "logger", "Log just cleared.");
return {success: true, message: "Log was just cleared."}; return { success: true, message: "Log was just cleared." };
} catch (error) { } catch (error) {
createLog("error", "lst", "logger", "There was an error clearing the log."); createLog(
return {success: false, message: "There was an error clearing the log."}; "error",
"lst",
"logger",
"There was an error clearing the log."
);
return {
success: false,
message: "There was an error clearing the log.",
};
} }
}; };

View File

@@ -1,4 +1,4 @@
import { and, eq, gte, inArray, lte, sql } from "drizzle-orm"; import { and, desc, eq, gte, inArray, lte, sql } from "drizzle-orm";
import { db } from "../../../../database/dbclient.js"; import { db } from "../../../../database/dbclient.js";
import { logs } from "../../../../database/schema/logs.js"; import { logs } from "../../../../database/schema/logs.js";
import { createLog } from "../logger.js"; import { createLog } from "../logger.js";
@@ -21,7 +21,8 @@ export const getLogs = async (data: any) => {
inArray(logs.level, data.level), inArray(logs.level, data.level),
eq(logs.checked, checked) eq(logs.checked, checked)
) )
); )
.orderBy(desc(logs.created_at));
return { success: true, message: "logs returned", data: logData }; return { success: true, message: "logs returned", data: logData };
} catch (error) { } catch (error) {

View File

@@ -56,17 +56,17 @@ export const migrateAdjustments = async () => {
/** /**
* Migrate all the silo adjustments :D * Migrate all the silo adjustments :D
*/ */
const silo: any = s?.data; const silo: any = s?.data.data;
createLog("info", "silo", "logistics", "Starting migration."); createLog("info", "silo", "logistics", "Starting migration.");
for (let i = 0; i < silo.length; i++) { for (let i = 0; i < silo.length; i++) {
const migrate = await db.insert(siloAdjustments).values({ const migrate = await db.insert(siloAdjustments).values({
warehouseID: silo[0].warehouseID, warehouseID: silo[i].warehouseID,
locationID: silo[0].locationID, locationID: silo[i].locationID,
currentStockLevel: silo[0].currentStockLevel, currentStockLevel: silo[i].currentStockLevel,
newLevel: silo[0].newLevel, newLevel: silo[i].newLevel,
dateAdjusted: new Date(silo[0].dateAdjusted), dateAdjusted: new Date(silo[i].dateAdjusted),
lastDateAdjusted: new Date(silo[0].lastDateAdjusted), lastDateAdjusted: new Date(silo[i].lastDateAdjusted),
add_user: silo[0].add_user, add_user: silo[i].add_user,
}); });
createLog( createLog(
"info", "info",
@@ -87,5 +87,3 @@ export const migrateAdjustments = async () => {
.where(eq(settings.name, "siloAdjMigrations")); .where(eq(settings.name, "siloAdjMigrations"));
createLog("info", "silo", "logistics", "Migration completed."); createLog("info", "silo", "logistics", "Migration completed.");
}; };
migrateAdjustments();

View File

@@ -0,0 +1,59 @@
import { differenceInDays, differenceInSeconds, format } from "date-fns";
import { timeZoneFix } from "../../../../../globalUtils/timeZoneFix.js";
import { createLog } from "../../../../logger/logger.js";
import { delay } from "../../../../../globalUtils/delay.js";
import { tryCatch } from "../../../../../globalUtils/tryCatch.js";
import { query } from "../../../../sqlServer/prodSqlServer.js";
import { cycleCountCheck } from "../../../../sqlServer/querys/warehouse/cycleCountCheck.js";
// setting timer for updating stockCheck on a restart will always check.
let lastCheck = 0;
export const lanes: any = [];
export const getLanesToCycleCount = async () => {
const currentTime: any = timeZoneFix();
// store the lanes in memeory
createLog("info", "warehouse", "logistics", "Empty lane triggered update.");
lastCheck = currentTime;
const ageQuery = cycleCountCheck.replaceAll("[ageOfRow]", `1000`);
const { data: prodLanes, error: pl } = await tryCatch(
query(ageQuery, "Get Stock lane date.")
);
// run the update on the lanes
for (let i = 0; i < prodLanes.length; i++) {
const createLane = {
laneID: prodLanes[i]?.laneID,
warehouseID: prodLanes[i]?.warehouseID,
warehouseName: prodLanes[i]?.warehouseName || "na",
Description: prodLanes[i]?.Description,
LastMoveDate: prodLanes[i]?.LastMoveDate
? format(prodLanes[i]?.LastInv, "M/d/yyyy")
: undefined,
LastInv: format(prodLanes[i]?.LastInv, "M/d/yyyy"),
rowType: prodLanes[i].rowType,
DaysSinceLast:
differenceInDays(
new Date(prodLanes[i].LastInv),
new Date(prodLanes[i].LastMoveDate)
) <= 0
? 0
: differenceInDays(
new Date(prodLanes[i].LastInv),
new Date(prodLanes[i].LastMoveDate)
),
upd_date: format(new Date(Date.now()), "M/d/yyyy"),
};
lanes.push(createLane);
createLog(
"debug",
"warehouse",
"logistics",
`${lanes[i].Description} was just added`
);
await delay(10);
//delay to slow this thing down
}
};

View File

@@ -0,0 +1,28 @@
import { lanes } from "./cyclecountCheck.js";
export const getCycleCountCheck = async (
age: number = 1000,
type: string = ""
) => {
/**
* Get the lane data based on the age and type
*/
let filteredLanes = lanes.filter((t: any) => t.DaysSinceLast >= age);
if (type != "") {
return {
sucess: true,
message: `${filteredLanes.length} lanes that are of type ${type} and have not been cycle counted in the last ${age} days.`,
data: filteredLanes.filter(
(t: any) => t.rowType === type.toUpperCase()
),
};
} else {
return {
success: true,
message: `${filteredLanes.length} lanes grabed that have not been cycle counted in the last ${age} days.`,
data: filteredLanes,
};
}
};

View File

@@ -7,6 +7,8 @@ import postComment from "./route/siloAdjustments/postComment.js";
import getStockSilo from "./route/siloAdjustments/getStockData.js"; import getStockSilo from "./route/siloAdjustments/getStockData.js";
import { migrateAdjustments } from "./controller/siloAdjustments/migrateAdjustments.js"; import { migrateAdjustments } from "./controller/siloAdjustments/migrateAdjustments.js";
import getSiloAdjustments from "./route/siloAdjustments/getSiloAdjustments.js"; import getSiloAdjustments from "./route/siloAdjustments/getSiloAdjustments.js";
import { getLanesToCycleCount } from "./controller/warehouse/cycleCountChecks/cyclecountCheck.js";
import getCycleCountCheck from "./route/getCycleCountChecks.js";
const app = new OpenAPIHono(); const app = new OpenAPIHono();
@@ -19,6 +21,8 @@ const routes = [
postComment, postComment,
getStockSilo, getStockSilo,
getSiloAdjustments, getSiloAdjustments,
//lanes
getCycleCountCheck,
] as const; ] as const;
// app.route("/server", modules); // app.route("/server", modules);
@@ -28,6 +32,17 @@ const appRoutes = routes.forEach((route) => {
setTimeout(() => { setTimeout(() => {
migrateAdjustments(); migrateAdjustments();
}, 10 * 1000); }, 120 * 1000);
/**
* Start the cycle count check
*/
setTimeout(() => {
getLanesToCycleCount();
}, 5 * 1000);
setInterval(async () => {
getLanesToCycleCount();
}, 15 * 60 * 1000);
export default app; export default app;

View File

@@ -0,0 +1,60 @@
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { responses } from "../../../globalUtils/routeDefs/responses.js";
import { tryCatch } from "../../../globalUtils/tryCatch.js";
import { getCycleCountCheck } from "../controller/warehouse/cycleCountChecks/getCycleCountCheck.js";
const app = new OpenAPIHono();
const Body = z
.object({
age: z.number().optional().openapi({ example: 90 }),
//email: z.string().optional().openapi({example: "s.smith@example.com"}),
type: z.string().optional().openapi({ example: "fg" }),
})
.openapi("User");
app.openapi(
createRoute({
tags: ["logistics"],
summary: "Returns lanes that need cycle counted",
method: "post",
path: "/cyclecountcheck",
request: {
body: {
content: {
"application/json": { schema: Body },
},
},
},
// description:
// "Provided a running number and lot number you can consume material.",
responses: responses(),
}),
async (c: any) => {
//apiHit(c, { endpoint: "api/sqlProd/close" });
const { data: body, error: be } = await tryCatch(c.req.json());
if (be) {
return c.json({ success: false, message: "Missing Data." });
}
const check: any = body;
const { data: lanes, error: le } = await tryCatch(
getCycleCountCheck(check.age, check.type)
);
if (le) {
return c.json({
success: false,
message: "Error getting lane data.",
data: le,
});
}
return c.json({
success: lanes.success,
message: lanes.message,
data: lanes.data,
});
}
);
export default app;

View File

@@ -3,6 +3,7 @@ import { ocmeData } from "../../../../database/schema/ocme.js";
import { differenceInMinutes } from "date-fns"; import { differenceInMinutes } from "date-fns";
import { createLog } from "../../logger/logger.js"; import { createLog } from "../../logger/logger.js";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { timeZoneFix } from "../../../globalUtils/timeZoneFix.js";
export const getInfo = async () => { export const getInfo = async () => {
let ocmeInfo: any = []; let ocmeInfo: any = [];
@@ -16,7 +17,7 @@ export const getInfo = async () => {
ocmeInfo = ocmeInfo.map((o: any) => { ocmeInfo = ocmeInfo.map((o: any) => {
const now = new Date(Date.now()); const now = new Date(Date.now());
//const strippedDate = o.add_Date.replace("Z", ""); //const strippedDate = o.add_Date.replace("Z", "");
const diff = differenceInMinutes(now, o.add_Date); const diff = differenceInMinutes(timeZoneFix(), o.add_Date);
return { ...o, waitingFor: diff }; return { ...o, waitingFor: diff };
}); });
createLog( createLog(

View File

@@ -32,7 +32,7 @@ export const createLabel = async (data: any, userPrinted: any) => {
if (settingsError) { if (settingsError) {
return { return {
success: false, success: false,
message: "There was an error getting the printer.", message: "There was an error getting the settings.",
settingsError, settingsError,
}; };
} }

View File

@@ -60,11 +60,11 @@ export const labelingProcess = async ({
"error", "error",
"labeling", "labeling",
"ocp", "ocp",
`There is not a lot assigned to ${macId[0]?.Name}.` `There is not a lot assigned to ${line}.`
); );
return { return {
success: false, success: false,
message: `There is not a lot assigned to ${macId[0]?.Name}.`, message: `There is not a lot assigned to ${line}.`,
}; };
} }
} }
@@ -128,7 +128,7 @@ export const labelingProcess = async ({
} }
// if there are more than 2 lots it might be an auto labeler, autolabeler will be defined by its id for now only dayton // if there are more than 2 lots it might be an auto labeler, autolabeler will be defined by its id for now only dayton
if (filteredLot.length > 2 && plantToken[0].value !== "usday1") { if (filteredLot?.length > 2 && plantToken[0].value !== "usday1") {
createLog( createLog(
"error", "error",
"labeling", "labeling",
@@ -214,15 +214,15 @@ export const labelingProcess = async ({
// create the label // create the label
const label = await createLabel(filteredLot[0], userPrinted); const label = await createLabel(filteredLot[0], userPrinted);
if (!label.success) { // if (!label.success) {
createLog( // createLog(
"error", // "error",
"labeling", // "labeling",
"ocp", // "ocp",
`There was an error creating the label: ${label.message}` // `There was an error creating the label: ${label.message}`
); // );
return { sucess: false, message: label.message, data: label.data }; // return { sucess: false, message: label.message, data: label.data };
} // }
// send over to be booked in if we can do it. // send over to be booked in if we can do it.
const bookin = settingData.filter((s) => s.name === "bookin"); const bookin = settingData.filter((s) => s.name === "bookin");

View File

@@ -0,0 +1,121 @@
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 { createLog } from "../../../logger/logger.js";
import { getPrinters } from "./getPrinters.js";
import { autoLabelingStats } from "./printerStatus.js";
let isPrinterCycling = false;
let actualPrinterCycle: any;
export const printerCycleAutoLabelers = async () => {
/**
* Will only check the auto labelers for status updates.
*/
if (isPrinterCycling)
return {
success: false,
message: "Printers are already being cycled.",
};
createLog("info", "ocp", "ocp", "AutoLabeling cycle has started.");
// get the printers
const { data: s, error: se } = await tryCatch(
db.select().from(settings).where(eq(settings.name, "ocpCycleDelay"))
);
if (se) {
createLog(
"error",
"ocp",
"ocp",
"There was an error getting the ocpCycleDelay."
);
return {
success: false,
message: "Error getting printers.",
};
}
const ocpDelay: any = s;
isPrinterCycling = true;
// start the actual printer cycle
actualPrinterCycle = setInterval(async () => {
const { data, error } = await tryCatch(getPrinters());
if (error) {
createLog(
"error",
"ocp",
"ocp",
"There was an error getting the printers."
);
return {
success: false,
message: "Error getting printers.",
};
}
let printers: any = data.data;
// only keep the assigned ones
printers = printers.filter((p: any) => p.assigned === true);
// for printers we want to ignore there must be a remark stateing to ignore.
printers = printers.filter((p: any) => !p.remark.includes("ignore"));
printers.forEach(async (p: any) => {
/**
* 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.
*/
// ignore pdf printer as we want it here for testing purposes
if (p.name.toLowerCase() === "pdf24") {
return;
}
if (p.name === "Autolabeler") {
await autoLabelingStats(p);
return;
}
});
}, parseInt(ocpDelay[0]?.value) * 2 * 1000);
return { success: true, message: "AutoLabeling cycle has been started." };
};
export const stopPrinterCycle = async () => {
/**
* We will stop the print cylce this is more an emergancy thing.
*/
if (actualPrinterCycle && !actualPrinterCycle._destroyed) {
createLog("info", "ocp", "ocp", "AutoLabeling cycle is being stopped.");
clearInterval(actualPrinterCycle);
isPrinterCycling = false;
return {
success: true,
message: "AutoLabeling cycle has been stopped.",
};
} else {
createLog(
"info",
"ocp",
"ocp",
"AutoLabeling cycle is already stopped."
);
isPrinterCycling = false;
return {
success: true,
message: "AutoLabeling cycle is already Stopped.",
};
}
};

View File

@@ -75,8 +75,16 @@ export const labelerTagRead = async (tagData: any) => {
// check if we need to manual check due to 20 pallets. // check if we need to manual check due to 20 pallets.
if (currentPalletCheck <= cameraPalletCheck) { if (currentPalletCheck <= cameraPalletCheck) {
currentPalletCheck = currentPalletCheck + 1; currentPalletCheck++;
labelingProcess({ line: numericString }); labelingProcess({ line: numericString });
createLog(
"info",
"dyco",
"ocp",
`You have printed ${currentPalletCheck} pallets, remaining until ${
cameraPalletCheck - currentPalletCheck
}.`
);
} else { } else {
currentPalletCheck = 0; currentPalletCheck = 0;
createLog( createLog(

View File

@@ -17,6 +17,9 @@ import { assignedPrinters } from "./utils/checkAssignments.js";
import { printerCycle } from "./controller/printers/printerCycle.js"; import { printerCycle } from "./controller/printers/printerCycle.js";
import stopPrinterCycle from "./routes/printers/stopCycle.js"; import stopPrinterCycle from "./routes/printers/stopCycle.js";
import startPrinterCycle from "./routes/printers/startCycle.js"; import startPrinterCycle from "./routes/printers/startCycle.js";
import { printerCycleAutoLabelers } from "./controller/printers/printerCycleAutoLabelers.js";
import AutostartPrinterCycle from "./routes/printers/autoLabelerStart.js";
import AutostopPrinterCycle from "./routes/printers/autoLabelerStop.js";
const app = new OpenAPIHono(); const app = new OpenAPIHono();
@@ -27,6 +30,8 @@ const routes = [
updateprinters, updateprinters,
startPrinterCycle, startPrinterCycle,
stopPrinterCycle, stopPrinterCycle,
AutostartPrinterCycle,
AutostopPrinterCycle,
// lots // lots
getLots, getLots,
// labeling // labeling
@@ -76,6 +81,7 @@ setTimeout(async () => {
await updatePrinters(); await updatePrinters();
await assignedPrinters(); await assignedPrinters();
printerCycle(); printerCycle();
printerCycleAutoLabelers();
} }
}, 10 * 1000); }, 10 * 1000);

View File

@@ -0,0 +1,41 @@
// an external way to creating logs
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { authMiddleware } from "../../../auth/middleware/authMiddleware.js";
import { responses } from "../../../../globalUtils/routeDefs/responses.js";
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
import { printerCycle } from "../../controller/printers/printerCycle.js";
const app = new OpenAPIHono({ strict: false });
app.openapi(
createRoute({
tags: ["ocp:printers"],
summary: "starts the printers cycling.",
method: "get",
path: "/startsprintercycle",
middleware: authMiddleware,
//description: "This might be a temp soltuin during the transtion between versions",
// request: {
// body: {content: {"application/json": {schema: CreateLog}}},
// },
responses: responses(),
}),
async (c) => {
const { data, error } = await tryCatch(printerCycle());
const dataError: any = error;
if (error) {
return c.json({
success: false,
message: "Error in stopping the printer cycle",
data: dataError?.data,
});
}
const getData: any = data;
return c.json({
success: getData?.success,
message: getData?.message,
data: getData.data ?? [],
});
}
);
export default app;

View File

@@ -0,0 +1,41 @@
// an external way to creating logs
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { authMiddleware } from "../../../auth/middleware/authMiddleware.js";
import { responses } from "../../../../globalUtils/routeDefs/responses.js";
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
import { stopPrinterCycle } from "../../controller/printers/printerCycle.js";
const app = new OpenAPIHono({ strict: false });
app.openapi(
createRoute({
tags: ["ocp:printers"],
summary: "Stops the printers cycling.",
method: "get",
path: "/stopprintercycle",
middleware: authMiddleware,
//description: "This might be a temp soltuin during the transtion between versions",
// request: {
// body: {content: {"application/json": {schema: CreateLog}}},
// },
responses: responses(),
}),
async (c) => {
const { data, error } = await tryCatch(stopPrinterCycle());
const dataError: any = error;
if (error) {
return c.json({
success: false,
message: "Error in stopping the printer cycle",
data: dataError?.data,
});
}
const getData: any = data;
return c.json({
success: getData?.success,
message: getData?.message,
data: getData.data ?? [],
});
}
);
export default app;

View File

@@ -49,7 +49,7 @@ app.openapi(
return c.json({ return c.json({
success: getData?.success, success: getData?.success,
message: getData?.message, message: getData?.message,
data: getData.data ?? [], data: getData?.data ?? [],
}); });
} }
); );

View File

@@ -28,8 +28,8 @@ export const assignedPrinters = async () => {
}; };
} }
const printers: any = print.data; const printers: any = print.data ?? [];
const lots: any = l.data; const lots: any = l.data ?? [];
for (let i = 0; i < printers.length; i++) { for (let i = 0; i < printers.length; i++) {
// is the printer assinged in alplalabel online? // is the printer assinged in alplalabel online?

View File

@@ -1,6 +1,7 @@
import {z, createRoute, OpenAPIHono} from "@hono/zod-openapi"; import { z, createRoute, OpenAPIHono } from "@hono/zod-openapi";
import {modules} from "../../../../../database/schema/modules.js"; import { modules } from "../../../../../database/schema/modules.js";
import {db} from "../../../../../database/dbclient.js"; import { db } from "../../../../../database/dbclient.js";
import { desc } from "drizzle-orm";
// Define the request body schema // Define the request body schema
const requestSchema = z.object({ const requestSchema = z.object({
@@ -13,10 +14,16 @@ const requestSchema = z.object({
// Define the response schema // Define the response schema
const responseSchema = z.object({ const responseSchema = z.object({
message: z.string().optional(), message: z.string().optional(),
module_id: z.string().openapi({example: "6c922c6c-7de3-4ec4-acb0-f068abdc"}).optional(), module_id: z
name: z.string().openapi({example: "Production"}).optional(), .string()
active: z.boolean().openapi({example: true}).optional(), .openapi({ example: "6c922c6c-7de3-4ec4-acb0-f068abdc" })
roles: z.string().openapi({example: `["viewer","technician"]`}).optional(), .optional(),
name: z.string().openapi({ example: "Production" }).optional(),
active: z.boolean().openapi({ example: true }).optional(),
roles: z
.string()
.openapi({ example: `["viewer","technician"]` })
.optional(),
}); });
const app = new OpenAPIHono(); const app = new OpenAPIHono();
@@ -30,7 +37,7 @@ app.openapi(
responses: { responses: {
200: { 200: {
content: { content: {
"application/json": {schema: responseSchema}, "application/json": { schema: responseSchema },
}, },
description: "Response message", description: "Response message",
}, },
@@ -40,7 +47,7 @@ app.openapi(
//console.log("system modules"); //console.log("system modules");
let module: any = []; let module: any = [];
try { try {
module = await db.select().from(modules); // .where(eq(modules.active, true)); module = await db.select().from(modules).orderBy(modules.name); // .where(eq(modules.active, true));
} catch (error) { } catch (error) {
console.log(error); console.log(error);
module = []; module = [];
@@ -49,7 +56,7 @@ app.openapi(
// parse the roles // parse the roles
const updateModules = module.map((m: any) => { const updateModules = module.map((m: any) => {
if (m.roles) { if (m.roles) {
return {...m, roles: m?.roles}; return { ...m, roles: m?.roles };
} }
return m; return m;
}); //JSON.parse(module[0]?.roles); }); //JSON.parse(module[0]?.roles);

View File

@@ -47,7 +47,10 @@ app.openapi(
//console.log("system modules"); //console.log("system modules");
let module: any = []; let module: any = [];
try { try {
module = await db.select().from(subModules); // .where(eq(modules.active, true)); module = await db
.select()
.from(subModules)
.orderBy(subModules.name); // .where(eq(modules.active, true));
} catch (error) { } catch (error) {
console.log(error); console.log(error);
module = []; module = [];

View File

@@ -3,42 +3,69 @@
* this will only run on a server start up * this will only run on a server start up
*/ */
import {db} from "../../../../database/dbclient.js"; import { db } from "../../../../database/dbclient.js";
import {modules} from "../../../../database/schema/modules.js"; import { modules } from "../../../../database/schema/modules.js";
import {createLog} from "../../logger/logger.js"; import { createLog } from "../../logger/logger.js";
// "view", "technician", "supervisor","manager", "admin", "systemAdmin" // "view", "technician", "supervisor","manager", "admin", "systemAdmin"
const newModules = [ const newModules: any = [
{name: "production", active: true, roles: ["viewer", "tester", "systemAdmin"]}, {
{name: "logistics", active: false, roles: ["viewer", "tester", "systemAdmin"]}, name: "production",
{name: "quality", active: false, roles: ["viewer", "manager", "tester", "systemAdmin"]}, active: true,
{name: "forklift", active: false, roles: ["manager", "admin", "tester", "systemAdmin"]}, roles: ["viewer", "tester", "systemAdmin"],
{name: "eom", active: false, roles: ["manager", "admin", "tester", "systemAdmin"]}, },
{name: "admin", active: true, roles: ["admin", "systemAdmin"]}, {
{name: "ocp", active: false, roles: ["viewer", "admin", "tester", "systemAdmin"]}, name: "logistics",
active: false,
roles: ["viewer", "manager", "supervisor", "tester", "systemAdmin"],
},
{
name: "quality",
active: false,
roles: ["viewer", "manager", "tester", "systemAdmin"],
},
{
name: "forklift",
active: false,
roles: ["manager", "admin", "tester", "systemAdmin"],
},
{
name: "eom",
active: false,
roles: ["manager", "admin", "tester", "systemAdmin"],
},
{ name: "admin", active: true, roles: ["admin", "systemAdmin"] },
{
name: "ocp",
active: false,
roles: ["viewer", "admin", "tester", "systemAdmin"],
},
]; ];
export const areModulesIn = async () => { export const areModulesIn = async () => {
// get the roles // get the roles
try { for (let i = 0; i < newModules.length; i++) {
const moduleCheck = await db.select().from(modules); try {
const newRole = await db
if (moduleCheck.length !== newModules.length) {
try {
const newRole = await db
.insert(modules) .insert(modules)
.values(newModules) .values(newModules[i])
.onConflictDoNothing() // this will only update the ones that are new :D .onConflictDoUpdate({
.returning({name: modules.name}); target: modules.name,
createLog("info", "lst", "server", "Roles were just added due to missing them on server startup"); set: { roles: newModules[i].roles },
} catch (error) { }) // this will only update the ones that are new :D
createLog("error", "lst", "server", "There was an error adding new roles to the db"); .returning({ name: modules.name });
} } catch (error) {
console.log(error);
createLog(
"error",
"lst",
"server",
"There was an error adding new modules to the db"
);
} }
} catch (error) {
createLog(
"error",
"lst",
"server",
`Error: ${JSON.stringify(error)}"There was an error getting or adding new roles"`
);
} }
createLog(
"info",
"lst",
"server",
"Modules were just added due to missing them on server startup"
);
}; };

View File

@@ -15,7 +15,7 @@ const newSubModules = [
link: "/siloAdjustments", link: "/siloAdjustments",
icon: "Cylinder", icon: "Cylinder",
active: false, active: false,
roles: ["tester", "systemAdmin"], roles: ["technician", "supervisor", "manager", "admin", "systemAdmin"],
subSubModule: [], subSubModule: [],
}, },
{ {
@@ -38,16 +38,6 @@ const newSubModules = [
active: false, active: false,
subSubModule: [], subSubModule: [],
}, },
{
name: "Ocme cycle counts",
moduleName: "logistics",
description: "",
link: "#",
icon: "Package",
role: ["technician", "supervisor", "manager", "admin", "systemAdmin"],
active: false,
subSubModule: [],
},
{ {
name: "Material Helper", name: "Material Helper",
moduleName: "logistics", moduleName: "logistics",

View File

@@ -0,0 +1,80 @@
export const cycleCountCheck = `
-- Define the structure of the result set from the stored procedure
DECLARE @results TABLE (
IdLocation INT,
LastMoveDate Date
)
-- insert into the temp table
insert into @results
select IdLagerAbteilung, MAX(CaSE WHEN CONVERT(char(10), Buchungsdatum, 120) IS NULL THEN '1900-01-01' ELSE CONVERT(char(10), Buchungsdatum, 120) END) AS LastLocMov
from AlplaPROD_test1.dbo.V_LagerBuchungen x(nolock)
group by IdLagerAbteilung
select * from (
select x.IdLagerAbteilung as laneID,
x.IdWarenLager as warehouseID,
w.Bezeichnung as warehouseName,
w.LagerTyp as warehouseIDTyp,
w.Standort as warehouseLocation,
x.Bezeichnung as Description,
LastMoveDate,
CASE WHEN CONVERT(char(10), i.Datum, 120) is null then getdate() - 365 else CONVERT(char(10), i.Datum, 120) end as LastInv,
--create the types of warehouses to choose from
case
-- empty
when (sum(EinlagerungsMengeSum) is null and Datum < LastMoveDate) or (
(sum(EinlagerungsMengeSum) is null and Datum < DATEADD(day, -[ageOfRow], getdate()))
) then 'EMPTY'
-- finished goods
when w.LagerTyp = 2 and w.Standort = 10 then 'FG'
-- external finished goods
when w.LagerTyp = 2 and w.Standort = 20 then 'EXTERNAL'
-- silos
when w.LagerTyp in (3) and x.MaterialSilo = 1 then 'BULK'
-- MATERIALS
when w.LagerTyp = 3 and x.MaterialSilo = 0 then 'MATERIALS'
-- MATERIALS
when w.LagerTyp = 11 then 'WASTE'
-- MATERIALS
when w.LagerTyp = 9 then 'PACKAGING'
end as rowType,
CASE WHEN DateDiff(DAY,i.Datum,getDate()) is null then 1000 else DateDiff(DAY,i.Datum,getDate()) end as DaysSinceLast
from AlplaPROD_test1.dbo.T_LagerAbteilungen as x (NOLOCK)
-- last move
left join
@results as b on
x.IdLagerAbteilung = b.IdLocation
-- last inv
left join
(select * from [AlplaPROD_test1].[dbo].[T_LagerAbteilungenInventuren] (nolock)) as i on x.IdLagerAbteilung =
i.IdLagerAbteilung
-- useing this to determin only if the lane is empty
left join
(select * from [AlplaPROD_test1].dbo.V_LagerPositionenBarcodes (nolock)) as y on x.IdLagerAbteilung =
y.IdLagerAbteilung
-- get the warehosue type
left join
(select * from [AlplaPROD_test1].dbo.T_WarenLager (nolock)) as w on x.IdWarenLager = w.IdWarenLager
where x.aktiv = 1 and x.IdWarenLager not in (1,5,6)
group by x.IdLagerAbteilung,
x.IdWarenLager,
w.LagerTyp,
w.Standort,
x.Bezeichnung,
LastMoveDate,
i.Datum,
x.MaterialSilo,
w.Bezeichnung
) xb
`;