Compare commits
4 Commits
566754bf2e
...
a30eebf5d3
| Author | SHA1 | Date | |
|---|---|---|---|
| a30eebf5d3 | |||
| 9aa0b31278 | |||
| 33cbb17a0e | |||
| 242ff6277a |
@@ -1,7 +1,7 @@
|
|||||||
vars {
|
vars {
|
||||||
url: http://localhost:4200
|
url: http://localhost:4200
|
||||||
session_cookie:
|
session_cookie:
|
||||||
urlv2: http://localhost:3000
|
urlv2: http://usmcd1vms036:3000
|
||||||
jwtV2:
|
jwtV2:
|
||||||
userID:
|
userID:
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ export type UserRoles = {
|
|||||||
| "supervisor"
|
| "supervisor"
|
||||||
| "manager"
|
| "manager"
|
||||||
| "admin"
|
| "admin"
|
||||||
| "systemAdmin";
|
| "systemAdmin"
|
||||||
|
| "user";
|
||||||
};
|
};
|
||||||
|
|
||||||
type UserRoleState = {
|
type UserRoleState = {
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ export default function TableNoExpand({
|
|||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<div className="p-4">
|
<div className="p-4">
|
||||||
<ScrollArea className="w-11/12 rounded-md border whitespace-nowrap">
|
<Table className="table-fixed w-full">
|
||||||
<Table>
|
<ScrollArea className="w-full rounded-md border whitespace-nowrap">
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
{table.getHeaderGroups().map((headerGroup) => (
|
{table.getHeaderGroups().map((headerGroup) => (
|
||||||
<TableRow key={headerGroup.id}>
|
<TableRow key={headerGroup.id}>
|
||||||
@@ -89,27 +89,28 @@ export default function TableNoExpand({
|
|||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
))}
|
))}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
<ScrollBar orientation="horizontal" />
|
||||||
<div className="flex items-center justify-end space-x-2 py-4">
|
</ScrollArea>
|
||||||
<Button
|
</Table>
|
||||||
variant="outline"
|
|
||||||
size="sm"
|
<div className="flex items-center justify-end space-x-2 py-4">
|
||||||
onClick={() => table.previousPage()}
|
<Button
|
||||||
disabled={!table.getCanPreviousPage()}
|
variant="outline"
|
||||||
>
|
size="sm"
|
||||||
Previous
|
onClick={() => table.previousPage()}
|
||||||
</Button>
|
disabled={!table.getCanPreviousPage()}
|
||||||
<Button
|
>
|
||||||
variant="outline"
|
Previous
|
||||||
size="sm"
|
</Button>
|
||||||
onClick={() => table.nextPage()}
|
<Button
|
||||||
disabled={!table.getCanNextPage()}
|
variant="outline"
|
||||||
>
|
size="sm"
|
||||||
Next
|
onClick={() => table.nextPage()}
|
||||||
</Button>
|
disabled={!table.getCanNextPage()}
|
||||||
</div>
|
>
|
||||||
<ScrollBar orientation="horizontal" />
|
Next
|
||||||
</ScrollArea>
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,13 @@ export const Route = createFileRoute("/_old/old/(logistics)/siloAdjustments/")({
|
|||||||
component: RouteComponent,
|
component: RouteComponent,
|
||||||
beforeLoad: async () => {
|
beforeLoad: async () => {
|
||||||
const auth = await checkUserAccess({
|
const auth = await checkUserAccess({
|
||||||
allowedRoles: ["systemAdmin", "technician", "admin", "manager"],
|
allowedRoles: [
|
||||||
|
"systemAdmin",
|
||||||
|
"technician",
|
||||||
|
"admin",
|
||||||
|
"manager",
|
||||||
|
"supervisor",
|
||||||
|
],
|
||||||
moduleName: "siloAdjustments", // optional
|
moduleName: "siloAdjustments", // optional
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
//import { LstCard } from "@/components/extendedUI/LstCard";
|
//import { LstCard } from "@/components/extendedUI/LstCard";
|
||||||
|
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { LstCard } from "@/components/ui/lstCard";
|
||||||
|
import TableNoExpand from "@/lib/tableStuff/TableNoExpand";
|
||||||
import { getPPOO } from "../../../-utils/querys/logistics/getPPOO";
|
import { getPPOO } from "../../../-utils/querys/logistics/getPPOO";
|
||||||
import { columns } from "../../../-utils/tableData/ppoo/ppooColumns";
|
import { columns } from "../../../-utils/tableData/ppoo/ppooColumns";
|
||||||
import { PPOOTable } from "../../../-utils/tableData/ppoo/ppooData";
|
|
||||||
//import { CircleX } from "lucide-react";
|
//import { CircleX } from "lucide-react";
|
||||||
//import { Suspense } from "react";
|
//import { Suspense } from "react";
|
||||||
//import { toast } from "sonner";
|
//import { toast } from "sonner";
|
||||||
@@ -12,7 +13,7 @@ export default function PPOO() {
|
|||||||
//{ style = {} }
|
//{ style = {} }
|
||||||
const { data, isError, isLoading } = useQuery(getPPOO());
|
const { data, isError, isLoading } = useQuery(getPPOO());
|
||||||
|
|
||||||
if (isLoading) return <div>Loading adjustmnet data...</div>;
|
if (isLoading) return <div>Loading adjustments data...</div>;
|
||||||
if (isError) {
|
if (isError) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@@ -28,11 +29,15 @@ export default function PPOO() {
|
|||||||
// };
|
// };
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PPOOTable
|
<>
|
||||||
columns={columns}
|
<LstCard className="">
|
||||||
data={data}
|
<TableNoExpand
|
||||||
//style={style}
|
columns={columns}
|
||||||
/>
|
data={data}
|
||||||
|
//style={style}
|
||||||
|
/>
|
||||||
|
</LstCard>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
// return (
|
// return (
|
||||||
// <div style={style}>
|
// <div style={style}>
|
||||||
|
|||||||
@@ -2,14 +2,16 @@ import { useQuery } from "@tanstack/react-query";
|
|||||||
import { useNavigate, useRouterState } from "@tanstack/react-router";
|
import { useNavigate, useRouterState } from "@tanstack/react-router";
|
||||||
import { createColumnHelper } from "@tanstack/react-table";
|
import { createColumnHelper } from "@tanstack/react-table";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { ArrowDown, ArrowUp } from "lucide-react";
|
import { ArrowDown, ArrowUp, Trash2 } from "lucide-react";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
Select,
|
Select,
|
||||||
SelectContent,
|
SelectContent,
|
||||||
|
SelectGroup,
|
||||||
SelectItem,
|
SelectItem,
|
||||||
|
SelectLabel,
|
||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select";
|
} from "@/components/ui/select";
|
||||||
@@ -30,7 +32,6 @@ type Pallets = {
|
|||||||
durationToMove: null;
|
durationToMove: null;
|
||||||
qualityDurationToInspect: number;
|
qualityDurationToInspect: number;
|
||||||
returnDurationToInspect: number;
|
returnDurationToInspect: number;
|
||||||
locationMovesTo: string;
|
|
||||||
locationDropOff: string;
|
locationDropOff: string;
|
||||||
palletStatus: number;
|
palletStatus: number;
|
||||||
palletStatusText: string;
|
palletStatusText: string;
|
||||||
@@ -40,6 +41,8 @@ type Pallets = {
|
|||||||
add_user: string;
|
add_user: string;
|
||||||
upd_date: Date;
|
upd_date: Date;
|
||||||
upd_user: string;
|
upd_user: string;
|
||||||
|
palletComplete: string;
|
||||||
|
canceled: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function QualityRequest() {
|
export default function QualityRequest() {
|
||||||
@@ -50,35 +53,35 @@ export default function QualityRequest() {
|
|||||||
const router = useRouterState();
|
const router = useRouterState();
|
||||||
const currentPath = router.location.href;
|
const currentPath = router.location.href;
|
||||||
|
|
||||||
const palletCompleted = async (e: any) => {
|
// const palletCompleted = async (e: any) => {
|
||||||
if (!session || !session.user) {
|
// if (!session || !session.user) {
|
||||||
toast.error("You are allowed to do this unless you are logged in");
|
// toast.error("You are allowed to do this unless you are logged in");
|
||||||
navigate({ to: "/login", search: { redirect: currentPath } });
|
// navigate({ to: "/login", search: { redirect: currentPath } });
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
const data = {
|
// const data = {
|
||||||
username: session?.user.username,
|
// username: session?.user.username,
|
||||||
runningNr: Number(e.original.runningNr),
|
// runningNr: Number(e.original.runningNr),
|
||||||
palletStatusText: "return",
|
// palletStatusText: "return",
|
||||||
};
|
// };
|
||||||
try {
|
// try {
|
||||||
const res = await axios.post("/lst/old/api/quality/newrequest", data);
|
// const res = await axios.post("/lst/old/api/quality/newrequest", data);
|
||||||
|
|
||||||
//console.log(res.data);
|
// //console.log(res.data);
|
||||||
|
|
||||||
if (res.data.success) {
|
// if (res.data.success) {
|
||||||
toast.success(res.data.message);
|
// toast.success(res.data.message);
|
||||||
refetch();
|
// refetch();
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (!res.data.success) {
|
// if (!res.data.success) {
|
||||||
toast.error(res.data.message);
|
// toast.error(res.data.message);
|
||||||
}
|
// }
|
||||||
} catch (error) {
|
// } catch (error) {
|
||||||
console.log(error);
|
// console.log(error);
|
||||||
toast.error("Encountered and error please try again");
|
// toast.error("Encountered and error please try again");
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
columnHelper.accessor("article", {
|
columnHelper.accessor("article", {
|
||||||
@@ -166,14 +169,14 @@ export default function QualityRequest() {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor("locationMovesTo", {
|
columnHelper.accessor("locationMovedTo", {
|
||||||
header: ({ column }) => {
|
header: ({ column }) => {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
||||||
>
|
>
|
||||||
<span className="flex flex-row gap-2">Location At Request</span>
|
<span className="flex flex-row gap-2">Location Moved to</span>
|
||||||
{column.getIsSorted() === "asc" ? (
|
{column.getIsSorted() === "asc" ? (
|
||||||
<ArrowUp className="ml-2 h-4 w-4" />
|
<ArrowUp className="ml-2 h-4 w-4" />
|
||||||
) : (
|
) : (
|
||||||
@@ -227,7 +230,7 @@ export default function QualityRequest() {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor("palletRequest", {
|
columnHelper.accessor("palletComplete", {
|
||||||
header: ({ column }) => {
|
header: ({ column }) => {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
@@ -245,15 +248,78 @@ export default function QualityRequest() {
|
|||||||
},
|
},
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
// if pending
|
// if pending
|
||||||
|
|
||||||
|
//const [p, setP] = useState(`${getValue()}`);
|
||||||
const okToCompleteStats = [2, 4, 5];
|
const okToCompleteStats = [2, 4, 5];
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{okToCompleteStats.includes(row.original.palletStatus) ? (
|
{okToCompleteStats.includes(row.original.palletStatus) ? (
|
||||||
<Button variant="outline" onClick={() => palletCompleted(row)}>
|
<Select
|
||||||
Check Complete
|
//value={"return to warehouse"}
|
||||||
</Button>
|
onValueChange={async (value) => {
|
||||||
|
if (!session || !session.user) {
|
||||||
|
toast.error(
|
||||||
|
"You are allowed to do this unless you are logged in",
|
||||||
|
);
|
||||||
|
navigate({
|
||||||
|
to: "/login",
|
||||||
|
search: { redirect: currentPath },
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
username: session?.user.username,
|
||||||
|
runningNr: Number(row.original.runningNr),
|
||||||
|
palletStatusText: value,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await axios.post(
|
||||||
|
"/lst/old/api/quality/newrequest",
|
||||||
|
data,
|
||||||
|
);
|
||||||
|
|
||||||
|
//console.log(res.data);
|
||||||
|
|
||||||
|
if (res.data.success) {
|
||||||
|
toast.success(res.data.message);
|
||||||
|
refetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!res.data.success) {
|
||||||
|
toast.error(res.data.message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
toast.error("Encountered and error please try again");
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SelectTrigger
|
||||||
|
// className={cn(
|
||||||
|
// "w-[100px]",
|
||||||
|
// active
|
||||||
|
// ? "border-green-500 text-green-600"
|
||||||
|
// : "border-gray-400 text-gray-500",
|
||||||
|
// )}
|
||||||
|
>
|
||||||
|
<SelectValue placeholder="Complete Selection" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectGroup>
|
||||||
|
<SelectLabel>Location to drop off</SelectLabel>
|
||||||
|
<SelectItem value="return to warehouse">
|
||||||
|
Return to Warehouse
|
||||||
|
</SelectItem>
|
||||||
|
<SelectItem value="rework">Rework</SelectItem>
|
||||||
|
<SelectItem value="grind">Grind</SelectItem>
|
||||||
|
<SelectItem value="scrap">Scrap</SelectItem>
|
||||||
|
</SelectGroup>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
) : (
|
) : (
|
||||||
<span>Pending to be completed</span>
|
<span>Pending move</span>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
@@ -262,7 +328,9 @@ export default function QualityRequest() {
|
|||||||
];
|
];
|
||||||
|
|
||||||
let adminColumns: any = [];
|
let adminColumns: any = [];
|
||||||
if (userAccess("quality", ["systemAdmin", "admin", "supervisor"])) {
|
if (
|
||||||
|
userAccess("quality", ["systemAdmin", "admin", "supervisor", "manager"])
|
||||||
|
) {
|
||||||
adminColumns = [
|
adminColumns = [
|
||||||
...columns,
|
...columns,
|
||||||
columnHelper.accessor("priority", {
|
columnHelper.accessor("priority", {
|
||||||
@@ -287,7 +355,6 @@ export default function QualityRequest() {
|
|||||||
// if pending
|
// if pending
|
||||||
|
|
||||||
const [p, setP] = useState(`${getValue()}`);
|
const [p, setP] = useState(`${getValue()}`);
|
||||||
console.log(getValue());
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Select
|
<Select
|
||||||
@@ -343,6 +410,78 @@ export default function QualityRequest() {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
columnHelper.accessor("palletComplete", {
|
||||||
|
header: ({ column }) => {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
onClick={() =>
|
||||||
|
column.toggleSorting(column.getIsSorted() === "asc")
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span className="flex flex-row gap-2">Cancel</span>
|
||||||
|
{column.getIsSorted() === "asc" ? (
|
||||||
|
<ArrowUp className="ml-2 h-4 w-4" />
|
||||||
|
) : (
|
||||||
|
<ArrowDown className="ml-2 h-4 w-4" />
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
cell: ({ row }) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
//value={"return to warehouse"}
|
||||||
|
variant="destructive"
|
||||||
|
onClick={async () => {
|
||||||
|
if (!session || !session.user) {
|
||||||
|
toast.error(
|
||||||
|
"You are allowed to do this unless you are logged in",
|
||||||
|
);
|
||||||
|
navigate({
|
||||||
|
to: "/login",
|
||||||
|
search: { redirect: currentPath },
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
username: session?.user.username,
|
||||||
|
runningNr: Number(row.original.runningNr),
|
||||||
|
palletStatusText: "canceled",
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await axios.post(
|
||||||
|
"/lst/old/api/quality/newrequest",
|
||||||
|
data,
|
||||||
|
);
|
||||||
|
|
||||||
|
//console.log(res.data);
|
||||||
|
|
||||||
|
if (res.data.success) {
|
||||||
|
toast.success(
|
||||||
|
`${row.original.runningNr} was just canceled`,
|
||||||
|
);
|
||||||
|
refetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!res.data.success) {
|
||||||
|
toast.error(res.data.message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
toast.error("Encountered and error please try again");
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Trash2 className="w-[24px] h-[24px]" />
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ export default function PPOO() {
|
|||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
||||||
|
className="w-16 ml-1"
|
||||||
>
|
>
|
||||||
<span className="flex flex-row gap-2">Article</span>
|
<span className="flex flex-row gap-2">Article</span>
|
||||||
{column.getIsSorted() === "asc" ? (
|
{column.getIsSorted() === "asc" ? (
|
||||||
@@ -63,6 +64,7 @@ export default function PPOO() {
|
|||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
||||||
|
className="w-16 ml-1"
|
||||||
>
|
>
|
||||||
<span className="flex flex-row gap-2">Running Number</span>
|
<span className="flex flex-row gap-2">Running Number</span>
|
||||||
{column.getIsSorted() === "asc" ? (
|
{column.getIsSorted() === "asc" ? (
|
||||||
@@ -80,6 +82,7 @@ export default function PPOO() {
|
|||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
||||||
|
className="w-16 ml-1"
|
||||||
>
|
>
|
||||||
<span className="flex flex-row gap-2">Location</span>
|
<span className="flex flex-row gap-2">Location</span>
|
||||||
{column.getIsSorted() === "asc" ? (
|
{column.getIsSorted() === "asc" ? (
|
||||||
@@ -97,8 +100,9 @@ export default function PPOO() {
|
|||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
||||||
|
className="w-16 ml-1"
|
||||||
>
|
>
|
||||||
<span className="flex flex-row gap-2">Drop off at</span>
|
<span className="flex flex-row gap-1">Drop off at</span>
|
||||||
{column.getIsSorted() === "asc" ? (
|
{column.getIsSorted() === "asc" ? (
|
||||||
<ArrowUp className="ml-2 h-4 w-4" />
|
<ArrowUp className="ml-2 h-4 w-4" />
|
||||||
) : (
|
) : (
|
||||||
@@ -111,7 +115,7 @@ export default function PPOO() {
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LstCard className="w-fit">
|
<LstCard className="w-5/6">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
Quality Request Card Total Pallets {filteredData.length}
|
Quality Request Card Total Pallets {filteredData.length}
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export const Route = createFileRoute("/_old/old/quality/")({
|
|||||||
"admin",
|
"admin",
|
||||||
"manager",
|
"manager",
|
||||||
"supervisor",
|
"supervisor",
|
||||||
|
"user",
|
||||||
],
|
],
|
||||||
moduleName: "quality", // optional
|
moduleName: "quality", // optional
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,11 +9,14 @@ import {
|
|||||||
import { db } from "../../../../../database/dbclient.js";
|
import { db } from "../../../../../database/dbclient.js";
|
||||||
import { invHistoricalData } from "../../../../../database/schema/historicalINV.js";
|
import { invHistoricalData } from "../../../../../database/schema/historicalINV.js";
|
||||||
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
|
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
|
||||||
|
import { createLog } from "../../../logger/logger.js";
|
||||||
import { query } from "../../../sqlServer/prodSqlServer.js";
|
import { query } from "../../../sqlServer/prodSqlServer.js";
|
||||||
import {
|
import {
|
||||||
materialPerDay,
|
materialPerDay,
|
||||||
materialPurchasesPerDay,
|
materialPurchasesPerDay,
|
||||||
} from "../../../sqlServer/querys/dataMart/materialPerDay.js";
|
} from "../../../sqlServer/querys/dataMart/materialPerDay.js";
|
||||||
|
import { singleArticle } from "../../../sqlServer/querys/misc/singleArticle.js";
|
||||||
|
import { sendEmail } from "../sendMail.js";
|
||||||
import { materialPurchases } from "./materialPurchases.js";
|
import { materialPurchases } from "./materialPurchases.js";
|
||||||
import { buildInventoryTimeline } from "./materialWithInv.js";
|
import { buildInventoryTimeline } from "./materialWithInv.js";
|
||||||
|
|
||||||
@@ -99,43 +102,77 @@ export default async function materialPerDayCheck() {
|
|||||||
|
|
||||||
// purchases
|
// purchases
|
||||||
|
|
||||||
const { data: p, error: pe } = (await tryCatch(
|
const pOrders = (await materialPurchases({ startDate, endDate })) as any;
|
||||||
query(
|
|
||||||
materialPurchasesPerDay
|
|
||||||
.replace("[startDate]", startDate)
|
|
||||||
.replace("[endDate]", endDate),
|
|
||||||
"material check",
|
|
||||||
),
|
|
||||||
)) as any;
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
message: "Error getting the material data",
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!data.success) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
message: data.message,
|
|
||||||
data: [],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
//console.log(pOrders);
|
||||||
const openingInventory: Record<string, number> = {};
|
const openingInventory: Record<string, number> = {};
|
||||||
const inventoryRows = await getInv();
|
const inventoryRows = await getInv();
|
||||||
for (const row of inventoryRows) {
|
for (const row of inventoryRows) {
|
||||||
openingInventory[row.article] = Number(row.total_QTY) || 0;
|
openingInventory[row.article] = Number(row.total_QTY) || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const materialsDemand = buildInventoryTimeline(
|
||||||
|
sumByMaterialAndWeek(data.data) as any,
|
||||||
|
openingInventory,
|
||||||
|
pOrders,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { data: av, error: eav } = await tryCatch(
|
||||||
|
query(singleArticle.replace("[av]", "107"), "single article"),
|
||||||
|
);
|
||||||
|
|
||||||
|
const formattedMaterials = materialsDemand
|
||||||
|
.filter((n) => n.MaterialHumanReadableId === `${av?.data[0].article}`)
|
||||||
|
.map((i) => ({
|
||||||
|
...i,
|
||||||
|
OpeningInventory: i.OpeningInventory?.toLocaleString("en-US", {
|
||||||
|
minimumFractionDigits: 2,
|
||||||
|
maximumFractionDigits: 2,
|
||||||
|
}),
|
||||||
|
Purchases: i.Purchases?.toLocaleString("en-US", {
|
||||||
|
minimumFractionDigits: 2,
|
||||||
|
maximumFractionDigits: 2,
|
||||||
|
}),
|
||||||
|
Consumption: i.Consumption?.toLocaleString("en-US", {
|
||||||
|
minimumFractionDigits: 2,
|
||||||
|
maximumFractionDigits: 2,
|
||||||
|
}),
|
||||||
|
ClosingInventory: i.ClosingInventory?.toLocaleString("en-US", {
|
||||||
|
minimumFractionDigits: 2,
|
||||||
|
maximumFractionDigits: 2,
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
|
// send the email stuff
|
||||||
|
const emailSetup = {
|
||||||
|
email: "blake.matthes@alpla.com",
|
||||||
|
subject: `Material Week.`,
|
||||||
|
template: "materialPerDay",
|
||||||
|
context: {
|
||||||
|
items: formattedMaterials,
|
||||||
|
article: av?.data[0].combined,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const { data: sentEmail, error: sendEmailError } = await tryCatch(
|
||||||
|
sendEmail(emailSetup),
|
||||||
|
);
|
||||||
|
if (sendEmailError) {
|
||||||
|
createLog(
|
||||||
|
"error",
|
||||||
|
"blocking",
|
||||||
|
"notify",
|
||||||
|
"Failed to send email, will try again on next interval",
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: "Failed to send email, will try again on next interval",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
message: "material data",
|
message: "material data",
|
||||||
data: buildInventoryTimeline(
|
data: formattedMaterials,
|
||||||
sumByMaterialAndWeek(data.data) as any,
|
|
||||||
openingInventory,
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
import { formatISO, parseISO, startOfWeek } from "date-fns";
|
import { formatISO, parseISO, startOfWeek } from "date-fns";
|
||||||
|
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
|
||||||
|
import { query } from "../../../sqlServer/prodSqlServer.js";
|
||||||
|
import { materialPurchasesPerDay } from "../../../sqlServer/querys/dataMart/materialPerDay.js";
|
||||||
|
|
||||||
function toDate(val: any) {
|
function toDate(val: any) {
|
||||||
if (val instanceof Date) return val;
|
if (val instanceof Date) return val;
|
||||||
@@ -6,20 +9,52 @@ function toDate(val: any) {
|
|||||||
return new Date(val);
|
return new Date(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const materialPurchases = async (data: any) => {
|
export const materialPurchases = async ({
|
||||||
|
startDate,
|
||||||
|
endDate,
|
||||||
|
}: {
|
||||||
|
startDate: string;
|
||||||
|
endDate: string;
|
||||||
|
}) => {
|
||||||
/** @type {Record<string, Record<string, number>>} */
|
/** @type {Record<string, Record<string, number>>} */
|
||||||
const grouped: any = {};
|
const grouped: any = {};
|
||||||
|
|
||||||
for (const r of data) {
|
const { data: p, error } = (await tryCatch(
|
||||||
|
query(
|
||||||
|
materialPurchasesPerDay
|
||||||
|
.replace("[startDate]", startDate)
|
||||||
|
.replace("[endDate]", endDate),
|
||||||
|
"material check",
|
||||||
|
),
|
||||||
|
)) as any;
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: "Error getting the material data",
|
||||||
|
error,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!p.success) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: p.message,
|
||||||
|
data: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const r of p.data) {
|
||||||
|
const pOrder = String(r.purhcaseOrder);
|
||||||
const mat = String(r.MaterialHumanReadableId);
|
const mat = String(r.MaterialHumanReadableId);
|
||||||
const d = toDate(r.CalDate);
|
const d = toDate(r.deliveryDate);
|
||||||
const week = formatISO(startOfWeek(d, { weekStartsOn: 1 }), {
|
const week = formatISO(startOfWeek(d, { weekStartsOn: 1 }), {
|
||||||
representation: "date",
|
representation: "date",
|
||||||
});
|
});
|
||||||
|
|
||||||
grouped[mat] ??= {};
|
grouped[mat] ??= {};
|
||||||
grouped[mat][week] ??= 0;
|
grouped[mat][week] ??= 0;
|
||||||
grouped[mat][week] += Number(r.DailyMaterialDemand) || 0;
|
grouped[mat][week] += Number(r.qty) || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = [];
|
const result = [];
|
||||||
@@ -29,7 +64,7 @@ export const materialPurchases = async (data: any) => {
|
|||||||
result.push({
|
result.push({
|
||||||
MaterialHumanReadableId: mat,
|
MaterialHumanReadableId: mat,
|
||||||
WeekStart: week,
|
WeekStart: week,
|
||||||
WeeklyDemand: Number(total).toFixed(2),
|
WeeklyPurchase: Number(total).toFixed(2),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,25 +5,51 @@ export const buildInventoryTimeline = (
|
|||||||
WeeklyDemand: number;
|
WeeklyDemand: number;
|
||||||
}>,
|
}>,
|
||||||
opening: Record<string, number>,
|
opening: Record<string, number>,
|
||||||
|
weeklyPurchases?: Array<{
|
||||||
|
MaterialHumanReadableId: string;
|
||||||
|
WeekStart: string;
|
||||||
|
WeeklyPurchase: number;
|
||||||
|
}>,
|
||||||
) => {
|
) => {
|
||||||
// group weekly demand by material
|
// group weekly demand by material
|
||||||
const grouped: Record<
|
const groupedDemand: Record<
|
||||||
string,
|
string,
|
||||||
Array<{ WeekStart: string; Demand: number }>
|
Array<{ WeekStart: string; Demand: number }>
|
||||||
> = {};
|
> = {};
|
||||||
|
|
||||||
for (const d of weeklyDemand) {
|
for (const d of weeklyDemand) {
|
||||||
const mat = d.MaterialHumanReadableId;
|
const mat = d.MaterialHumanReadableId;
|
||||||
grouped[mat] ??= [];
|
groupedDemand[mat] ??= [];
|
||||||
grouped[mat].push({
|
groupedDemand[mat].push({
|
||||||
WeekStart: d.WeekStart,
|
WeekStart: d.WeekStart,
|
||||||
Demand: Number(d.WeeklyDemand),
|
Demand: Number(d.WeeklyDemand),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort weeks chronologically per material
|
// group weekly purchases by material
|
||||||
for (const mat of Object.keys(grouped)) {
|
const groupedPurchases: Record<
|
||||||
grouped[mat].sort(
|
string,
|
||||||
|
Array<{ WeekStart: string; Purchase: number }>
|
||||||
|
> = {};
|
||||||
|
if (weeklyPurchases) {
|
||||||
|
for (const p of weeklyPurchases) {
|
||||||
|
const mat = p.MaterialHumanReadableId;
|
||||||
|
groupedPurchases[mat] ??= [];
|
||||||
|
groupedPurchases[mat].push({
|
||||||
|
WeekStart: p.WeekStart,
|
||||||
|
Purchase: Number(p.WeeklyPurchase),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort both chronologically
|
||||||
|
for (const mat of Object.keys(groupedDemand)) {
|
||||||
|
groupedDemand[mat].sort(
|
||||||
|
(a, b) =>
|
||||||
|
new Date(a.WeekStart).getTime() - new Date(b.WeekStart).getTime(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
for (const mat of Object.keys(groupedPurchases)) {
|
||||||
|
groupedPurchases[mat].sort(
|
||||||
(a, b) =>
|
(a, b) =>
|
||||||
new Date(a.WeekStart).getTime() - new Date(b.WeekStart).getTime(),
|
new Date(a.WeekStart).getTime() - new Date(b.WeekStart).getTime(),
|
||||||
);
|
);
|
||||||
@@ -33,25 +59,30 @@ export const buildInventoryTimeline = (
|
|||||||
MaterialHumanReadableId: string;
|
MaterialHumanReadableId: string;
|
||||||
WeekStart: string;
|
WeekStart: string;
|
||||||
OpeningInventory: number;
|
OpeningInventory: number;
|
||||||
|
Purchases: number;
|
||||||
Consumption: number;
|
Consumption: number;
|
||||||
ClosingInventory: number;
|
ClosingInventory: number;
|
||||||
}> = [];
|
}> = [];
|
||||||
|
|
||||||
for (const [mat, weeks] of Object.entries(grouped)) {
|
for (const [mat, weeks] of Object.entries(groupedDemand)) {
|
||||||
// get starting inventory from the ERP result
|
|
||||||
let inv = opening[mat] ?? 0;
|
let inv = opening[mat] ?? 0;
|
||||||
|
const purchasesForMaterial = groupedPurchases[mat] ?? [];
|
||||||
|
|
||||||
for (const w of weeks) {
|
for (const week of weeks) {
|
||||||
const week = w.WeekStart;
|
const demand = Number(week.Demand);
|
||||||
const demand = Number(w.Demand);
|
const purchase =
|
||||||
|
purchasesForMaterial.find((p) => p.WeekStart === week.WeekStart)
|
||||||
|
?.Purchase ?? 0;
|
||||||
|
|
||||||
const openingInv = inv;
|
const openingInv = inv;
|
||||||
const closingInv = openingInv - demand;
|
const adjustedInv = openingInv + purchase;
|
||||||
|
const closingInv = adjustedInv - demand;
|
||||||
|
|
||||||
result.push({
|
result.push({
|
||||||
MaterialHumanReadableId: mat,
|
MaterialHumanReadableId: mat,
|
||||||
WeekStart: week,
|
WeekStart: week.WeekStart,
|
||||||
OpeningInventory: Number(openingInv.toFixed(2)),
|
OpeningInventory: Number(openingInv.toFixed(2)),
|
||||||
|
Purchases: Number(purchase.toFixed(2)),
|
||||||
Consumption: Number(demand.toFixed(2)),
|
Consumption: Number(demand.toFixed(2)),
|
||||||
ClosingInventory: Number(closingInv.toFixed(2)),
|
ClosingInventory: Number(closingInv.toFixed(2)),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,149 +1,152 @@
|
|||||||
import { tryCatch } from "../../../globalUtils/tryCatch.js";
|
import Handlebars from "handlebars";
|
||||||
import { db } from "../../../../database/dbclient.js";
|
|
||||||
import { settings } from "../../../../database/schema/settings.js";
|
|
||||||
import nodemailer from "nodemailer";
|
|
||||||
import type { Transporter } from "nodemailer";
|
import type { Transporter } from "nodemailer";
|
||||||
import type SMTPTransport from "nodemailer/lib/smtp-transport/index.js";
|
import nodemailer from "nodemailer";
|
||||||
import type Mail from "nodemailer/lib/mailer/index.js";
|
import type Mail from "nodemailer/lib/mailer/index.js";
|
||||||
import type { Address } from "nodemailer/lib/mailer/index.js";
|
import type { Address } from "nodemailer/lib/mailer/index.js";
|
||||||
|
import type SMTPTransport from "nodemailer/lib/smtp-transport/index.js";
|
||||||
|
import hbs from "nodemailer-express-handlebars";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { fileURLToPath } from "url";
|
import { fileURLToPath } from "url";
|
||||||
import hbs from "nodemailer-express-handlebars";
|
|
||||||
import { promisify } from "util";
|
import { promisify } from "util";
|
||||||
import { createLog } from "../../logger/logger.js";
|
import { db } from "../../../../database/dbclient.js";
|
||||||
|
import { settings } from "../../../../database/schema/settings.js";
|
||||||
|
import { tryCatch } from "../../../globalUtils/tryCatch.js";
|
||||||
import { installed } from "../../../index.js";
|
import { installed } from "../../../index.js";
|
||||||
|
import { createLog } from "../../logger/logger.js";
|
||||||
|
|
||||||
interface HandlebarsMailOptions extends Mail.Options {
|
interface HandlebarsMailOptions extends Mail.Options {
|
||||||
template: string;
|
template: string;
|
||||||
context: Record<string, unknown>; // Use a generic object for context
|
context: Record<string, unknown>; // Use a generic object for context
|
||||||
}
|
}
|
||||||
|
|
||||||
interface EmailData {
|
interface EmailData {
|
||||||
email: string;
|
email: string;
|
||||||
subject: string;
|
subject: string;
|
||||||
template: string;
|
template: string;
|
||||||
context: [];
|
context: [];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const sendEmail = async (data: any): Promise<any> => {
|
export const sendEmail = async (data: any): Promise<any> => {
|
||||||
if (!installed) {
|
if (!installed) {
|
||||||
createLog("error", "notify", "notify", "server not installed.");
|
createLog("error", "notify", "notify", "server not installed.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let transporter: Transporter;
|
let transporter: Transporter;
|
||||||
let fromEmail: string | Address;
|
let fromEmail: string | Address;
|
||||||
const { data: settingData, error: settingError } = await tryCatch(
|
const { data: settingData, error: settingError } = await tryCatch(
|
||||||
db.select().from(settings)
|
db.select().from(settings),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (settingError) {
|
if (settingError) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
message: "There was an error getting the settings.",
|
message: "There was an error getting the settings.",
|
||||||
settingError,
|
settingError,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// get the plantToken
|
// get the plantToken
|
||||||
const server = settingData.filter((n) => n.name === "server");
|
const server = settingData.filter((n) => n.name === "server");
|
||||||
|
|
||||||
if (
|
if (
|
||||||
server[0].value === "localhost" &&
|
server[0].value === "localhostx" &&
|
||||||
process.env.EMAIL_USER &&
|
process.env.EMAIL_USER &&
|
||||||
process.env.EMAIL_PASSWORD
|
process.env.EMAIL_PASSWORD
|
||||||
) {
|
) {
|
||||||
transporter = nodemailer.createTransport({
|
transporter = nodemailer.createTransport({
|
||||||
service: "gmail",
|
service: "gmail",
|
||||||
auth: {
|
host: "smtp.gmail.com",
|
||||||
user: process.env.EMAIL_USER,
|
port: 465,
|
||||||
pass: process.env.EMAIL_PASSWORD,
|
auth: {
|
||||||
},
|
user: process.env.EMAIL_USER,
|
||||||
//debug: true,
|
pass: process.env.EMAIL_PASSWORD,
|
||||||
});
|
},
|
||||||
|
//debug: true,
|
||||||
|
});
|
||||||
|
|
||||||
// update the from email
|
// update the from email
|
||||||
fromEmail = process.env.EMAIL_USER;
|
fromEmail = process.env.EMAIL_USER;
|
||||||
} else {
|
} else {
|
||||||
// convert to the correct plant token.
|
// convert to the correct plant token.
|
||||||
const plantToken = settingData.filter((s) => s.name === "plantToken");
|
const plantToken = settingData.filter((s) => s.name === "plantToken");
|
||||||
|
|
||||||
let host = `${plantToken[0].value}-smtp.alpla.net`;
|
let host = `${plantToken[0].value}-smtp.alpla.net`;
|
||||||
|
|
||||||
const testServers = ["test1", "test2", "test3"];
|
const testServers = ["test1", "test2", "test3"];
|
||||||
|
|
||||||
if (testServers.includes(plantToken[0].value)) {
|
if (testServers.includes(plantToken[0].value)) {
|
||||||
host = "USMCD1-smtp.alpla.net";
|
host = "USMCD1-smtp.alpla.net";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (plantToken[0].value === "usiow2") {
|
if (plantToken[0].value === "usiow2") {
|
||||||
host = "USIOW1-smtp.alpla.net";
|
host = "USIOW1-smtp.alpla.net";
|
||||||
}
|
}
|
||||||
|
|
||||||
transporter = nodemailer.createTransport({
|
transporter = nodemailer.createTransport({
|
||||||
host: host,
|
host: host,
|
||||||
port: 25,
|
port: 25,
|
||||||
rejectUnauthorized: false,
|
rejectUnauthorized: false,
|
||||||
//secure: false,
|
//secure: false,
|
||||||
// auth: {
|
// auth: {
|
||||||
// user: "alplaprod",
|
// user: "alplaprod",
|
||||||
// pass: "obelix",
|
// pass: "obelix",
|
||||||
// },
|
// },
|
||||||
debug: true,
|
debug: true,
|
||||||
} as SMTPTransport.Options);
|
} as SMTPTransport.Options);
|
||||||
|
|
||||||
// update the from email
|
// update the from email
|
||||||
fromEmail = `noreply@alpla.com`;
|
fromEmail = `noreply@alpla.com`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// creating the handlbar options
|
// creating the handlbar options
|
||||||
const viewPath = path.resolve(
|
const viewPath = path.resolve(
|
||||||
path.dirname(fileURLToPath(import.meta.url)),
|
path.dirname(fileURLToPath(import.meta.url)),
|
||||||
"../utils/views/"
|
"../utils/views/",
|
||||||
);
|
);
|
||||||
|
|
||||||
const handlebarOptions = {
|
const handlebarOptions = {
|
||||||
viewEngine: {
|
viewEngine: {
|
||||||
extname: ".hbs",
|
extname: ".hbs",
|
||||||
//layoutsDir: path.resolve(viewPath, "layouts"), // Path to layouts directory
|
//layoutsDir: path.resolve(viewPath, "layouts"), // Path to layouts directory
|
||||||
defaultLayout: "", // Specify the default layout
|
defaultLayout: "", // Specify the default layout
|
||||||
partialsDir: viewPath,
|
partialsDir: viewPath,
|
||||||
},
|
},
|
||||||
viewPath: viewPath,
|
viewPath: viewPath,
|
||||||
extName: ".hbs", // File extension for Handlebars templates
|
extName: ".hbs", // File extension for Handlebars templates
|
||||||
};
|
};
|
||||||
|
|
||||||
transporter.use("compile", hbs(handlebarOptions));
|
transporter.use("compile", hbs(handlebarOptions));
|
||||||
|
|
||||||
const mailOptions: HandlebarsMailOptions = {
|
const mailOptions: HandlebarsMailOptions = {
|
||||||
from: fromEmail,
|
from: fromEmail,
|
||||||
to: data.email,
|
to: data.email,
|
||||||
subject: data.subject,
|
subject: data.subject,
|
||||||
//text: "You will have a reset token here and only have 30min to click the link before it expires.",
|
//text: "You will have a reset token here and only have 30min to click the link before it expires.",
|
||||||
//html: emailTemplate("BlakesTest", "This is an example with css"),
|
//html: emailTemplate("BlakesTest", "This is an example with css"),
|
||||||
template: data.template, // Name of the Handlebars template (e.g., 'welcome.hbs')
|
template: data.template, // Name of the Handlebars template (e.g., 'welcome.hbs')
|
||||||
context: data.context,
|
context: data.context,
|
||||||
};
|
};
|
||||||
|
|
||||||
// now verify and send the email
|
// now verify and send the email
|
||||||
const sendMailPromise = promisify(transporter.sendMail).bind(transporter);
|
const sendMailPromise = promisify(transporter.sendMail).bind(transporter);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Send email and await the result
|
// Send email and await the result
|
||||||
const info = await sendMailPromise(mailOptions);
|
const info = await sendMailPromise(mailOptions);
|
||||||
createLog(
|
createLog(
|
||||||
"info",
|
"info",
|
||||||
"notification",
|
"notification",
|
||||||
"system",
|
"system",
|
||||||
`Email was sent to: ${data.email}`
|
`Email was sent to: ${data.email}`,
|
||||||
);
|
);
|
||||||
return { success: true, message: "Email sent.", data: info };
|
return { success: true, message: "Email sent.", data: info };
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
createLog(
|
createLog(
|
||||||
"error",
|
"error",
|
||||||
"notification",
|
"notification",
|
||||||
"system",
|
"system",
|
||||||
`Error sending Email: ${JSON.stringify(err)}`
|
`Error sending Email: ${JSON.stringify(err)}`,
|
||||||
);
|
);
|
||||||
return { success: false, message: "Error sending email.", error: err };
|
return { success: false, message: "Error sending email.", error: err };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
// an external way to creating logs
|
||||||
|
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
|
||||||
|
import { apiHit } from "../../../globalUtils/apiHits.js";
|
||||||
|
import { responses } from "../../../globalUtils/routeDefs/responses.js";
|
||||||
|
import materialPerDayCheck from "../controller/materialsPerDay/materialPerDay.js";
|
||||||
|
import runTiImport from "../controller/notifications/tiIntergration.js";
|
||||||
|
|
||||||
|
const app = new OpenAPIHono({ strict: false });
|
||||||
|
|
||||||
|
app.openapi(
|
||||||
|
createRoute({
|
||||||
|
tags: ["notify"],
|
||||||
|
summary: "Manually trigger TI intergrations.",
|
||||||
|
method: "get",
|
||||||
|
path: "/materialPerDayCheck",
|
||||||
|
//middleware: authMiddleware,
|
||||||
|
responses: responses(),
|
||||||
|
}),
|
||||||
|
async (c) => {
|
||||||
|
apiHit(c, { endpoint: "/materialPerDayCheck" });
|
||||||
|
const tiImport = await materialPerDayCheck();
|
||||||
|
return c.json({
|
||||||
|
success: tiImport?.success,
|
||||||
|
message: tiImport?.message,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
export default app;
|
||||||
@@ -1,28 +1,27 @@
|
|||||||
// an external way to creating logs
|
// an external way to creating logs
|
||||||
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
|
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
|
||||||
import { responses } from "../../../globalUtils/routeDefs/responses.js";
|
|
||||||
|
|
||||||
import runTiImport from "../controller/notifications/tiIntergration.js";
|
|
||||||
import { apiHit } from "../../../globalUtils/apiHits.js";
|
import { apiHit } from "../../../globalUtils/apiHits.js";
|
||||||
|
import { responses } from "../../../globalUtils/routeDefs/responses.js";
|
||||||
|
import runTiImport from "../controller/notifications/tiIntergration.js";
|
||||||
|
|
||||||
const app = new OpenAPIHono({ strict: false });
|
const app = new OpenAPIHono({ strict: false });
|
||||||
|
|
||||||
app.openapi(
|
app.openapi(
|
||||||
createRoute({
|
createRoute({
|
||||||
tags: ["notify"],
|
tags: ["notify"],
|
||||||
summary: "Manually trigger TI intergrations.",
|
summary: "Manually trigger TI intergrations.",
|
||||||
method: "get",
|
method: "get",
|
||||||
path: "/tiTrigger",
|
path: "/tiTrigger",
|
||||||
//middleware: authMiddleware,
|
//middleware: authMiddleware,
|
||||||
responses: responses(),
|
responses: responses(),
|
||||||
}),
|
}),
|
||||||
async (c) => {
|
async (c) => {
|
||||||
apiHit(c, { endpoint: "/tiTrigger" });
|
apiHit(c, { endpoint: "/tiTrigger" });
|
||||||
const tiImport = await runTiImport();
|
const tiImport = await runTiImport();
|
||||||
return c.json({
|
return c.json({
|
||||||
success: tiImport?.success,
|
success: tiImport?.success,
|
||||||
message: tiImport?.message,
|
message: tiImport?.message,
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
export default app;
|
export default app;
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
{{!-- <link rel="stylesheet" href="styles/styles.css" /> --}}
|
||||||
|
{{> styles}}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>All,</p>
|
||||||
|
<p>Below is the weekly material demand for Article: {{article}}.</p>
|
||||||
|
<table >
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>AV</th>
|
||||||
|
<th>Week</th>
|
||||||
|
<th>Opening Inventory</th>
|
||||||
|
<th>Purchases</th>
|
||||||
|
<th>Consumption</th>
|
||||||
|
<th>Closing Inventory</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
{{#each items}}
|
||||||
|
<tr>
|
||||||
|
<td>{{MaterialHumanReadableId}}</td>
|
||||||
|
<td>{{WeekStart}}</td>
|
||||||
|
<td>{{OpeningInventory}}</td>
|
||||||
|
<td>{{Purchases}}</td>
|
||||||
|
<td>{{Consumption}}</td>
|
||||||
|
<td>{{ClosingInventory}}</td>
|
||||||
|
</tr>
|
||||||
|
{{/each}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p>Thank you,</p>
|
||||||
|
<p>LST Team</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -13,6 +13,10 @@ export const addNewPallet = async (data: any) => {
|
|||||||
* Post new pallets
|
* Post new pallets
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const returnLabels = ["return to warehouse", "rework", "grind", "scrap"];
|
||||||
|
|
||||||
|
console.log(data, returnLabels.includes(data.palletStatusText));
|
||||||
|
|
||||||
if (parseInt(data.runningNr) <= 0) {
|
if (parseInt(data.runningNr) <= 0) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
@@ -40,7 +44,7 @@ export const addNewPallet = async (data: any) => {
|
|||||||
const palletData: any = c;
|
const palletData: any = c;
|
||||||
// if the pallet exist then tell the user to check on it
|
// if the pallet exist then tell the user to check on it
|
||||||
const pStatus = [1, 4, 6];
|
const pStatus = [1, 4, 6];
|
||||||
if (!data.priority) {
|
if (!data.priority && data.palletStatusText !== "canceled") {
|
||||||
if (palletData && pStatus.includes(palletData[0]?.palletStatus)) {
|
if (palletData && pStatus.includes(palletData[0]?.palletStatus)) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
@@ -73,22 +77,39 @@ export const addNewPallet = async (data: any) => {
|
|||||||
upd_user: data.user,
|
upd_user: data.user,
|
||||||
upd_date: sql`NOW()`,
|
upd_date: sql`NOW()`,
|
||||||
};
|
};
|
||||||
} else {
|
} else if (data.palletStatusText === "canceled") {
|
||||||
pData = {
|
pData = {
|
||||||
warehouseAtRequest: p[0].warehouseAtRequest,
|
warehouseAtRequest: null,
|
||||||
locationAtRequest: p[0].locationAtRequest,
|
locationAtRequest: null,
|
||||||
warehouseMovedTo: null,
|
warehouseMovedTo: null,
|
||||||
locationMovedTo: null,
|
locationMovedTo: null,
|
||||||
palletStatus: data.palletStatusText === "return" ? 6 : 4,
|
palletStatus: 5,
|
||||||
//durationToMove: 0,
|
//durationToMove: 0,
|
||||||
palletStatusText:
|
palletStatusText: "canceled",
|
||||||
data.palletStatusText === "return" ? "return" : "reactivated",
|
qualityDurationToInspect: 0,
|
||||||
qualityDurationToInspect:
|
locationDropOff: "canceled",
|
||||||
data.palletStatusText === "return"
|
palletRequest: palletData[0].palletStatus + 1,
|
||||||
? differenceInMinutes(new Date(Date.now()), p[0].lastMove)
|
upd_user: data.user,
|
||||||
: 0,
|
upd_date: sql`NOW()`,
|
||||||
locationDropOff:
|
};
|
||||||
data.palletStatusText === "return" ? "Return to warhouse" : "",
|
} else {
|
||||||
|
pData = {
|
||||||
|
warehouseAtRequest: p[0].warehouseAtRequest || "no longer on stock",
|
||||||
|
locationAtRequest: p[0].locationAtRequest || "no longer on stock",
|
||||||
|
warehouseMovedTo: null,
|
||||||
|
locationMovedTo: null,
|
||||||
|
palletStatus: returnLabels.includes(data.palletStatusText) ? 6 : 4,
|
||||||
|
//durationToMove: 0,
|
||||||
|
palletStatusText: returnLabels.includes(data.palletStatusText)
|
||||||
|
? data.palletStatusText
|
||||||
|
: "reactivated",
|
||||||
|
|
||||||
|
qualityDurationToInspect: returnLabels.includes(data.palletStatusText)
|
||||||
|
? differenceInMinutes(new Date(Date.now()), p[0].lastMove)
|
||||||
|
: 0,
|
||||||
|
locationDropOff: returnLabels.includes(data.palletStatusText)
|
||||||
|
? data.palletStatusText
|
||||||
|
: "No location Checked",
|
||||||
palletRequest: palletData[0].palletStatus + 1,
|
palletRequest: palletData[0].palletStatus + 1,
|
||||||
upd_user: data.user,
|
upd_user: data.user,
|
||||||
upd_date: sql`NOW()`,
|
upd_date: sql`NOW()`,
|
||||||
|
|||||||
@@ -71,21 +71,21 @@ export const qualityCycle = async () => {
|
|||||||
const qDataPost = {
|
const qDataPost = {
|
||||||
warehouseMovedTo: prodData[0]?.warehouseAtRequest,
|
warehouseMovedTo: prodData[0]?.warehouseAtRequest,
|
||||||
locationMovedTo: prodData[0]?.locationAtRequest,
|
locationMovedTo: prodData[0]?.locationAtRequest,
|
||||||
// how ling did it take the warhouse to originally move the pallet
|
// how ling did it take the warehouse to originally move the pallet
|
||||||
durationToMove: warehouse.includes(lstQData[i].palletStatus)
|
durationToMove: warehouse.includes(lstQData[i].palletStatus)
|
||||||
? differenceInMinutes(
|
? differenceInMinutes(
|
||||||
new Date(Date.now()),
|
new Date(Date.now()),
|
||||||
lstQData[i].upd_date,
|
lstQData[i].upd_date,
|
||||||
)
|
)
|
||||||
: lstQData[i].durationToMove,
|
: lstQData[i].durationToMove,
|
||||||
// how long did it take warehouse to move the pallet back agian
|
// how long did it take warehouse to move the pallet back again
|
||||||
returnDurationToInspect:
|
returnDurationToInspect:
|
||||||
lstQData[i].palletStatus === 7
|
lstQData[i].palletStatus === 7
|
||||||
? differenceInMinutes(
|
? differenceInMinutes(
|
||||||
new Date(Date.now()),
|
new Date(Date.now()),
|
||||||
lstQData[i].upd_date,
|
lstQData[i].upd_date,
|
||||||
)
|
)
|
||||||
: lstQData[i].qualityDurationToInspect,
|
: lstQData[i].returnDurationToInspect,
|
||||||
palletStatus: 2,
|
palletStatus: 2,
|
||||||
palletStatusText: "moved",
|
palletStatusText: "moved",
|
||||||
upd_date: sql`NOW()`,
|
upd_date: sql`NOW()`,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
* startdate and end date should be passed over
|
* startdate and end date should be passed over
|
||||||
*/
|
*/
|
||||||
export const materialPerDay = `
|
export const materialPerDay = `
|
||||||
use [test3_AlplaPROD2.0_Read]
|
use [test1_AlplaPROD2.0_Read]
|
||||||
|
|
||||||
DECLARE @ShiftStartHour INT = 6
|
DECLARE @ShiftStartHour INT = 6
|
||||||
declare @startDate nvarchar(max) = '[startDate]'
|
declare @startDate nvarchar(max) = '[startDate]'
|
||||||
@@ -121,7 +121,7 @@ declare @endDate nvarchar(max) = '[endDate]'
|
|||||||
SELECT
|
SELECT
|
||||||
[IdBestellung] as purhcaseOrder
|
[IdBestellung] as purhcaseOrder
|
||||||
|
|
||||||
,[IdArtikelVarianten]
|
,[IdArtikelVarianten] as MaterialHumanReadableId
|
||||||
,convert(date, [BestellDatum], 120) as orderDate
|
,convert(date, [BestellDatum], 120) as orderDate
|
||||||
,convert(date, [Lieferdatum], 120) as deliveryDate
|
,convert(date, [Lieferdatum], 120) as deliveryDate
|
||||||
,[BestellMenge] as qty
|
,[BestellMenge] as qty
|
||||||
|
|||||||
10
lstV2/server/services/sqlServer/querys/misc/singleArticle.ts
Normal file
10
lstV2/server/services/sqlServer/querys/misc/singleArticle.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
export const singleArticle = `
|
||||||
|
use AlplaPROD_test1
|
||||||
|
|
||||||
|
select
|
||||||
|
idartikelvarianten as article,
|
||||||
|
CONCAT(idartikelvarianten , ' - ' , Alias) as combined
|
||||||
|
|
||||||
|
from V_Artikel (nolock)
|
||||||
|
where idartikelvarianten = '[av]'
|
||||||
|
`;
|
||||||
Reference in New Issue
Block a user