Compare commits

...

22 Commits

Author SHA1 Message Date
995311c563 feat(querys): plant query for gln and label data for sscc and other info 2025-03-10 16:59:17 -05:00
123d8a09ba feat(ocme): new setting for determining the fifo check 2025-03-10 16:58:48 -05:00
4fe400af3b refactor(modules): changed how the defaults are on some modules 2025-03-10 16:58:30 -05:00
8c31ac723d test(ocme): shipment pallets 2025-03-10 16:58:06 -05:00
a5cd8433f7 refactor(ocme): postRunning number removed bloat 2025-03-10 16:35:29 -05:00
c5f12814ea feat(ocme): pickedup route added 2025-03-10 16:35:07 -05:00
e2562768a5 refactor(ocme): added in apihits to getinfo 2025-03-10 16:34:46 -05:00
971038b10e feat(ocme): finalized posting RN and sscc just to keep it the same as ocme 2025-03-10 16:34:25 -05:00
1bcb4db328 feat(ocme): added in picked up and included a all function to reduce endpoints 2025-03-10 16:33:24 -05:00
f15afe5c11 refactor(ocme): changes made so that we only get the not picked up pallets 2025-03-10 16:32:37 -05:00
0e579c84b5 refactor(server:consume): change so error returns 200 so we can see the true error 2025-03-10 16:32:02 -05:00
40b970ef92 refactor(logger): changed so that everything comes over as lowerCase to make it more easy to search 2025-03-10 16:31:27 -05:00
0eb60706e4 feat(roles): added tester role 2025-03-10 16:29:13 -05:00
27d242f4f3 refactor(register): split the code to be more standard to the rest of the app 2025-03-10 16:22:46 -05:00
cd4109533e fix(auth): changed the profile update so we can run correctly now 2025-03-10 16:20:07 -05:00
8b1c65db4e feat(sscc): added in a creation of the sscc for now only ocme but will extend to be label data 2025-03-10 16:19:33 -05:00
6d1157a9d0 refactor(server): added in ability to listen on all ip's 2025-03-10 16:19:04 -05:00
9df643ce6b feat(materials): added in comsumption card to consume based on running nr 2025-03-10 16:18:25 -05:00
6c4e14fad3 feat(permissions): more permissions for accessing via sidbar 2025-03-10 16:17:57 -05:00
22e050ebfa test(apihits): framework for apiHits to be implemented but no db insert yet 2025-03-10 16:16:46 -05:00
008717b988 refactor(db): added in a db config for dev 2025-03-10 16:16:07 -05:00
65b35bc9a3 fix(user): when user didnt hape permissions would error, changed to have undefined now 2025-03-10 09:35:52 -05:00
33 changed files with 751 additions and 80 deletions

View File

@@ -0,0 +1,26 @@
import {pgTable, text, timestamp} from "drizzle-orm/pg-core";
import {createSelectSchema} from "drizzle-zod";
export const apiHits = pgTable(
"apiHits",
{
ip: text("ip"),
endpoint: text("endpoint"),
action: text("action"),
lastBody: text("lastBody"),
stats: text("stats"),
add_date: timestamp().defaultNow(),
upd_date: timestamp().defaultNow(),
}
// (table) => [
// // uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`),
// uniqueIndex("role_name").on(table.name),
// ]
);
// Schema for inserting a user - can be used to validate API requests
// export const insertRolesSchema = createInsertSchema(roles, {
// 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(apiHits);

14
drizzle-dev.config.ts Normal file
View File

@@ -0,0 +1,14 @@
import {defineConfig} from "drizzle-kit";
import dotenv from "dotenv";
dotenv.config();
const database = process.env.DATABASE_URL! || "";
export default defineConfig({
dialect: "postgresql", // 'mysql' | 'sqlite' | 'turso'
schema: "database/schema",
out: "database/migrations",
dbCredentials: {
url: database,
},
});

View File

@@ -19,7 +19,12 @@ export function AppSidebar() {
<Sidebar collapsible="icon">
<SidebarContent>
<Header />
{moduleActive("production") && <ProductionSideBar />}
{moduleActive("production") && (
<ProductionSideBar
user={user}
moduleID={modules.filter((n) => n.name === "production")[0].module_id as string}
/>
)}
{moduleActive("logistics") && (
<LogisticsSideBar
user={user}

View File

@@ -15,7 +15,7 @@ const items = [
title: "Silo Adjustments",
url: "#",
icon: Cylinder,
role: ["technician", "supervisor", "manager", "admin", "systemAdmin"],
role: ["admin", "systemAdmin"],
module: "logistics",
active: true,
},
@@ -23,7 +23,7 @@ const items = [
title: "Bulk orders",
url: "#",
icon: Truck,
role: ["technician", "supervisor", "manager", "admin", "systemAdmin"],
role: ["systemAdmin"],
module: "logistics",
active: true,
},
@@ -31,7 +31,7 @@ const items = [
title: "Forecast",
url: "#",
icon: Truck,
role: ["technician", "supervisor", "manager", "admin", "systemAdmin"],
role: ["systemAdmin"],
module: "logistics",
active: true,
},
@@ -43,6 +43,14 @@ const items = [
module: "logistics",
active: false,
},
{
title: "Material Helper",
url: "/materialHelper/consumption",
icon: Package,
role: ["technician", "supervisor", "manager", "admin", "systemAdmin"],
module: "logistics",
active: true,
},
];
export function LogisticsSideBar({user, moduleID}: {user: User | null; moduleID: string}) {

View File

@@ -7,16 +7,21 @@ import {
SidebarMenuButton,
SidebarMenuItem,
} from "../../ui/sidebar";
import {hasPageAccess} from "@/utils/userAccess";
import {User} from "@/types/users";
const items = [
{
title: "One Click Print",
url: "/ocp",
icon: Printer,
role: ["systemAdmin"],
module: "ocp",
active: true,
},
];
export function ProductionSideBar() {
export function ProductionSideBar({user, moduleID}: {user: User | null; moduleID: string}) {
return (
<SidebarGroup>
<SidebarGroupLabel>Production</SidebarGroupLabel>
@@ -24,12 +29,16 @@ export function ProductionSideBar() {
<SidebarMenu>
{items.map((item) => (
<SidebarMenuItem key={item.title}>
<SidebarMenuButton asChild>
<a href={item.url}>
<item.icon />
<span>{item.title}</span>
</a>
</SidebarMenuButton>
<>
{hasPageAccess(user, item.role, moduleID) && item.active && (
<SidebarMenuButton asChild>
<a href={item.url}>
<item.icon />
<span>{item.title}</span>
</a>
</SidebarMenuButton>
)}
</>
</SidebarMenuItem>
))}
</SidebarMenu>

View File

@@ -0,0 +1,97 @@
import {LstCard} from "@/components/extendedUI/LstCard";
import {Button} from "@/components/ui/button";
import {CardHeader} from "@/components/ui/card";
import {Input} from "@/components/ui/input";
import {Label} from "@/components/ui/label";
import axios from "axios";
import {useState} from "react";
import {useForm} from "react-hook-form";
import {toast} from "sonner";
export default function ConsumeMaterial() {
const {register: register1, handleSubmit: handleSubmit1, reset} = useForm();
const [submitting, setSubmitting] = useState(false);
const token = localStorage.getItem("auth_token");
const handleConsume = async (data: any) => {
setSubmitting(!submitting);
try {
const result = await axios.post(`/api/logistics/consume`, data, {
headers: {Authorization: `Bearer ${token}`},
});
if (result.data.success) {
toast.success(result.data.message);
setSubmitting(!submitting);
reset();
}
if (!result.data.success) {
//console.log(result.data);
setSubmitting(!submitting);
toast.error(result.data.message);
}
} catch (error: any) {
//console.log(error);
setSubmitting(!submitting);
if (error.status === 401) {
toast.error("Unauthorized to do this task.");
} else {
toast.error("Unexpected error if this continues please constact an admin.");
}
}
};
return (
<div className="m-2">
<LstCard>
<CardHeader>
<p className="text-center text-lg">Consuming Material.</p>
</CardHeader>
<div className="flex m-1">
<div className="w-96 m-1">
<LstCard>
<form onSubmit={handleSubmit1(handleConsume)}>
<div className="m-2">
<Label htmlFor="runningNr">Enter unit running number</Label>
<Input
className="mt-2"
//defaultValue="634"
type="number"
{...register1("runningNr")}
/>
</div>
<div className="m-2">
<Label htmlFor="lotNum">Enter lot number</Label>
<Input
className="mt-2"
//defaultValue="634"
type="number"
{...register1("lotNum")}
/>
</div>
<Button className="m-2" color="primary" type="submit" disabled={submitting}>
Consume materal
</Button>
</form>
</LstCard>
</div>
<div className="m-1 p-1">
<LstCard>
<div className="w-96 p-1">
<ol>
<li>1. Enter the running number of the material you would like to consume</li>
<li>2. Enter the lot number you will be consuming to</li>
<li>3. Press consume material</li>
</ol>
<p className="text-pretty w-96">
*This process is only for barcoded material, if it is set to auto consume you will
encounter and error.
</p>
</div>
</LstCard>
</div>
</div>
</LstCard>
</div>
);
}

View File

@@ -1,11 +1,25 @@
import { createFileRoute } from '@tanstack/react-router'
import ConsumeMaterial from "@/components/logistics/materialHelper/consumption/ConsumeMaterial";
import {createFileRoute} from "@tanstack/react-router";
export const Route = createFileRoute(
'/(logistics)/materialHelper/consumption/',
)({
component: RouteComponent,
})
export const Route = createFileRoute("/(logistics)/materialHelper/consumption/")({
component: RouteComponent,
head: () => ({
meta: [
{
name: "description",
content: "My App is a web application",
},
{
title: "LST - Logistics",
},
],
}),
});
function RouteComponent() {
return <div>Hello "/(logistics)/materialHelper/consumption/"!</div>
return (
<div>
<ConsumeMaterial />
</div>
);
}

View File

@@ -3,6 +3,17 @@ import {createFileRoute} from "@tanstack/react-router";
export const Route = createFileRoute("/(logistics)/materialHelper/")({
component: RouteComponent,
head: () => ({
meta: [
{
name: "description",
content: "My App is a web application",
},
{
title: "LST - Logistics",
},
],
}),
});
function RouteComponent() {

View File

@@ -18,7 +18,7 @@ export function hasPageAccess(user: User | null, role: any, module_id: string):
// get only the module in the user profile
const userRole = user?.roles.filter((role) => role.module_id === module_id);
if (role.includes(userRole[0].role)) {
if (role.includes(userRole[0]?.role)) {
return true;
}

View File

@@ -6,6 +6,8 @@
"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:frontend": "cd frontend && npm run dev",
"dev:dbgen": " drizzle-kit generate --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:server": "rimraf dist && tsc --build && xcopy server\\scripts dist\\server\\scripts /E /I /Y",
"build:frontend": "cd frontend && npm run build",

View File

@@ -6,6 +6,7 @@ const requestSchema = z.object({
ip: z.string().optional(),
endpoint: z.string(),
action: z.string().optional(),
lastBody: z.string().optional(),
stats: z.string().optional(),
});
@@ -13,19 +14,25 @@ type ApiHitData = z.infer<typeof requestSchema>;
export const apiHit = async (
c: Context,
data: unknown
data: ApiHitData
): Promise<{success: boolean; data?: ApiHitData; errors?: any[]}> => {
// console.log(data);
try {
// Extract IP from request headers or connection info
const forwarded = c.req.header("host");
//console.log(forwarded);
console.log(forwarded);
// Validate the data
const validatedData = requestSchema.parse(data);
const checkData = {
ip: forwarded!,
endpoint: data?.endpoint,
lastBody: data?.lastBody,
action: data?.action,
stats: data?.stats,
};
const validatedData = requestSchema.parse(checkData);
// Proceed with the validated data
// console.log("Validated Data:", validatedData);
return {success: true, data: validatedData};
} catch (error) {
// Explicitly check if the error is an instance of ZodError

View File

@@ -0,0 +1,50 @@
import {eq} from "drizzle-orm";
import {db} from "../../database/dbclient.js";
import {settings} from "../../database/schema/settings.js";
import {query} from "../services/sqlServer/prodSqlServer.js";
import {plantInfo} from "../services/sqlServer/querys/dataMart/plantInfo.js";
import {createLog} from "../services/logger/logger.js";
export const createSSCC = async (runningNumber: number) => {
// get the token
const plantToken = await db.select().from(settings).where(eq(settings.name, "plantToken"));
let global; // get from plant address in basis enter the entire string here.
try {
global = await query(plantInfo.replaceAll("[token]", plantToken[0].value), "plantInfo");
} catch (error) {
createLog("error", "lst", "globalUtils", `There was an error getting the GLN: Error: ${error}`);
}
// create the sscc without the check diget and make sure we have it all correct
let step1SSCC = global[0].gln.toString().slice(0, 7).padStart(10, "0") + runningNumber.toString().padStart(9, "0");
let sum = 0;
for (let i = 0; i < step1SSCC.length; i++) {
let digit = parseInt(step1SSCC[i], 10);
if (i % 2 === 0) {
// Even index in 0-based index system means odd position in 1-based index system
sum += digit * 3;
} else {
sum += digit;
}
}
let checkDigit = (10 - (sum % 10)) % 10;
// make sure the check digit is never 10
// let checkDigit = 10 - ((oddSum * 3 + evenSum) % 10) === 10 ? 0 : (oddSum * 3 + evenSum) % 10;
// return the true sscc
let sscc = step1SSCC + checkDigit;
// console.log(step1SSCC);
// console.log(checkDigit);
return sscc.padStart(20, "0");
};
// let rn = 518475;
// console.log(`Creating sscc`);
// let sscc = await createSSCC(rn);
// console.log(sscc);

View File

@@ -15,8 +15,19 @@ import tcpServer from "./services/tcpServer/tcpServer.js";
import ocme from "./services/ocme/ocmeService.js";
import sqlService from "./services/sqlServer/sqlService.js";
import logistics from "./services/logistics/logisticsService.js";
import {db} from "../database/dbclient.js";
import {settings} from "../database/schema/settings.js";
import {eq} from "drizzle-orm";
const allowedOrigins = ["http://localhost:3000", "http://localhost:4000", "http://localhost:5173"];
// plant token
const dbServer = await db.select().from(settings).where(eq(settings.name, "dbServer"));
const serverPort = await db.select().from(settings).where(eq(settings.name, "serverPort"));
const allowedOrigins = [
"http://localhost:3000",
"http://localhost:4000",
"http://localhost:5173",
`http://usmcd1vms006:4000`,
];
const app = new OpenAPIHono();
// middle ware
@@ -110,9 +121,10 @@ serve(
{
fetch: app.fetch,
port: Number(process.env.VITE_SERVER_PORT),
hostname: "0.0.0.0",
},
(info) => {
createLog("info", "LST", "server", `Server is running on http://localhost:${info.port}`);
createLog("info", "LST", "server", `Server is running on http://${info.address}:${info.port}`);
}
);

View File

@@ -20,7 +20,7 @@ app.route("auth/session", session);
// required to login
/* User area just needs to be logged in to enter here */
app.route("auth/profileUpdate", profile);
app.route("auth/profileupdate", profile);
/* will need to increase to make sure the person coming here has the correct permissions */
app.route("auth/getuseraccess", getAccess);

View File

@@ -1 +1,46 @@
export const registerUser = async () => {};
import {eq} from "drizzle-orm";
import {db} from "../../../../database/dbclient.js";
import {users} from "../../../../database/schema/users.js";
import {createPassword} from "../utils/createPassword.js";
import {setSysAdmin} from "./userRoles/setSysAdmin.js";
export const registerUser = async (username: string, password: string, email: string) => {
const usercount = await db.select().from(users);
// make sure the user dose not already exist in the system
const userCheck = await db.select().from(users).where(eq(users.username, username));
if (userCheck.length === 1) {
return {
success: false,
message: `${username} already exists please login or reset password, if you feel this is an error please contact your admin.`,
};
}
// make sure we only send over a username that is all lowercase
username = username.toLowerCase();
// get the good kinda password
password = await createPassword(password);
try {
const user = await db
.insert(users)
.values({username, email, password})
.returning({user: users.username, email: users.email});
if (usercount.length <= 1) {
console.log(`${username} is the first user and will be set to system admin.`);
const updateUser = await db.select().from(users).where(eq(users.username, username));
setSysAdmin(updateUser, "systemAdmin");
}
return {sucess: true, message: "User Registered", user};
} catch (error) {
console.log(error);
return {
success: false,
message: `${username} already exists please login or reset password, if you feel this is an error please contact your admin.`,
};
}
};

View File

@@ -1,9 +1,6 @@
import {z, createRoute, OpenAPIHono} from "@hono/zod-openapi";
import {db} from "../../../../database/dbclient.js";
import {users} from "../../../../database/schema/users.js";
import {apiHit} from "../../../globalUtils/apiHits.js";
import {createPassword} from "../utils/createPassword.js";
import {eq} from "drizzle-orm";
import {registerUser} from "../controllers/register.js";
const app = new OpenAPIHono();
@@ -24,6 +21,7 @@ const UserSchema = z.object({
type User = z.infer<typeof UserSchema>;
const responseSchema = z.object({
success: z.boolean().optional().openapi({example: true}),
message: z.string().optional().openapi({example: "User Created"}),
});
@@ -79,32 +77,10 @@ app.openapi(
);
}
// make sure the user dose not already exist in the system
const userCheck = await db.select().from(users).where(eq(users.username, username));
if (userCheck.length === 1) {
return c.json(
{
success: false,
message: `${username} already exists please login or reset password, if you feel this is an error please contact your admin.`,
},
400
);
}
// make sure we only send over a username that is all lowercase
username = username.toLowerCase();
// get the good kinda password
password = await createPassword(password);
try {
const user = await db
.insert(users)
.values({username, email, password})
.returning({user: users.username, email: users.email});
const register = await registerUser(username, password, email);
return c.json({message: "User Registered", user}, 200);
return c.json({success: register.success, message: register.message, user: register?.user}, 200);
} catch (error) {
console.log(error);
return c.json(

View File

@@ -13,6 +13,7 @@ const newRoles = [
{name: "supervisor"},
{name: "manager"},
{name: "admin"},
{name: "tester"},
{name: "systemAdmin"},
];
export const areRolesIn = async () => {

View File

@@ -17,8 +17,8 @@ export default async function (log: Log) {
// Insert log entry into the PostgreSQL database using Drizzle ORM
await db.insert(logs).values({
level: obj.level,
username: obj?.username,
service: obj?.service,
username: obj?.username.toLowerCase(),
service: obj?.service.toLowerCase(),
message: obj.msg,
});
}

View File

@@ -27,7 +27,7 @@ export const consumeMaterial = async (data: Data, prod: any) => {
if (barcode.length === 0) {
return {
success: false,
message: "The running number provided is not in stock please check if stock and try again.",
message: "The running number you've is not in stock.",
};
//throw Error("The provided runningNr is not in stock");
}
@@ -49,6 +49,6 @@ export const consumeMaterial = async (data: Data, prod: any) => {
//console.log(results);
return {success: true, message: "Material was consumed", status: results.status};
} catch (error: any) {
return {success: false, status: error.response?.status, message: error.response?.data.errors[0].message};
return {success: false, status: 200, message: error.response?.data.errors[0].message};
}
};

View File

@@ -2,11 +2,12 @@ import {db} from "../../../../database/dbclient.js";
import {ocmeData} from "../../../../database/schema/ocme.js";
import {differenceInMinutes} from "date-fns";
import {createLog} from "../../logger/logger.js";
import {eq} from "drizzle-orm";
export const getInfo = async () => {
let ocmeInfo: any = [];
try {
ocmeInfo = await db.select().from(ocmeData);
ocmeInfo = await db.select().from(ocmeData).where(eq(ocmeData.pickedUp, false));
// add in the time difference
ocmeInfo = ocmeInfo.map((o: any) => {
@@ -14,6 +15,7 @@ export const getInfo = async () => {
const diff = differenceInMinutes(now, o.add_Date!);
return {...o, waitingFor: diff};
});
createLog("info", "ocme", "ocme", `There are ${ocmeInfo.length} pallet(s) to be picked up.`);
} catch (error) {
createLog("error", "ocme", "ocme", "There was an error trying to retrive the ocmeInfo.");
throw Error("There was an error trying to retrive the.");

View File

@@ -0,0 +1,42 @@
import {eq, sql} from "drizzle-orm";
import {db} from "../../../../database/dbclient.js";
import {ocmeData} from "../../../../database/schema/ocme.js";
import {createLog, logLevel} from "../../logger/logger.js";
export const pickedup = async (data: any) => {
if (data.sscc && !data.runningNr) {
data.runningNr = data.sscc.slice(10, -1);
}
if (!data.sscc && !data.runningNr) {
// data.runningNr = data.sscc.slice(10, -1);
return {success: false, message: "Missing data please try again", data: []};
}
if (data.all) {
try {
const updateRn = await db
.update(ocmeData)
.set({pickedUp: true, upd_date: sql`NOW()`})
.returning({runningNr: ocmeData.runningNr});
createLog("info", "ocme", "ocme", `Pending pallets were just cleared out.`);
return {success: true, message: `Pending pallets were just cleared out.`, data: updateRn};
} catch (error) {
createLog("error", "ocme", "ocme", `Error clearing out the pallets.`);
return {success: false, message: `Error clearing out the pallets.`, error};
}
}
try {
const updateRn = await db
.update(ocmeData)
.set({pickedUp: true, upd_date: sql`NOW()`})
.where(eq(ocmeData.runningNr, data.runningNr))
.returning({runningNr: ocmeData.runningNr});
createLog("info", "ocme", "ocme", `${parseInt(data.runningNr)} was just pickedup`);
return {success: true, message: `${parseInt(data.runningNr)} was just pickedup`, data: updateRn};
} catch (error) {
createLog("error", "ocme", "ocme", `${parseInt(data.runningNr)} was just pickedup`);
return {success: false, message: `${parseInt(data.runningNr)} was not pickedup`, error};
}
};

View File

@@ -1,13 +1,43 @@
import {db} from "../../../../database/dbclient.js";
import {ocmeData} from "../../../../database/schema/ocme.js";
import {createSSCC} from "../../../globalUtils/createSSCC.js";
import {createLog} from "../../logger/logger.js";
import {query} from "../../sqlServer/prodSqlServer.js";
import {labelData} from "../../sqlServer/querys/materialHelpers/labelInfo.js";
export const postLabelData = async (data: any) => {
// if we have sscc we will do everything here and ignore the rn even it its sent over
if (data.sscc) {
return {success: true, message: "sscc sent over", data: data};
if (data.sscc && !data.runningNr) {
data.runningNr = data.sscc.slice(10, -1);
}
if (data.runningNr) {
return {success: true, message: "runningNr sent over", data: data};
} else {
throw Error("Improper data was sent over");
if (!data.sscc && !data.runningNr) {
// data.runningNr = data.sscc.slice(10, -1);
return {success: false, message: "Missing data please try again", data: []};
}
let label;
const filterQuery = labelData.replaceAll("[rn]", data.runningNr);
try {
label = await query(filterQuery, "Label data");
} catch (error) {
createLog("error", "ocme", "ocme", "There was an error getting the labelData");
}
const newPost = {
sscc: data.sscc ? data.sscc : await createSSCC(data.runningNr),
runningNr: data.runningNr,
completed: data.completed,
lineNum: label[0].machineLocation,
areaFrom: data.areaFrom,
pickedUp: false,
};
try {
const enterNewData = await db.insert(ocmeData).values(newPost).returning({sscc: ocmeData.sscc});
return {success: true, message: "Data was posted to ocme info", data: enterNewData};
} catch (error) {
console.log(error);
return {success: false, message: "Data was posted to ocme info", data: newPost};
}
};

View File

@@ -3,9 +3,13 @@ import {OpenAPIHono} from "@hono/zod-openapi";
// routes
import getInfo from "./route/getInfo.js";
import postRunningNr from "./route/postRunningNumber.js";
import pickedup from "./route/pickedUp.js";
import postsscc from "./route/postSSCC.js";
import getShipments from "./route/getShipmentPallets.js";
const app = new OpenAPIHono();
const routes = [getInfo, postRunningNr] as const;
const routes = [getInfo, postRunningNr, postsscc, pickedup, getShipments] as const;
// app.route("/server", modules);
const appRoutes = routes.forEach((route) => {

View File

@@ -1,5 +1,6 @@
import {createRoute, OpenAPIHono, z} from "@hono/zod-openapi";
import {getInfo} from "../controller/getInfo.js";
import {apiHit} from "../../../globalUtils/apiHits.js";
const app = new OpenAPIHono();
@@ -69,6 +70,7 @@ app.openapi(
}),
async (c) => {
// make sure we have a vaid user being accessed thats really logged in
apiHit(c, {endpoint: "api/auth/register"});
try {
return c.json({success: true, message: "Ocme Info", data: await getInfo()}, 200);
} catch (error) {

View File

@@ -0,0 +1,83 @@
import {createRoute, OpenAPIHono, z} from "@hono/zod-openapi";
import {apiHit} from "../../../globalUtils/apiHits.js";
const app = new OpenAPIHono();
const ShipmentID = z.object({
shipmentID: z.string().optional().openapi({example: "14558"}),
});
app.openapi(
createRoute({
tags: ["ocme"],
summary: "Post New running number to be picked up.",
method: "post",
path: "/getshipmentpallets",
request: {
body: {
content: {
"application/json": {schema: ShipmentID},
},
},
},
responses: {
200: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({example: true}),
message: z.string().openapi({example: "Starter"}),
// data: z
// .array(z.object({sscc: z.string().optional()}))
// .optional()
// .openapi({example: []}),
}),
},
},
description: "Response message",
},
400: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({example: false}),
message: z.string().optional().openapi({example: "Internal Server error"}),
data: z.array(z.object({})).optional().openapi({example: []}),
}),
},
},
description: "Internal Server Error",
},
// 401: {
// content: {
// "application/json": {
// schema: z.object({message: z.string().optional().openapi({example: "Unauthenticated"})}),
// },
// },
// description: "Unauthorized",
// },
// 500: {
// content: {
// "application/json": {
// schema: z.object({message: z.string().optional().openapi({example: "Internal Server error"})}),
// },
// },
// description: "Internal Server Error",
// },
},
}),
async (c) => {
// make sure we have a vaid user being accessed thats really logged in
try {
const data = await c.req.json();
apiHit(c, {endpoint: "api/ocme/getshipmentpallets", lastBody: data});
const postPallet = {success: true, message: "Something", data: []};
return c.json({success: postPallet.success, message: postPallet.message, data: postPallet.data ?? []}, 200);
} catch (error) {
return c.json({success: false, message: "There was an error getting the shipment data.", data: error}, 400);
}
}
);
export default app;

View File

@@ -0,0 +1,89 @@
import {createRoute, OpenAPIHono, z} from "@hono/zod-openapi";
import {postLabelData} from "../controller/postRunningNr.js";
import {apiHit} from "../../../globalUtils/apiHits.js";
import {pickedup} from "../controller/pickedup.js";
const app = new OpenAPIHono();
const PostRunningNr = z.object({
sscc: z.string().optional().openapi({example: "00090103830005710997"}),
runningNr: z.string().optional().openapi({example: "localhost"}),
areaFrom: z.string().optional().openapi({example: "The server we are going to connect to"}),
completed: z.boolean().optional().openapi({example: true}),
all: z.boolean().optional().openapi({example: false}),
});
app.openapi(
createRoute({
tags: ["ocme"],
summary: "Picks up a pallet in the system.",
method: "patch",
description:
"removes the pallet(s) from showing as needed to be picked up, we clear everything related to the pallet number to reduce the risk of a mix, passing `all` will just clear everything that is pending.",
path: "/pickedup",
request: {
body: {
content: {
"application/json": {schema: PostRunningNr},
},
},
},
responses: {
200: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({example: true}),
message: z.string().openapi({example: "Starter"}),
// data: z
// .array(z.object({sscc: z.string().optional()}))
// .optional()
// .openapi({example: []}),
}),
},
},
description: "Response message",
},
400: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({example: false}),
message: z.string().optional().openapi({example: "Internal Server error"}),
data: z.array(z.object({})).optional().openapi({example: []}),
}),
},
},
description: "Internal Server Error",
},
// 401: {
// content: {
// "application/json": {
// schema: z.object({message: z.string().optional().openapi({example: "Unauthenticated"})}),
// },
// },
// description: "Unauthorized",
// },
500: {
content: {
"application/json": {
schema: z.object({message: z.string().optional().openapi({example: "Internal Server error"})}),
},
},
description: "Internal Server Error",
},
},
}),
async (c) => {
// make sure we have a vaid user being accessed thats really logged in
try {
const data = await c.req.json();
apiHit(c, {endpoint: "api/ocme/pickedup", lastBody: data});
const postPallet = await pickedup(data);
return c.json({success: postPallet.success, message: postPallet.message, data: postPallet.data}, 200);
} catch (error) {
return c.json({success: false, message: "There was an error getting ocmeInfo data", data: error}, 400);
}
}
);
export default app;

View File

@@ -1,6 +1,7 @@
import {createRoute, OpenAPIHono, z} from "@hono/zod-openapi";
import {getInfo} from "../controller/getInfo.js";
import {postLabelData} from "../controller/postRunningNr.js";
import {apiHit} from "../../../globalUtils/apiHits.js";
const app = new OpenAPIHono();
@@ -31,7 +32,10 @@ app.openapi(
schema: z.object({
success: z.boolean().openapi({example: true}),
message: z.string().openapi({example: "Starter"}),
data: z.array(z.object({})).optional().openapi({example: []}),
// data: z
// .array(z.object({sscc: z.string().optional()}))
// .optional()
// .openapi({example: []}),
}),
},
},
@@ -71,8 +75,9 @@ app.openapi(
// make sure we have a vaid user being accessed thats really logged in
try {
const data = await c.req.json();
apiHit(c, {endpoint: "api/ocme/postRunningNumber", lastBody: data});
const postPallet = await postLabelData(data);
return c.json({success: postPallet.success, message: postPallet.message, data: postPallet.data}, 200);
return c.json({success: postPallet.success, message: postPallet.message, data: postPallet.data ?? []}, 200);
} catch (error) {
return c.json({success: false, message: "There was an error getting ocmeInfo data", data: error}, 400);
}

View File

@@ -0,0 +1,86 @@
import {createRoute, OpenAPIHono, z} from "@hono/zod-openapi";
import {getInfo} from "../controller/getInfo.js";
import {postLabelData} from "../controller/postRunningNr.js";
import {apiHit} from "../../../globalUtils/apiHits.js";
const app = new OpenAPIHono();
const PostRunningNr = z.object({
sscc: z.string().optional().openapi({example: "00090103830005710997"}),
runningNr: z.string().optional().openapi({example: "localhost"}),
areaFrom: z.string().optional().openapi({example: "The server we are going to connect to"}),
completed: z.boolean().optional().openapi({example: true}),
});
app.openapi(
createRoute({
tags: ["ocme"],
summary: "Post New running number to be picked up.",
method: "post",
path: "/postsscc",
request: {
body: {
content: {
"application/json": {schema: PostRunningNr},
},
},
},
responses: {
200: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({example: true}),
message: z.string().openapi({example: "Starter"}),
// data: z
// .array(z.object({sscc: z.string().optional()}))
// .optional()
// .openapi({example: []}),
}),
},
},
description: "Response message",
},
400: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({example: false}),
message: z.string().optional().openapi({example: "Internal Server error"}),
data: z.array(z.object({})).optional().openapi({example: []}),
}),
},
},
description: "Internal Server Error",
},
// 401: {
// content: {
// "application/json": {
// schema: z.object({message: z.string().optional().openapi({example: "Unauthenticated"})}),
// },
// },
// description: "Unauthorized",
// },
// 500: {
// content: {
// "application/json": {
// schema: z.object({message: z.string().optional().openapi({example: "Internal Server error"})}),
// },
// },
// description: "Internal Server Error",
// },
},
}),
async (c) => {
// make sure we have a vaid user being accessed thats really logged in
try {
const data = await c.req.json();
apiHit(c, {endpoint: "api/ocme/postRunningNumber", lastBody: data});
const postPallet = await postLabelData(data);
return c.json({success: postPallet.success, message: postPallet.message, data: postPallet.data ?? []}, 200);
} catch (error) {
return c.json({success: false, message: "There was an error getting ocmeInfo data", data: error}, 400);
}
}
);
export default app;

View File

@@ -8,13 +8,13 @@ import {modules} from "../../../../database/schema/modules.js";
import {createLog} from "../../logger/logger.js";
// "view", "technician", "supervisor","manager", "admin", "systemAdmin"
const newModules = [
{name: "production", active: false, roles: ["viewer", "systemAdmin"]},
{name: "logistics", active: false, roles: ["viewer", "systemAdmin"]},
{name: "quality", active: false, roles: ["viewer", "manager", "systemAdmin"]},
{name: "forklift", active: false, roles: ["manager", "admin", "systemAdmin"]},
{name: "eom", active: false, roles: ["manager", "admin", "systemAdmin"]},
{name: "admin", active: false, roles: ["admin", "systemAdmin"]},
{name: "ocp", active: false, roles: ["viewer", "admin", "systemAdmin"]},
{name: "production", active: true, roles: ["viewer", "tester", "systemAdmin"]},
{name: "logistics", active: false, roles: ["viewer", "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 () => {
// get the roles

View File

@@ -56,6 +56,12 @@ const newSettings = [
description: "Dose the plant have 2 machines that go to 1?",
moduleName: "ocp",
},
{
name: "fifoCheck",
value: "45",
description: "How far back do we want to check for fifo default 45, putting 0 will ignore.",
moduleName: "ocme",
},
];
export const areSettingsIn = async () => {
// get the roles
@@ -69,12 +75,12 @@ export const areSettingsIn = async () => {
.values(newSettings)
.onConflictDoNothing() // this will only update the ones that are new :D
.returning({name: settings.name});
createLog("info", "lst", "server", "Roles were just added due to missing them on server startup");
createLog("info", "lst", "server", "Settingss were just added due to missing them on server startup");
} catch (error) {
createLog("error", "lst", "server", "There was an error adding new roles to the db");
}
}
} catch (error) {
createLog("error", "lst", "server", "There was an error getting or adding new roles");
createLog("error", "lst", "server", "There was an error getting or adding new Settingss");
}
};

View File

@@ -0,0 +1,12 @@
export const plantInfo = `
select werkkurzbez as plantToken,
gln,
IdAdressen as addressId,
Bezeichnung as addressDecriptuion,
Strasse as streetAddress,
plz as zipcode,
ort as cityState
--,*
from alplaprod_test1.dbo.T_Adressen where werkkurzbez = '[token]'
`;

View File

@@ -1,3 +1,20 @@
export const labelData = `
select Barcode as barcode from alplaprod_test1.dbo.V_LagerPositionenBarcodes (NOLOCK) where lfdnr = [rn]
select x.Barcode as barcode,
Produktionslos as lot,
x.IdArtikelVarianten as article,
x.ArtikelVariantenBez as description,
m.Standort as machineLocation,
m.Bezeichnung as machineDescription,
e.IdEtikettenDrucker as printer,
x.LfdNr as runningNr
from alplaprod_test1.dbo.V_LagerPositionenBarcodes x (NOLOCK)
left join
alplaprod_test1.dbo.T_EtikettenGedruckt as e
on x.Lfdnr = e.LfdNr
left join
alplaprod_test1.dbo.T_Maschine as m on
e.IdMaschine = m.IdMaschine
where x.lfdnr = [rn] and x.IdWarenlager not in(6)
`;

View File

@@ -0,0 +1,16 @@
export const shipmentPallets = `
select TOP([totalPallets]) IdLagerAbteilung as laneId,
LagerAbteilungKurzBez as lane,
Produktionslos as lotNum,
lfdnr as runningNumber,
IdAdresse as addressID,
BewegungsDatumMax as lastMove, IdArtikelVarianten as article
from AlplaPROD_test1.dbo.V_LagerPositionenBarcodes (nolock)
where IdArtikelVarianten = [article]
and LagerAbteilungKurzBez in ([lanes])
and GesperrtAktivSum in (0)
order by CASE
WHEN BewegungsDatumMax <= DATEADD(DAY, -[fifo], GETDATE()) THEN 0
ELSE 1
END desc
`;