Compare commits
22 Commits
4e1f7d4040
...
97cf624440
| Author | SHA1 | Date | |
|---|---|---|---|
| 97cf624440 | |||
| e0df6b8cd7 | |||
| c248cc0129 | |||
| 57d3727f49 | |||
| 5a48dcf553 | |||
| eac7444038 | |||
| b290b21ca2 | |||
| 86905b591b | |||
| 28b050859a | |||
| 3c9e627021 | |||
| 7152e72822 | |||
| a03130a961 | |||
| aea06c12a0 | |||
| 4f1d83137b | |||
| 72a3292633 | |||
| 174a6c0adc | |||
| 556aaa381d | |||
| 5f7915b81f | |||
| 613a486160 | |||
| caccaf143c | |||
| 2a7eb26e6b | |||
| 844f337f6c |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -150,3 +150,4 @@ dist
|
||||
.pnp.*
|
||||
|
||||
backend-0.1.3.zip
|
||||
BulkForecastTemplate
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# All CHanges to LST can be found below.
|
||||
|
||||
### [2.16.1](https://git.tuffraid.net/cowch/lstV2/compare/v2.16.0...v2.16.1) (2025-04-23)
|
||||
|
||||
## [2.16.0](https://git.tuffraid.net/cowch/lstV2/compare/v2.15.0...v2.16.0) (2025-04-22)
|
||||
|
||||
|
||||
|
||||
213
frontend/src/components/auth/Register.tsx
Normal file
213
frontend/src/components/auth/Register.tsx
Normal file
@@ -0,0 +1,213 @@
|
||||
import { LstCard } from "../extendedUI/LstCard";
|
||||
import { CardHeader } from "../ui/card";
|
||||
import { toast } from "sonner";
|
||||
|
||||
import { Label } from "../ui/label";
|
||||
import { Input } from "../ui/input";
|
||||
import { Button } from "../ui/button";
|
||||
import { useForm } from "@tanstack/react-form";
|
||||
import { Separator } from "../ui/separator";
|
||||
import { useNavigate } from "@tanstack/react-router";
|
||||
import { useState } from "react";
|
||||
import axios from "axios";
|
||||
|
||||
export default function RegisterForm() {
|
||||
const navigate = useNavigate();
|
||||
const [registering, setRegistering] = useState(false);
|
||||
const form = useForm({
|
||||
defaultValues: {
|
||||
username: "",
|
||||
password: "",
|
||||
email: "",
|
||||
},
|
||||
onSubmit: async ({ value }) => {
|
||||
setRegistering(true);
|
||||
try {
|
||||
const res = await axios.post("/api/auth/register", value);
|
||||
|
||||
if (res.data.success) {
|
||||
navigate({ to: "/login" });
|
||||
form.reset();
|
||||
toast.success(
|
||||
`${value.username} was just created please login`
|
||||
);
|
||||
setRegistering(false);
|
||||
}
|
||||
|
||||
if (!res.data.success) {
|
||||
toast.error(res.data.message);
|
||||
setRegistering(false);
|
||||
}
|
||||
} catch (error) {
|
||||
//console.log(error);
|
||||
toast.error("There was an error registering");
|
||||
setRegistering(false);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="ml-[25%]">
|
||||
<LstCard className="p-3 w-96">
|
||||
<CardHeader>
|
||||
<div>
|
||||
<p className="text-2xl">Login to register</p>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<hr className="rounded"></hr>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<Separator />
|
||||
<form.Field
|
||||
name="username"
|
||||
validators={{
|
||||
// We can choose between form-wide and field-specific validators
|
||||
onChange: ({ value }) =>
|
||||
value.length > 3
|
||||
? undefined
|
||||
: "Username must be longer than 3 letters",
|
||||
}}
|
||||
children={(field) => {
|
||||
return (
|
||||
<div className="m-2 min-w-48 max-w-96 p-2">
|
||||
<Label htmlFor="username" className="mb-2">
|
||||
Username
|
||||
</Label>
|
||||
<Input
|
||||
name={field.name}
|
||||
value={field.state.value}
|
||||
onBlur={field.handleBlur}
|
||||
//type="number"
|
||||
onChange={(e) =>
|
||||
field.handleChange(e.target.value)
|
||||
}
|
||||
/>
|
||||
{field.state.meta.errors.length ? (
|
||||
<em>
|
||||
{field.state.meta.errors.join(",")}
|
||||
</em>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Separator />
|
||||
<form.Field
|
||||
name="email"
|
||||
validators={{
|
||||
// We can choose between form-wide and field-specific validators
|
||||
onChange: ({ value }) =>
|
||||
value.length > 3
|
||||
? undefined
|
||||
: "You must enter a valid email",
|
||||
}}
|
||||
children={(field) => {
|
||||
return (
|
||||
<div className="m-2 min-w-48 max-w-96 p-2">
|
||||
<Label htmlFor="email" className="mb-2">
|
||||
Alpla Email
|
||||
</Label>
|
||||
<Input
|
||||
name={field.name}
|
||||
value={field.state.value}
|
||||
onBlur={field.handleBlur}
|
||||
//type="number"
|
||||
onChange={(e) =>
|
||||
field.handleChange(e.target.value)
|
||||
}
|
||||
/>
|
||||
{field.state.meta.errors.length ? (
|
||||
<em>
|
||||
{field.state.meta.errors.join(",")}
|
||||
</em>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Separator className="m-2" />
|
||||
<p>
|
||||
Your password Should be your windows password, as this
|
||||
is how you will interact with alplaprod
|
||||
</p>
|
||||
<form.Field
|
||||
name="password"
|
||||
// We can choose between form-wide and field-specific validators
|
||||
validators={{
|
||||
onChangeAsyncDebounceMs: 500,
|
||||
onChangeAsync: ({ value }) => {
|
||||
// if (
|
||||
// window.location.pathname.includes(
|
||||
// "/users"
|
||||
// ) &&
|
||||
// value.length === 0
|
||||
// ) {
|
||||
// return;
|
||||
// }
|
||||
if (value.length < 4) {
|
||||
return "Password must be at least 4 characters long.";
|
||||
}
|
||||
|
||||
if (!/[A-Z]/.test(value)) {
|
||||
return "Password must contain at least one uppercase letter.";
|
||||
}
|
||||
|
||||
if (!/[a-z]/.test(value)) {
|
||||
return "Password must contain at least one lower case letter.";
|
||||
}
|
||||
|
||||
if (!/[0-9]/.test(value)) {
|
||||
return "Password must contain at least one number.";
|
||||
}
|
||||
|
||||
if (
|
||||
!/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(
|
||||
value
|
||||
)
|
||||
) {
|
||||
return "Password must contain at least one special character.";
|
||||
}
|
||||
},
|
||||
}}
|
||||
children={(field) => {
|
||||
return (
|
||||
<div className="m-2 min-w-48 max-w-96 p-2">
|
||||
<Label htmlFor="password1" className="mb-2">
|
||||
Password
|
||||
</Label>
|
||||
<Input
|
||||
name={field.name}
|
||||
value={field.state.value}
|
||||
onBlur={field.handleBlur}
|
||||
type="password"
|
||||
onChange={(e) =>
|
||||
field.handleChange(e.target.value)
|
||||
}
|
||||
/>
|
||||
{field.state.meta.errors.length ? (
|
||||
<em>
|
||||
{field.state.meta.errors.join(",")}
|
||||
</em>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<div className="mt-4 ml-4 flex justify-end">
|
||||
<Button
|
||||
type="submit"
|
||||
onClick={form.handleSubmit}
|
||||
disabled={registering}
|
||||
>
|
||||
Register
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</LstCard>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,78 +1,23 @@
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import OrderImport from "./OrderImport";
|
||||
import StandardOrderTemplate from "./StandardOrderTemplate";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import StandardForecastTemplate from "./StandardForecastTemplate";
|
||||
import ForecastImport from "./ForecastImport";
|
||||
import { useSettingStore } from "@/lib/store/useSettings";
|
||||
|
||||
export default function DMButtons() {
|
||||
const { settings } = useSettingStore();
|
||||
|
||||
const plantToken = settings.filter((n) => n.name === "plantToken");
|
||||
console.log(plantToken);
|
||||
//console.log(plantToken);
|
||||
return (
|
||||
<div className="flex flex-row-reverse">
|
||||
<div className="m-2">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button>Standard DM</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuLabel>
|
||||
Standard templates and imports
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>
|
||||
<StandardOrderTemplate />
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<OrderImport
|
||||
fileType={"standard"}
|
||||
name={"Standard Order Import"}
|
||||
/>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>
|
||||
<StandardForecastTemplate />
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<ForecastImport
|
||||
fileType={"standard"}
|
||||
name={"Standard Forecast Import"}
|
||||
/>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
<div className="flex flex-row-reverse gap-1">
|
||||
{plantToken[0]?.value === "usday1" && (
|
||||
<div className="m-2">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button>Dayton Customs</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuLabel>
|
||||
Custom import templates
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
|
||||
<DropdownMenuItem>
|
||||
<div className="flex flex-row gap-2">
|
||||
<OrderImport
|
||||
fileType={"abbott"}
|
||||
name={"Abbott truck list"}
|
||||
/>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<OrderImport
|
||||
fileType={"energizer"}
|
||||
name={"Energizer Truck List"}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -18,7 +18,7 @@ export default function ForecastImport(props: any) {
|
||||
|
||||
// create the form data with the correct fileType
|
||||
const formData = new FormData();
|
||||
formData.append("postOrders", e.target.files[0]);
|
||||
formData.append("postForecast", e.target.files[0]);
|
||||
formData.append("fileType", props.fileType); // extra field
|
||||
// console.log(formData);
|
||||
|
||||
@@ -33,10 +33,13 @@ export default function ForecastImport(props: any) {
|
||||
},
|
||||
}
|
||||
);
|
||||
console.log("Upload successful:", response.data);
|
||||
toast.success(
|
||||
"File Uploaded, please validate processing in alplaprod 2.0"
|
||||
);
|
||||
//console.log("Upload successful:", response.data);
|
||||
toast.success(response?.data?.message);
|
||||
fileInputRef.current.value = null;
|
||||
setPosting(false);
|
||||
// toast.success(
|
||||
// "File Uploaded, please validate processing in alplaprod 2.0"
|
||||
// );
|
||||
setPosting(false);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
||||
@@ -20,7 +20,6 @@ export default function OrderImport(props: any) {
|
||||
const formData = new FormData();
|
||||
formData.append("postOrders", e.target.files[0]);
|
||||
formData.append("fileType", props.fileType); // extra field
|
||||
// console.log(formData);
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
@@ -33,10 +32,9 @@ export default function OrderImport(props: any) {
|
||||
},
|
||||
}
|
||||
);
|
||||
console.log("Upload successful:", response.data);
|
||||
toast.success(
|
||||
"File Uploaded, please validate processing in alplaprod 2.0"
|
||||
);
|
||||
//console.log("Upload successful:", response.data);
|
||||
toast.success(response?.data?.message);
|
||||
fileInputRef.current.value = null;
|
||||
setPosting(false);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { LstCard } from "@/components/extendedUI/LstCard";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import OrderImport from "./OrderImport";
|
||||
import StandardOrderTemplate from "./StandardOrderTemplate";
|
||||
import ForecastImport from "./ForecastImport";
|
||||
import StandardForecastTemplate from "./StandardForecastTemplate";
|
||||
|
||||
export default function DmPage() {
|
||||
return (
|
||||
@@ -9,6 +13,13 @@ export default function DmPage() {
|
||||
<h4 className="text-center underline text-2xl">
|
||||
Simple instructions for creating/updating orders
|
||||
</h4>
|
||||
<div className="flex flex-row gap-3 m-1">
|
||||
<OrderImport
|
||||
fileType={"standard"}
|
||||
name={"Standard Order Import"}
|
||||
/>
|
||||
<StandardOrderTemplate />
|
||||
</div>
|
||||
<Separator />
|
||||
</div>
|
||||
|
||||
@@ -36,6 +47,7 @@ export default function DmPage() {
|
||||
<h4 className="text-center underline text-2xl">
|
||||
Some notes to consider
|
||||
</h4>
|
||||
|
||||
<ul className="list-disc mr-2">
|
||||
<li>
|
||||
No longer need to add in the invoice id, we take the
|
||||
@@ -80,8 +92,15 @@ export default function DmPage() {
|
||||
<h4 className="text-center underline text-2xl">
|
||||
Simple instructions for creating forecast
|
||||
</h4>
|
||||
<div className="flex flex-row gap-3 m-1">
|
||||
<ForecastImport
|
||||
fileType={"standard"}
|
||||
name={"Standard Forecast Import"}
|
||||
/>
|
||||
<StandardForecastTemplate />
|
||||
<Separator className="my-4" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="m-5">
|
||||
<ul className="list-disc mr-2">
|
||||
<li>
|
||||
|
||||
193
frontend/src/components/user/PasswordChange.tsx
Normal file
193
frontend/src/components/user/PasswordChange.tsx
Normal file
@@ -0,0 +1,193 @@
|
||||
import { useForm } from "@tanstack/react-form";
|
||||
import { useNavigate } from "@tanstack/react-router";
|
||||
import axios from "axios";
|
||||
import { useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { LstCard } from "../extendedUI/LstCard";
|
||||
import { CardContent, CardHeader } from "../ui/card";
|
||||
|
||||
import { Label } from "../ui/label";
|
||||
import { Input } from "../ui/input";
|
||||
import { Button } from "../ui/button";
|
||||
|
||||
export default function PasswordChange() {
|
||||
const [saving, setSaving] = useState(false);
|
||||
const token = localStorage.getItem("auth_token");
|
||||
const navigate = useNavigate();
|
||||
|
||||
const form = useForm({
|
||||
defaultValues: {
|
||||
password: "",
|
||||
confirmPassword: "",
|
||||
},
|
||||
onSubmit: async ({ value }) => {
|
||||
setSaving(true);
|
||||
try {
|
||||
const res = await axios.patch("/api/auth/profile", value, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
//console.log(res.data);
|
||||
|
||||
if (res.data.success) {
|
||||
localStorage.removeItem("auth_token");
|
||||
navigate({ to: "/login" });
|
||||
form.reset();
|
||||
toast.success(`Your password was just updated.`);
|
||||
setSaving(false);
|
||||
}
|
||||
|
||||
if (!res.data.success) {
|
||||
toast.error(res.data.message);
|
||||
setSaving(false);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
toast.error("There was an error updating your password");
|
||||
setSaving(false);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<LstCard className="w-96 ml-7">
|
||||
<CardHeader>
|
||||
<p>Password Change Form</p>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<form.Field
|
||||
name="password"
|
||||
// We can choose between form-wide and field-specific validators
|
||||
validators={{
|
||||
onChangeAsyncDebounceMs: 500,
|
||||
onChangeAsync: ({ value }) => {
|
||||
// if (
|
||||
// window.location.pathname.includes(
|
||||
// "/users"
|
||||
// ) &&
|
||||
// value.length === 0
|
||||
// ) {
|
||||
// return;
|
||||
// }
|
||||
if (value.length < 4) {
|
||||
return "Password must be at least 4 characters long.";
|
||||
}
|
||||
|
||||
if (!/[A-Z]/.test(value)) {
|
||||
return "Password must contain at least one uppercase letter.";
|
||||
}
|
||||
|
||||
if (!/[a-z]/.test(value)) {
|
||||
return "Password must contain at least one lower case letter.";
|
||||
}
|
||||
|
||||
if (!/[0-9]/.test(value)) {
|
||||
return "Password must contain at least one number.";
|
||||
}
|
||||
|
||||
if (
|
||||
!/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(
|
||||
value
|
||||
)
|
||||
) {
|
||||
return "Password must contain at least one special character.";
|
||||
}
|
||||
},
|
||||
}}
|
||||
children={(field) => {
|
||||
return (
|
||||
<div className="m-2 min-w-48 max-w-96 p-2">
|
||||
<Label
|
||||
htmlFor="password1"
|
||||
className="mb-2"
|
||||
>
|
||||
Password
|
||||
</Label>
|
||||
<Input
|
||||
name={field.name}
|
||||
value={field.state.value}
|
||||
onBlur={field.handleBlur}
|
||||
type="password"
|
||||
onChange={(e) =>
|
||||
field.handleChange(
|
||||
e.target.value
|
||||
)
|
||||
}
|
||||
/>
|
||||
{field.state.meta.errors.length ? (
|
||||
<em>
|
||||
{field.state.meta.errors.join(
|
||||
","
|
||||
)}
|
||||
</em>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
||||
<form.Field
|
||||
name="confirmPassword"
|
||||
validators={{
|
||||
onChange: ({ value, fieldApi }) => {
|
||||
const password =
|
||||
fieldApi.form.getFieldValue("password");
|
||||
if (value !== password) {
|
||||
return "Passwords do not match.";
|
||||
}
|
||||
},
|
||||
}}
|
||||
>
|
||||
{(field) => {
|
||||
return (
|
||||
<div className="m-2 min-w-48 max-w-96 p-2">
|
||||
<Label
|
||||
htmlFor="confirmPassword"
|
||||
className="mb-2"
|
||||
>
|
||||
Confirm Password
|
||||
</Label>
|
||||
<Input
|
||||
name={field.name}
|
||||
value={field.state.value}
|
||||
onBlur={field.handleBlur}
|
||||
type="password"
|
||||
onChange={(e) =>
|
||||
field.handleChange(
|
||||
e.target.value
|
||||
)
|
||||
}
|
||||
/>
|
||||
{field.state.meta.errors.length ? (
|
||||
<em>
|
||||
{field.state.meta.errors.join(
|
||||
", "
|
||||
)}
|
||||
</em>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</form.Field>
|
||||
<div className="mt-4 ml-4 flex justify-end">
|
||||
<Button
|
||||
type="submit"
|
||||
onClick={form.handleSubmit}
|
||||
disabled={saving}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</CardContent>
|
||||
</LstCard>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
// Import Routes
|
||||
|
||||
import { Route as rootRoute } from './routes/__root'
|
||||
import { Route as RegisterImport } from './routes/register'
|
||||
import { Route as LoginImport } from './routes/login'
|
||||
import { Route as ChangelogImport } from './routes/changelog'
|
||||
import { Route as AboutImport } from './routes/about'
|
||||
@@ -27,6 +28,7 @@ import { Route as AdminSettingsImport } from './routes/_admin/settings'
|
||||
import { Route as AdminServersImport } from './routes/_admin/servers'
|
||||
import { Route as AdminNotificationMGTImport } from './routes/_admin/notificationMGT'
|
||||
import { Route as AdminModulesImport } from './routes/_admin/modules'
|
||||
import { Route as userPasswordChangeImport } from './routes/(user)/passwordChange'
|
||||
import { Route as ocmeCyclecountIndexImport } from './routes/(ocme)/cyclecount/index'
|
||||
import { Route as logisticsSiloAdjustmentsIndexImport } from './routes/(logistics)/siloAdjustments/index'
|
||||
import { Route as logisticsOpenOrdersIndexImport } from './routes/(logistics)/openOrders/index'
|
||||
@@ -40,6 +42,12 @@ import { Route as logisticsSiloAdjustmentsCommentCommentImport } from './routes/
|
||||
|
||||
// Create/Update Routes
|
||||
|
||||
const RegisterRoute = RegisterImport.update({
|
||||
id: '/register',
|
||||
path: '/register',
|
||||
getParentRoute: () => rootRoute,
|
||||
} as any)
|
||||
|
||||
const LoginRoute = LoginImport.update({
|
||||
id: '/login',
|
||||
path: '/login',
|
||||
@@ -133,6 +141,12 @@ const AdminModulesRoute = AdminModulesImport.update({
|
||||
getParentRoute: () => AdminRoute,
|
||||
} as any)
|
||||
|
||||
const userPasswordChangeRoute = userPasswordChangeImport.update({
|
||||
id: '/(user)/passwordChange',
|
||||
path: '/passwordChange',
|
||||
getParentRoute: () => rootRoute,
|
||||
} as any)
|
||||
|
||||
const ocmeCyclecountIndexRoute = ocmeCyclecountIndexImport.update({
|
||||
id: '/(ocme)/cyclecount/',
|
||||
path: '/cyclecount/',
|
||||
@@ -252,6 +266,20 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof LoginImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
'/register': {
|
||||
id: '/register'
|
||||
path: '/register'
|
||||
fullPath: '/register'
|
||||
preLoaderRoute: typeof RegisterImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
'/(user)/passwordChange': {
|
||||
id: '/(user)/passwordChange'
|
||||
path: '/passwordChange'
|
||||
fullPath: '/passwordChange'
|
||||
preLoaderRoute: typeof userPasswordChangeImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
'/_admin/modules': {
|
||||
id: '/_admin/modules'
|
||||
path: '/modules'
|
||||
@@ -438,6 +466,8 @@ export interface FileRoutesByFullPath {
|
||||
'/about': typeof AboutRoute
|
||||
'/changelog': typeof ChangelogRoute
|
||||
'/login': typeof LoginRoute
|
||||
'/register': typeof RegisterRoute
|
||||
'/passwordChange': typeof userPasswordChangeRoute
|
||||
'/modules': typeof AdminModulesRoute
|
||||
'/notificationMGT': typeof AdminNotificationMGTRoute
|
||||
'/servers': typeof AdminServersRoute
|
||||
@@ -465,6 +495,8 @@ export interface FileRoutesByTo {
|
||||
'/about': typeof AboutRoute
|
||||
'/changelog': typeof ChangelogRoute
|
||||
'/login': typeof LoginRoute
|
||||
'/register': typeof RegisterRoute
|
||||
'/passwordChange': typeof userPasswordChangeRoute
|
||||
'/modules': typeof AdminModulesRoute
|
||||
'/notificationMGT': typeof AdminNotificationMGTRoute
|
||||
'/servers': typeof AdminServersRoute
|
||||
@@ -495,6 +527,8 @@ export interface FileRoutesById {
|
||||
'/about': typeof AboutRoute
|
||||
'/changelog': typeof ChangelogRoute
|
||||
'/login': typeof LoginRoute
|
||||
'/register': typeof RegisterRoute
|
||||
'/(user)/passwordChange': typeof userPasswordChangeRoute
|
||||
'/_admin/modules': typeof AdminModulesRoute
|
||||
'/_admin/notificationMGT': typeof AdminNotificationMGTRoute
|
||||
'/_admin/servers': typeof AdminServersRoute
|
||||
@@ -524,6 +558,8 @@ export interface FileRouteTypes {
|
||||
| '/about'
|
||||
| '/changelog'
|
||||
| '/login'
|
||||
| '/register'
|
||||
| '/passwordChange'
|
||||
| '/modules'
|
||||
| '/notificationMGT'
|
||||
| '/servers'
|
||||
@@ -550,6 +586,8 @@ export interface FileRouteTypes {
|
||||
| '/about'
|
||||
| '/changelog'
|
||||
| '/login'
|
||||
| '/register'
|
||||
| '/passwordChange'
|
||||
| '/modules'
|
||||
| '/notificationMGT'
|
||||
| '/servers'
|
||||
@@ -578,6 +616,8 @@ export interface FileRouteTypes {
|
||||
| '/about'
|
||||
| '/changelog'
|
||||
| '/login'
|
||||
| '/register'
|
||||
| '/(user)/passwordChange'
|
||||
| '/_admin/modules'
|
||||
| '/_admin/notificationMGT'
|
||||
| '/_admin/servers'
|
||||
@@ -608,6 +648,8 @@ export interface RootRouteChildren {
|
||||
AboutRoute: typeof AboutRoute
|
||||
ChangelogRoute: typeof ChangelogRoute
|
||||
LoginRoute: typeof LoginRoute
|
||||
RegisterRoute: typeof RegisterRoute
|
||||
userPasswordChangeRoute: typeof userPasswordChangeRoute
|
||||
OcpIndexRoute: typeof OcpIndexRoute
|
||||
logisticsSiloAdjustmentsHistRoute: typeof logisticsSiloAdjustmentsHistRoute
|
||||
logisticsDmIndexRoute: typeof logisticsDmIndexRoute
|
||||
@@ -628,6 +670,8 @@ const rootRouteChildren: RootRouteChildren = {
|
||||
AboutRoute: AboutRoute,
|
||||
ChangelogRoute: ChangelogRoute,
|
||||
LoginRoute: LoginRoute,
|
||||
RegisterRoute: RegisterRoute,
|
||||
userPasswordChangeRoute: userPasswordChangeRoute,
|
||||
OcpIndexRoute: OcpIndexRoute,
|
||||
logisticsSiloAdjustmentsHistRoute: logisticsSiloAdjustmentsHistRoute,
|
||||
logisticsDmIndexRoute: logisticsDmIndexRoute,
|
||||
@@ -660,6 +704,8 @@ export const routeTree = rootRoute
|
||||
"/about",
|
||||
"/changelog",
|
||||
"/login",
|
||||
"/register",
|
||||
"/(user)/passwordChange",
|
||||
"/ocp/",
|
||||
"/(logistics)/siloAdjustments/$hist",
|
||||
"/(logistics)/dm/",
|
||||
@@ -708,6 +754,12 @@ export const routeTree = rootRoute
|
||||
"/login": {
|
||||
"filePath": "login.tsx"
|
||||
},
|
||||
"/register": {
|
||||
"filePath": "register.tsx"
|
||||
},
|
||||
"/(user)/passwordChange": {
|
||||
"filePath": "(user)/passwordChange.tsx"
|
||||
},
|
||||
"/_admin/modules": {
|
||||
"filePath": "_admin/modules.tsx",
|
||||
"parent": "/_admin"
|
||||
|
||||
28
frontend/src/routes/(user)/passwordChange.tsx
Normal file
28
frontend/src/routes/(user)/passwordChange.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import PasswordChange from "@/components/user/PasswordChange";
|
||||
import { createFileRoute, redirect } from "@tanstack/react-router";
|
||||
|
||||
export const Route = createFileRoute("/(user)/passwordChange")({
|
||||
component: RouteComponent,
|
||||
beforeLoad: async () => {
|
||||
const auth = localStorage.getItem("auth_token");
|
||||
if (!auth) {
|
||||
throw redirect({
|
||||
to: "/login",
|
||||
search: {
|
||||
// Use the current location to power a redirect after login
|
||||
// (Do not use `router.state.resolvedLocation` as it can
|
||||
// potentially lag behind the actual current location)
|
||||
redirect: location.pathname + location.search,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
function RouteComponent() {
|
||||
return (
|
||||
<div>
|
||||
<PasswordChange />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -80,8 +80,12 @@ export const Route = createRootRoute({
|
||||
Hello {user?.username}
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
{/* <DropdownMenuItem>Profile</DropdownMenuItem>
|
||||
<DropdownMenuItem>Billing</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<Link to="/passwordChange">
|
||||
Password Change
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
{/* <DropdownMenuItem>Billing</DropdownMenuItem>
|
||||
<DropdownMenuItem>Team</DropdownMenuItem>
|
||||
<DropdownMenuItem>Subscription</DropdownMenuItem> */}
|
||||
<hr className="solid"></hr>
|
||||
|
||||
106
frontend/src/routes/register.tsx
Normal file
106
frontend/src/routes/register.tsx
Normal file
@@ -0,0 +1,106 @@
|
||||
import RegisterForm from "@/components/auth/Register";
|
||||
import { LstCard } from "@/components/extendedUI/LstCard";
|
||||
import { CardContent, CardHeader } from "@/components/ui/card";
|
||||
import { createFileRoute, redirect } from "@tanstack/react-router";
|
||||
|
||||
export const Route = createFileRoute("/register")({
|
||||
component: RouteComponent,
|
||||
beforeLoad: () => {
|
||||
const isLoggedIn = localStorage.getItem("auth_token");
|
||||
if (isLoggedIn) {
|
||||
throw redirect({
|
||||
to: "/",
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
function RouteComponent() {
|
||||
return (
|
||||
<div className="flex flex-row w-5/6 justify-between gap-2">
|
||||
<RegisterForm />
|
||||
<div>
|
||||
<LstCard>
|
||||
<CardHeader>
|
||||
<h2 className="text-2xl font-bold mb-4">
|
||||
Disclaimer and User Agreement
|
||||
</h2>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="max-w-2xl mx-auto p-6 rounded-2xl shadow-md">
|
||||
<ul className="list-decimal list-inside space-y-3">
|
||||
<li>
|
||||
<span className="font-bold">
|
||||
Authentication Notice:
|
||||
</span>
|
||||
To interact with the Alpla prod through this
|
||||
application, you must use your{" "}
|
||||
<span className="font-semibold">
|
||||
Windows login credentials
|
||||
</span>
|
||||
. These credentials are used solely for
|
||||
authentication purposes.
|
||||
</li>
|
||||
{/* <li>
|
||||
<span className="font-bold">
|
||||
Password Privacy and Security:
|
||||
</span>
|
||||
This application{" "}
|
||||
<span className="font-semibold">
|
||||
does not store, sync, or transmit
|
||||
</span>{" "}
|
||||
your Windows password in any form.
|
||||
Authentication is handled securely, and your
|
||||
credentials are never logged or accessible
|
||||
to the developers or third parties.
|
||||
</li> */}
|
||||
<li>
|
||||
<span className="font-bold">
|
||||
Data Handling:
|
||||
</span>
|
||||
All data accessed through the Alpla prod
|
||||
remains the property of Alpla. The app
|
||||
functions as a secure interface for
|
||||
accessing and updating this information
|
||||
where permitted by your role.
|
||||
</li>
|
||||
<li>
|
||||
<span className="font-bold">
|
||||
User Responsibility:
|
||||
</span>
|
||||
You are responsible for any actions
|
||||
performed using your account. Please ensure
|
||||
you do not share your credentials with
|
||||
others and always log out of the application
|
||||
when not in use.
|
||||
</li>
|
||||
<li>
|
||||
<span className="font-bold">
|
||||
No Warranty:
|
||||
</span>
|
||||
This application is provided "
|
||||
<span className="italic">as is</span>"
|
||||
without any warranty of any kind, either
|
||||
expressed or implied. While every effort is
|
||||
made to ensure functionality and data
|
||||
accuracy, the app is subject to ongoing
|
||||
development and may contain bugs or require
|
||||
updates.
|
||||
</li>
|
||||
<li>
|
||||
<span className="font-bold">
|
||||
Consent Required:
|
||||
</span>
|
||||
By signing up or continuing to use this
|
||||
application, you agree to the above terms
|
||||
and acknowledge that you understand how your
|
||||
login information is used.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</CardContent>
|
||||
</LstCard>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "lstv2",
|
||||
"version": "2.16.0",
|
||||
"version": "2.16.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "lstv2",
|
||||
"version": "2.16.0",
|
||||
"version": "2.16.1",
|
||||
"dependencies": {
|
||||
"@dotenvx/dotenvx": "^1.39.0",
|
||||
"@hono/node-server": "^1.14.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "lstv2",
|
||||
"version": "2.16.0",
|
||||
"version": "2.16.1",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "concurrently -n \"server,frontend\" -c \"#007755,#2f6da3\" \"npm run dev:server\" \"cd frontend && npm run dev\"",
|
||||
@@ -18,7 +18,7 @@
|
||||
"db:generate": "npx drizzle-kit generate",
|
||||
"db:migrate": "npx drizzle-kit push",
|
||||
"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 build",
|
||||
"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",
|
||||
"scriptBuild": "powershell -ExecutionPolicy Bypass -File server/scripts/build.ps1 -dir \"C:\\Users\\matthes01\\Documents\\lstv2\"",
|
||||
@@ -35,7 +35,7 @@
|
||||
}
|
||||
},
|
||||
"admConfig": {
|
||||
"build": 288,
|
||||
"build": 297,
|
||||
"oldBuild": "backend-0.1.3.zip"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -146,7 +146,7 @@ $plantFunness = {
|
||||
############################################################################
|
||||
Write-Host "Stopping the services to do the updates, pkgs and db changes."
|
||||
|
||||
Write-Host "Stopping services to update"
|
||||
#Write-Host "Stopping services to update"
|
||||
$serviceGateway = "LST-Gateway$(if ($token -eq "usiow2") { "_2" })"
|
||||
$serviceAuth = "LST-Auth$(if ($token -eq "usiow2") { "_2" })"
|
||||
$serviceSystem = "LST-System$(if ($token -eq "usiow2") { "_2" })"
|
||||
@@ -155,30 +155,30 @@ $plantFunness = {
|
||||
$serviceOcme = "LST-Ocme$(if ($token -eq "usiow2") { "_2" })"
|
||||
$serviceLstV2 = "LSTV2$(if ($token -eq "usiow2") { "_2" })"
|
||||
|
||||
if($token -eq "usday1"){
|
||||
Write-Host "Stopping $($serviceOcme)"
|
||||
Stop-Service -DisplayName $serviceOcme -Force
|
||||
}
|
||||
# if($token -eq "usday1"){
|
||||
# Write-Host "Stopping $($serviceOcme)"
|
||||
# Stop-Service -DisplayName $serviceOcme -Force
|
||||
# }
|
||||
|
||||
Write-Host "Stopping $($serviceGateway)"
|
||||
Stop-Service -DisplayName $serviceGateway -Force
|
||||
Start-Sleep -Seconds 1
|
||||
# Write-Host "Stopping $($serviceGateway)"
|
||||
# Stop-Service -DisplayName $serviceGateway -Force
|
||||
# Start-Sleep -Seconds 1
|
||||
|
||||
Write-Host "Stopping $($serviceAuth)"
|
||||
Stop-Service -DisplayName $serviceAuth -Force
|
||||
Start-Sleep -Seconds 1
|
||||
# Write-Host "Stopping $($serviceAuth)"
|
||||
# Stop-Service -DisplayName $serviceAuth -Force
|
||||
# Start-Sleep -Seconds 1
|
||||
|
||||
Write-Host "Stopping $($serviceSystem)"
|
||||
Stop-Service -DisplayName $serviceSystem -Force
|
||||
Start-Sleep -Seconds 1
|
||||
# Write-Host "Stopping $($serviceSystem)"
|
||||
# Stop-Service -DisplayName $serviceSystem -Force
|
||||
# Start-Sleep -Seconds 1
|
||||
|
||||
Write-Host "Stopping $($serviceApp)"
|
||||
Stop-Service -DisplayName $serviceApp -Force
|
||||
Start-Sleep -Seconds 1
|
||||
# Write-Host "Stopping $($serviceApp)"
|
||||
# Stop-Service -DisplayName $serviceApp -Force
|
||||
# Start-Sleep -Seconds 1
|
||||
|
||||
Write-Host "Stopping $($serviceFrontEnd)"
|
||||
Stop-Service -DisplayName $serviceFrontEnd -Force
|
||||
Start-Sleep -Seconds 1
|
||||
# Write-Host "Stopping $($serviceFrontEnd)"
|
||||
# Stop-Service -DisplayName $serviceFrontEnd -Force
|
||||
# Start-Sleep -Seconds 1
|
||||
|
||||
Write-Host "Stopping $($serviceLstV2)"
|
||||
Stop-Service -DisplayName $serviceLstV2 -Force
|
||||
@@ -194,11 +194,16 @@ $plantFunness = {
|
||||
Write-Host "Removing services that are no longer used."
|
||||
& $nssmPath remove "LogisticsSupportTool" confirm
|
||||
& $nssmPath remove $serviceAuth confirm
|
||||
& $nssmPath remove $serviceGateway confirm
|
||||
& $nssmPath remove $serviceSystem confirm
|
||||
& $nssmPath remove $serviceApp confirm
|
||||
& $nssmPath remove $serviceFrontEnd confirm
|
||||
& $nssmPath remove $serviceOcme confirm
|
||||
# & $nssmPath remove $serviceGateway confirm
|
||||
# if($token -eq "usday1"){
|
||||
# & $nssmPath remove $serviceOcme confirm
|
||||
# }
|
||||
Start-Sleep -Seconds 5
|
||||
Start-Sleep -Seconds 2
|
||||
|
||||
$service = Get-Service -Name $serviceLstV2 -ErrorAction SilentlyContinue
|
||||
|
||||
@@ -233,188 +238,188 @@ $plantFunness = {
|
||||
# Frontend env
|
||||
###########################################################
|
||||
|
||||
Write-Host "Creating the env file in the front end"
|
||||
$envContentTemplatef = @"
|
||||
NEXTAUTH_SECRET= "12348fssad5sdg2f2354afvfw34"
|
||||
NEXTAUTH_URL_INTERNAL= "http://localhost:3000"
|
||||
NEXTAUTH_URL="{url}"
|
||||
API_KEY= "E3ECD3619A943B98C6F33E3322362"
|
||||
"@
|
||||
# Write-Host "Creating the env file in the front end"
|
||||
# $envContentTemplatef = @"
|
||||
# NEXTAUTH_SECRET= "12348fssad5sdg2f2354afvfw34"
|
||||
# NEXTAUTH_URL_INTERNAL= "http://localhost:3000"
|
||||
# NEXTAUTH_URL="{url}"
|
||||
# API_KEY= "E3ECD3619A943B98C6F33E3322362"
|
||||
# "@
|
||||
|
||||
try {
|
||||
$url = "http://$($token)vms006:3000"
|
||||
# try {
|
||||
# $url = "http://$($token)vms006:3000"
|
||||
|
||||
if ($token -eq "usiow2") {
|
||||
$url = "http://usiow1vms006:3001"
|
||||
}
|
||||
# if ($token -eq "usiow2") {
|
||||
# $url = "http://usiow1vms006:3001"
|
||||
# }
|
||||
|
||||
if ($token -in @("test1", "test2", "test3")) {
|
||||
$url = "http://usmcd1vms036:3000"
|
||||
}
|
||||
# if ($token -in @("test1", "test2", "test3")) {
|
||||
# $url = "http://usmcd1vms036:3000"
|
||||
# }
|
||||
|
||||
# Replace {url} with the actual $url
|
||||
$envContentf = $envContentTemplatef -replace "{url}", $url
|
||||
# # Replace {url} with the actual $url
|
||||
# $envContentf = $envContentTemplatef -replace "{url}", $url
|
||||
|
||||
# Define the path where the .env file should be created
|
||||
$envFilePathf = $obslst + "\apps\frontend\.env"
|
||||
Write-Host "Final URL: $url"
|
||||
# Write the content to the .env file
|
||||
$envContentf | Out-File -FilePath $envFilePathf -Encoding UTF8 -Force
|
||||
# # Define the path where the .env file should be created
|
||||
# $envFilePathf = $obslst + "\apps\frontend\.env"
|
||||
# Write-Host "Final URL: $url"
|
||||
# # Write the content to the .env file
|
||||
# $envContentf | Out-File -FilePath $envFilePathf -Encoding UTF8 -Force
|
||||
|
||||
# Optional: Verify the file was created
|
||||
if (Test-Path $envFilePathf) {
|
||||
Write-Host "`.env` file created successfully on $env:COMPUTERNAME at $envFilePathf"
|
||||
} else {
|
||||
Write-Host "Failed to create `.env` file on $env:COMPUTERNAME"
|
||||
}
|
||||
# # Optional: Verify the file was created
|
||||
# if (Test-Path $envFilePathf) {
|
||||
# Write-Host "`.env` file created successfully on $env:COMPUTERNAME at $envFilePathf"
|
||||
# } else {
|
||||
# Write-Host "Failed to create `.env` file on $env:COMPUTERNAME"
|
||||
# }
|
||||
|
||||
} catch {
|
||||
Write-Host "Error: Failed to create `.env` file on $server - $_"
|
||||
}
|
||||
# } catch {
|
||||
# Write-Host "Error: Failed to create `.env` file on $server - $_"
|
||||
# }
|
||||
|
||||
###########################################################
|
||||
# DB env
|
||||
###########################################################
|
||||
|
||||
Write-Host "Creating the env file in the front end"
|
||||
$envContentTemplateb = @"
|
||||
DATABASE_URL="file:E:\LST\db\{dbLink}.db"
|
||||
"@
|
||||
# Write-Host "Creating the env file in the front end"
|
||||
# $envContentTemplateb = @"
|
||||
# DATABASE_URL="file:E:\LST\db\{dbLink}.db"
|
||||
# "@
|
||||
|
||||
try {
|
||||
# try {
|
||||
|
||||
$dbLink = "lstBackendDB"
|
||||
# $dbLink = "lstBackendDB"
|
||||
|
||||
if ($token -eq "usiow2") {
|
||||
$dbLink = "lstBackendDB_2"
|
||||
}
|
||||
# if ($token -eq "usiow2") {
|
||||
# $dbLink = "lstBackendDB_2"
|
||||
# }
|
||||
|
||||
if ($token -in @("test1", "test2", "test3")) {
|
||||
$dbLink = "lstBackendDB"
|
||||
}
|
||||
# if ($token -in @("test1", "test2", "test3")) {
|
||||
# $dbLink = "lstBackendDB"
|
||||
# }
|
||||
|
||||
# Replace {url} with the actual $url
|
||||
$envContentb = $envContentTemplateb -replace "{dbLink}", $dbLink
|
||||
# # Replace {url} with the actual $url
|
||||
# $envContentb = $envContentTemplateb -replace "{dbLink}", $dbLink
|
||||
|
||||
# Define the path where the .env file should be created
|
||||
$envFilePathb = $obslst + "\packages\database\.env"
|
||||
# # Define the path where the .env file should be created
|
||||
# $envFilePathb = $obslst + "\packages\database\.env"
|
||||
|
||||
# Write the content to the .env file
|
||||
$envContentb | Out-File -FilePath $envFilePathb -Encoding UTF8 -Force
|
||||
# # Write the content to the .env file
|
||||
# $envContentb | Out-File -FilePath $envFilePathb -Encoding UTF8 -Force
|
||||
|
||||
# Optional: Verify the file was created
|
||||
if (Test-Path $envFilePathb) {
|
||||
Write-Host "`.env` file created successfully on $env:COMPUTERNAME at $envFilePathb"
|
||||
} else {
|
||||
Write-Host "Failed to create `.env` file on $env:COMPUTERNAME"
|
||||
}
|
||||
# # Optional: Verify the file was created
|
||||
# if (Test-Path $envFilePathb) {
|
||||
# Write-Host "`.env` file created successfully on $env:COMPUTERNAME at $envFilePathb"
|
||||
# } else {
|
||||
# Write-Host "Failed to create `.env` file on $env:COMPUTERNAME"
|
||||
# }
|
||||
|
||||
} catch {
|
||||
Write-Host "Error: Failed to create `.env` file on $server - $_"
|
||||
}
|
||||
# } catch {
|
||||
# Write-Host "Error: Failed to create `.env` file on $server - $_"
|
||||
# }
|
||||
|
||||
###########################################################
|
||||
# backend env
|
||||
###########################################################
|
||||
|
||||
Write-Host "Creating the env file in the front end"
|
||||
$envContentTemplated = @"
|
||||
# Server env
|
||||
NODE_ENV = production
|
||||
# server apiKey
|
||||
API_KEY = E3ECD3619A943B98C6F33E3322362
|
||||
# Prisma DB link
|
||||
DATABASE_URL="file:E:\LST\db\{dbLink}.db"
|
||||
# if you still want the db in the same folder as the server install you need to do like the example below else use the relevent link
|
||||
DATEBASE_LOC="E:\LST\db\{dbLink}.db"
|
||||
DATABASE_BACKUP_LOC="E:\LST\backups"
|
||||
# Server port
|
||||
GATEWAY_PORT={gatewayport}
|
||||
AUTH_PORT=4100
|
||||
SYSTEM_APP_PORT={systemport}
|
||||
OCME_PORT={ocme}
|
||||
# Write-Host "Creating the env file in the front end"
|
||||
# $envContentTemplated = @"
|
||||
# # Server env
|
||||
# NODE_ENV = production
|
||||
# # server apiKey
|
||||
# API_KEY = E3ECD3619A943B98C6F33E3322362
|
||||
# # Prisma DB link
|
||||
# DATABASE_URL="file:E:\LST\db\{dbLink}.db"
|
||||
# # if you still want the db in the same folder as the server install you need to do like the example below else use the relevent link
|
||||
# DATEBASE_LOC="E:\LST\db\{dbLink}.db"
|
||||
# DATABASE_BACKUP_LOC="E:\LST\backups"
|
||||
# # Server port
|
||||
# GATEWAY_PORT={gatewayport}
|
||||
# AUTH_PORT=4100
|
||||
# SYSTEM_APP_PORT={systemport}
|
||||
# OCME_PORT={ocme}
|
||||
|
||||
# This should me removed once we have the entire app broke out to its own apps
|
||||
OLD_APP_PORT={appPort}
|
||||
# # This should me removed once we have the entire app broke out to its own apps
|
||||
# OLD_APP_PORT={appPort}
|
||||
|
||||
# Logging
|
||||
LOG_LEVEL = info
|
||||
LOG_LOC ="E:\\LST\\logs"
|
||||
# # Logging
|
||||
# LOG_LEVEL = info
|
||||
# LOG_LOC ="E:\\LST\\logs"
|
||||
|
||||
# authentication
|
||||
SALTING = 12
|
||||
SECRET = E3ECD3619A943B98C6F33E3322362
|
||||
JWT_SECRET = 12348fssad5sdg2f2354afvfw34
|
||||
JWT_EXPIRES_TIME = 1h
|
||||
# # authentication
|
||||
# SALTING = 12
|
||||
# SECRET = E3ECD3619A943B98C6F33E3322362
|
||||
# JWT_SECRET = 12348fssad5sdg2f2354afvfw34
|
||||
# JWT_EXPIRES_TIME = 1h
|
||||
|
||||
# cookie time is in min please take this into consideration when creating all the times
|
||||
COOKIE_EXPIRES_TIME = 60
|
||||
# # cookie time is in min please take this into consideration when creating all the times
|
||||
# COOKIE_EXPIRES_TIME = 60
|
||||
|
||||
# password token reset in mintues
|
||||
RESET_TOKEN = 330
|
||||
"@
|
||||
# # password token reset in mintues
|
||||
# RESET_TOKEN = 330
|
||||
# "@
|
||||
|
||||
try {
|
||||
# try {
|
||||
|
||||
$dbLink = "lstBackendDB"
|
||||
$gatewayport = "4400"
|
||||
$systemport = "4200"
|
||||
$ocmeport = "4300"
|
||||
$appport = "4400"
|
||||
# $dbLink = "lstBackendDB"
|
||||
# $gatewayport = "4400"
|
||||
# $systemport = "4200"
|
||||
# $ocmeport = "4300"
|
||||
# $appport = "4400"
|
||||
|
||||
if ($token -eq "usiow2") {
|
||||
$dbLink = "lstBackendDB_2"
|
||||
$gatewayport = "4401"
|
||||
$systemport = "4201"
|
||||
$ocmeport = "4301"
|
||||
$appport = "4401"
|
||||
}
|
||||
# if ($token -eq "usiow2") {
|
||||
# $dbLink = "lstBackendDB_2"
|
||||
# $gatewayport = "4401"
|
||||
# $systemport = "4201"
|
||||
# $ocmeport = "4301"
|
||||
# $appport = "4401"
|
||||
# }
|
||||
|
||||
if ($token -in @("test1", "test2", "test3")) {
|
||||
$dbLink = "lstBackendDB"
|
||||
}
|
||||
# if ($token -in @("test1", "test2", "test3")) {
|
||||
# $dbLink = "lstBackendDB"
|
||||
# }
|
||||
|
||||
#
|
||||
$port1 = $envContentTemplated -replace "{gatewayport}", $gatewayport
|
||||
$port2 = $port1 -replace "{systemport}", $systemport
|
||||
$port3 = $port2 -replace "{ocme}", $ocmeport
|
||||
$port4 = $port3 -replace "{appPort}", $appport
|
||||
$envContentd = $port4 -replace "{dbLink}", $dbLink
|
||||
# #
|
||||
# $port1 = $envContentTemplated -replace "{gatewayport}", $gatewayport
|
||||
# $port2 = $port1 -replace "{systemport}", $systemport
|
||||
# $port3 = $port2 -replace "{ocme}", $ocmeport
|
||||
# $port4 = $port3 -replace "{appPort}", $appport
|
||||
# $envContentd = $port4 -replace "{dbLink}", $dbLink
|
||||
|
||||
|
||||
# Define the path where the .env file should be created
|
||||
$envFilePathd = $obslst + "\.env"
|
||||
# # Define the path where the .env file should be created
|
||||
# $envFilePathd = $obslst + "\.env"
|
||||
|
||||
# Write the content to the .env file
|
||||
$envContentd | Out-File -FilePath $envFilePathd -Encoding UTF8 -Force
|
||||
# # Write the content to the .env file
|
||||
# $envContentd | Out-File -FilePath $envFilePathd -Encoding UTF8 -Force
|
||||
|
||||
# Optional: Verify the file was created
|
||||
if (Test-Path $envFilePathd) {
|
||||
Write-Host "`.env` file created successfully on $env:COMPUTERNAME at $envFilePathd"
|
||||
} else {
|
||||
Write-Host "Failed to create `.env` file on $env:COMPUTERNAME"
|
||||
}
|
||||
# # Optional: Verify the file was created
|
||||
# if (Test-Path $envFilePathd) {
|
||||
# Write-Host "`.env` file created successfully on $env:COMPUTERNAME at $envFilePathd"
|
||||
# } else {
|
||||
# Write-Host "Failed to create `.env` file on $env:COMPUTERNAME"
|
||||
# }
|
||||
|
||||
} catch {
|
||||
Write-Host "Error: Failed to create `.env` file on $server - $_"
|
||||
}
|
||||
# } catch {
|
||||
# Write-Host "Error: Failed to create `.env` file on $server - $_"
|
||||
# }
|
||||
|
||||
|
||||
Write-Host "Running install on obs server."
|
||||
Set-Location $obslst
|
||||
npm run newinstall # --omit=dev
|
||||
Write-Host "Update the frontend"
|
||||
npm run install:front
|
||||
npm run install:ui
|
||||
npm run install:db
|
||||
# Write-Host "Running install on obs server."
|
||||
# Set-Location $obslst
|
||||
# npm run newinstall # --omit=dev
|
||||
# Write-Host "Update the frontend"
|
||||
# npm run install:front
|
||||
# npm run install:ui
|
||||
# npm run install:db
|
||||
|
||||
Write-Host "Running db updates"
|
||||
npm run db:migrate
|
||||
Start-Sleep -Seconds 1
|
||||
npm run db:gen
|
||||
Start-Sleep -Seconds 1
|
||||
Write-Host "incase a new default setting was added we want to add it in."
|
||||
npm run db:init
|
||||
# Write-Host "Running db updates"
|
||||
# npm run db:migrate
|
||||
# Start-Sleep -Seconds 1
|
||||
# npm run db:gen
|
||||
# Start-Sleep -Seconds 1
|
||||
# Write-Host "incase a new default setting was added we want to add it in."
|
||||
# npm run db:init
|
||||
|
||||
###########################################################
|
||||
# Starting the services back up.
|
||||
|
||||
@@ -51,7 +51,7 @@ export const registerUser = async (
|
||||
setSysAdmin(updateUser, "systemAdmin");
|
||||
}
|
||||
|
||||
return { sucess: true, message: "User Registered", user };
|
||||
return { success: true, message: "User Registered", user };
|
||||
} catch (error) {
|
||||
createLog("error", "auth", "auth", `${error}`);
|
||||
return {
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { User } from "../../../../types/users.js";
|
||||
import { createPassword } from "../../utils/createPassword.js";
|
||||
import { createLog } from "../../../logger/logger.js";
|
||||
import { sendEmail } from "../../../notifications/controller/sendMail.js";
|
||||
import { settings } from "../../../../../database/schema/settings.js";
|
||||
|
||||
export const updateUserADM = async (userData: User) => {
|
||||
/**
|
||||
@@ -13,7 +14,6 @@ export const updateUserADM = async (userData: User) => {
|
||||
* password, username, email.
|
||||
*/
|
||||
|
||||
console.log(userData);
|
||||
createLog(
|
||||
"info",
|
||||
"apiAuthedRoute",
|
||||
@@ -39,6 +39,21 @@ export const updateUserADM = async (userData: User) => {
|
||||
"The user you are looking for has either been deleted or dose not exist.",
|
||||
};
|
||||
}
|
||||
|
||||
const { data: s, error: se } = await tryCatch(db.select().from(settings));
|
||||
|
||||
if (se) {
|
||||
return {
|
||||
success: false,
|
||||
message: `There was an error getting setting data to post to the server.`,
|
||||
data: se,
|
||||
};
|
||||
}
|
||||
|
||||
const set: any = s;
|
||||
const server = set.filter((n: any) => n.name === "server");
|
||||
const port = set.filter((n: any) => n.name === "serverPort");
|
||||
|
||||
const upd_user = user as User;
|
||||
const password: string = userData.password
|
||||
? await createPassword(userData.password!)
|
||||
@@ -72,6 +87,8 @@ export const updateUserADM = async (userData: User) => {
|
||||
context: {
|
||||
password: userData.password!,
|
||||
username: user[0].username!,
|
||||
server: server[0].value,
|
||||
port: port[0].value,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ app.openapi(
|
||||
tags: ["auth:user"],
|
||||
summary: "Updates a users Profile",
|
||||
description: "Currently you can only update your password over the API",
|
||||
method: "post",
|
||||
method: "patch",
|
||||
path: "/profile",
|
||||
middleware: authMiddleware,
|
||||
request: {
|
||||
@@ -38,10 +38,9 @@ app.openapi(
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.object({
|
||||
message: z
|
||||
.string()
|
||||
.optional()
|
||||
.openapi({ example: "User Profile has been updated" }),
|
||||
message: z.string().optional().openapi({
|
||||
example: "User Profile has been updated",
|
||||
}),
|
||||
}),
|
||||
},
|
||||
},
|
||||
@@ -81,13 +80,16 @@ app.openapi(
|
||||
|
||||
if (authHeader?.includes("Basic")) {
|
||||
return c.json(
|
||||
{ message: "You are a Basic user! Please login to get a token" },
|
||||
{
|
||||
message:
|
||||
"You are a Basic user! Please login to get a token",
|
||||
},
|
||||
401
|
||||
);
|
||||
}
|
||||
|
||||
if (!authHeader) {
|
||||
return c.json({ message: "Unauthorized" }, 401);
|
||||
return c.json({ success: false, message: "Unauthorized" }, 401);
|
||||
}
|
||||
|
||||
const token = authHeader?.split("Bearer ")[1] || "";
|
||||
@@ -103,16 +105,24 @@ app.openapi(
|
||||
"auth",
|
||||
"Failed session check, user must be logged out"
|
||||
);
|
||||
return c.json({ message: "Unauthorized" }, 401);
|
||||
return c.json({ success: false, message: "Unauthorized" }, 401);
|
||||
}
|
||||
|
||||
// now pass all the data over to update the user info
|
||||
try {
|
||||
const data = await c?.req.json();
|
||||
await updateProfile(user, data, token);
|
||||
return c.json({ message: "Your profile has been updated" });
|
||||
return c.json({
|
||||
success: true,
|
||||
message: "Your profile has been updated",
|
||||
});
|
||||
} catch (error) {
|
||||
return c.json({ message: "There was an error", error });
|
||||
console.log(error);
|
||||
return c.json({
|
||||
success: false,
|
||||
message: "There was an error",
|
||||
error,
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { lorealForecast } from "./mappings/loralForecast.js";
|
||||
import { standardForecast } from "./mappings/standardForcast.js";
|
||||
|
||||
export const forecastIn = async (data: any, user: any) => {
|
||||
@@ -12,7 +13,7 @@ export const forecastIn = async (data: any, user: any) => {
|
||||
// what type of order are we dealing with?
|
||||
if (data["fileType"] === "standard") {
|
||||
//run the standard forecast in
|
||||
const standard = await standardForecast(data["postPostForecast"], user);
|
||||
const standard = await standardForecast(data["postForecast"], user);
|
||||
success = standard.success ?? false;
|
||||
message = standard.message ?? "Error posting standard forecast";
|
||||
orderData = standard.data;
|
||||
@@ -23,7 +24,11 @@ export const forecastIn = async (data: any, user: any) => {
|
||||
}
|
||||
|
||||
if (data["fileType"] === "loreal") {
|
||||
// orders in
|
||||
//run the standard forecast in
|
||||
const loreal = await lorealForecast(data["postForecast"], user);
|
||||
success = loreal.success ?? false;
|
||||
message = loreal.message ?? "Error posting standard forecast";
|
||||
orderData = loreal.data;
|
||||
}
|
||||
|
||||
if (data["fileType"] === "pg") {
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
import { db } from "../../../../../../../database/dbclient.js";
|
||||
import { settings } from "../../../../../../../database/schema/settings.js";
|
||||
import { tryCatch } from "../../../../../../globalUtils/tryCatch.js";
|
||||
import XLSX from "xlsx";
|
||||
import { excelDateStuff } from "../../../../utils/excelDateStuff.js";
|
||||
import { postForecast } from "../postForecast.js";
|
||||
|
||||
let customerID = 4;
|
||||
export const lorealForecast = async (data: any, user: any) => {
|
||||
/**
|
||||
* Post a standard forecast based on the standard template.
|
||||
*/
|
||||
|
||||
const { data: s, error: e } = await tryCatch(db.select().from(settings));
|
||||
|
||||
if (e) {
|
||||
return {
|
||||
sucess: false,
|
||||
message: `Error getting settings`,
|
||||
data: e,
|
||||
};
|
||||
}
|
||||
|
||||
const plantToken = s.filter((s) => s.name === "plantToken");
|
||||
|
||||
const arrayBuffer = await data.arrayBuffer();
|
||||
const buffer = Buffer.from(arrayBuffer);
|
||||
|
||||
const workbook = XLSX.read(buffer, { type: "buffer" });
|
||||
|
||||
const sheet: any = workbook.Sheets["Alpla HDPE"];
|
||||
const range = XLSX.utils.decode_range(sheet["!ref"]);
|
||||
|
||||
const headers = [];
|
||||
for (let C = range.s.c; C <= range.e.c; ++C) {
|
||||
const cellAddress = XLSX.utils.encode_cell({ r: 0, c: C }); // row 0 = Excel row 1
|
||||
const cell = sheet[cellAddress];
|
||||
headers.push(cell ? cell.v : undefined);
|
||||
}
|
||||
|
||||
const forecastData: any = XLSX.utils.sheet_to_json(sheet, {
|
||||
defval: "",
|
||||
header: headers,
|
||||
range: 2,
|
||||
});
|
||||
|
||||
// Extract the customer code (assuming it's always present)
|
||||
const customerCode = forecastData["NORTH HDPE BOTTLES"];
|
||||
|
||||
// Filter out non-date properties (these are your metadata fields)
|
||||
const metadataFields = [
|
||||
"NORTH HDPE BOTTLES",
|
||||
"BLOCKED",
|
||||
"INVENTORY",
|
||||
"CALL-OFF",
|
||||
"PALLET CONSUMPTION",
|
||||
];
|
||||
|
||||
const foreCastData: any = [];
|
||||
|
||||
// process the forcast
|
||||
forecastData.forEach((item: any, index: any) => {
|
||||
//console.log(`Processing item ${index + 1} of ${forecastData.length}`);
|
||||
|
||||
// Extract the customer code
|
||||
const customerCode = item["NORTH HDPE BOTTLES"];
|
||||
|
||||
// Process each date in the current object
|
||||
for (const [date, qty] of Object.entries(item)) {
|
||||
// Skip metadata fields
|
||||
if (metadataFields.includes(date)) continue;
|
||||
|
||||
if (qty === 0) continue;
|
||||
|
||||
// Create your transformed record
|
||||
const record = {
|
||||
customerArticleNo: customerCode,
|
||||
requirementDate: excelDateStuff(parseInt(date)),
|
||||
quantity: qty,
|
||||
};
|
||||
|
||||
// Do something with this record
|
||||
foreCastData.push(record);
|
||||
}
|
||||
});
|
||||
|
||||
const predefinedObject = {
|
||||
receivingPlantId: plantToken[0].value,
|
||||
documentName: `ForecastFromLST-${new Date(Date.now()).toLocaleString(
|
||||
"en-US"
|
||||
)}`,
|
||||
sender: user.username || "lst-system",
|
||||
customerId: customerID,
|
||||
positions: [],
|
||||
};
|
||||
|
||||
let updatedPredefinedObject = {
|
||||
...predefinedObject,
|
||||
positions: [
|
||||
...predefinedObject.positions,
|
||||
...foreCastData.filter((q: any) => q.customerArticleNo != ""),
|
||||
],
|
||||
};
|
||||
const posting: any = await postForecast(updatedPredefinedObject, user);
|
||||
return {
|
||||
success: posting.success,
|
||||
message: posting.message,
|
||||
data: posting.data,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,11 +1,114 @@
|
||||
import { db } from "../../../../../../../database/dbclient.js";
|
||||
import { settings } from "../../../../../../../database/schema/settings.js";
|
||||
import { tryCatch } from "../../../../../../globalUtils/tryCatch.js";
|
||||
import XLSX from "xlsx";
|
||||
import { excelDateStuff } from "../../../../utils/excelDateStuff.js";
|
||||
import { postForecast } from "../postForecast.js";
|
||||
|
||||
export const standardForecast = async (data: any, user: any) => {
|
||||
/**
|
||||
* Post a standard forecast based on the standard template.
|
||||
*/
|
||||
|
||||
const { data: s, error: e } = await tryCatch(db.select().from(settings));
|
||||
|
||||
if (e) {
|
||||
return {
|
||||
sucess: false,
|
||||
message: `Error getting settings`,
|
||||
data: e,
|
||||
};
|
||||
}
|
||||
|
||||
const plantToken = s.filter((s) => s.name === "plantToken");
|
||||
|
||||
const arrayBuffer = await data.arrayBuffer();
|
||||
const buffer = Buffer.from(arrayBuffer);
|
||||
|
||||
const workbook = XLSX.read(buffer, { type: "buffer" });
|
||||
|
||||
const sheetName = workbook.SheetNames[0];
|
||||
const sheet = workbook.Sheets[sheetName];
|
||||
|
||||
const headers = [
|
||||
"CustomerArticleNumber",
|
||||
"Quantity",
|
||||
"RequirementDate",
|
||||
"CustomerID",
|
||||
];
|
||||
|
||||
const forecastData: any = XLSX.utils.sheet_to_json(sheet, {
|
||||
defval: "",
|
||||
header: headers,
|
||||
range: 1,
|
||||
});
|
||||
|
||||
const groupedByCustomer: any = forecastData.reduce(
|
||||
(acc: any, item: any) => {
|
||||
const id = item.CustomerID;
|
||||
if (!acc[id]) {
|
||||
acc[id] = [];
|
||||
}
|
||||
acc[id].push(item);
|
||||
return acc;
|
||||
},
|
||||
{}
|
||||
);
|
||||
|
||||
const foreCastData: any = [];
|
||||
|
||||
for (const [customerID, forecast] of Object.entries(groupedByCustomer)) {
|
||||
//console.log(`Running for Customer ID: ${customerID}`);
|
||||
const newForecast: any = forecast;
|
||||
|
||||
const predefinedObject = {
|
||||
receivingPlantId: plantToken[0].value,
|
||||
documentName: `ForecastFromLST-${new Date(
|
||||
Date.now()
|
||||
).toLocaleString("en-US")}`,
|
||||
sender: user.username || "lst-system",
|
||||
customerId: customerID,
|
||||
positions: [],
|
||||
};
|
||||
|
||||
// map everything out for each order
|
||||
const nForecast = newForecast.map((o: any) => {
|
||||
// const invoice = i.filter(
|
||||
// (i: any) => i.deliveryAddress === parseInt(customerID)
|
||||
// );
|
||||
// if (!invoice) {
|
||||
// return;
|
||||
// }
|
||||
return {
|
||||
customerArticleNo: o.CustomerArticleNumber,
|
||||
requirementDate: excelDateStuff(parseInt(o.RequirementDate)),
|
||||
quantity: o.Quantity,
|
||||
};
|
||||
});
|
||||
|
||||
// do that fun combining thing
|
||||
let updatedPredefinedObject = {
|
||||
...predefinedObject,
|
||||
positions: [...predefinedObject.positions, ...nForecast],
|
||||
};
|
||||
|
||||
//console.log(updatedPredefinedObject);
|
||||
|
||||
// post the orders to the server
|
||||
const posting: any = await postForecast(updatedPredefinedObject, user);
|
||||
|
||||
foreCastData.push({
|
||||
customer: customerID,
|
||||
//totalOrders: orders?.length(),
|
||||
success: posting.success,
|
||||
message: posting.message,
|
||||
data: posting.data,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Forecast Posted",
|
||||
data: [],
|
||||
data: foreCastData,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
import XLSX from "xlsx";
|
||||
import { tryCatch } from "../../../../../../globalUtils/tryCatch.js";
|
||||
import { db } from "../../../../../../../database/dbclient.js";
|
||||
import { settings } from "../../../../../../../database/schema/settings.js";
|
||||
import { query } from "../../../../../sqlServer/prodSqlServer.js";
|
||||
import { orderState } from "../../../../../sqlServer/querys/dm/orderState.js";
|
||||
import { excelDateStuff } from "../../../../utils/excelDateStuff.js";
|
||||
import { invoiceAddress } from "../../../../../sqlServer/querys/dm/invoiceAddress.js";
|
||||
import { postOrders } from "../postOrders.js";
|
||||
|
||||
export const energizerOrders = async (data: any, user: any) => {
|
||||
/**
|
||||
* Standard orders meaning that we get the standard file exported and fill it out and uplaod to lst.
|
||||
*/
|
||||
|
||||
const { data: s, error: e } = await tryCatch(db.select().from(settings));
|
||||
|
||||
if (e) {
|
||||
return {
|
||||
sucess: false,
|
||||
message: `Error getting settings`,
|
||||
data: e,
|
||||
};
|
||||
}
|
||||
|
||||
// order state
|
||||
const { data: openOrders, error: oe } = await tryCatch(
|
||||
query(orderState, "Gets the next 500 orders that have not been started")
|
||||
);
|
||||
|
||||
if (oe) {
|
||||
return {
|
||||
sucess: false,
|
||||
message: `Error getting article data`,
|
||||
data: oe,
|
||||
};
|
||||
}
|
||||
|
||||
// order state
|
||||
const { data: i, error: ie } = await tryCatch(
|
||||
query(invoiceAddress, "Gets invoices addresses")
|
||||
);
|
||||
|
||||
if (ie) {
|
||||
return {
|
||||
sucess: false,
|
||||
message: `Error getting invoice address data`,
|
||||
data: ie,
|
||||
};
|
||||
}
|
||||
const plantToken = s.filter((s) => s.name === "plantToken");
|
||||
|
||||
const arrayBuffer = await data.arrayBuffer();
|
||||
const buffer = Buffer.from(arrayBuffer);
|
||||
|
||||
const workbook = XLSX.read(buffer, { type: "buffer" });
|
||||
|
||||
const sheetName = workbook.SheetNames[0];
|
||||
const sheet = workbook.Sheets[sheetName];
|
||||
|
||||
// define custom headers
|
||||
const headers = [
|
||||
"ITEM",
|
||||
"PO",
|
||||
"ReleaseNo",
|
||||
"QTY",
|
||||
"DELDATE",
|
||||
"COMMENTS",
|
||||
"What changed",
|
||||
"CUSTOMERID",
|
||||
];
|
||||
const orderData = XLSX.utils.sheet_to_json(sheet, {
|
||||
defval: "",
|
||||
header: headers,
|
||||
range: 1,
|
||||
});
|
||||
|
||||
// the base of the import
|
||||
const predefinedObject = {
|
||||
receivingPlantId: plantToken[0].value,
|
||||
documentName: `OrdersFromLST-${new Date(Date.now()).toLocaleString(
|
||||
"en-US"
|
||||
)}`,
|
||||
sender: user.username || "lst-system",
|
||||
externalRefNo: `OrdersFromLST-${new Date(Date.now()).toLocaleString(
|
||||
"en-US"
|
||||
)}`,
|
||||
orders: [],
|
||||
};
|
||||
|
||||
let newOrders: any = orderData;
|
||||
|
||||
// filter out the orders that have already been started just to reduce the risk of errors.
|
||||
newOrders.filter((oo: any) =>
|
||||
openOrders.some(
|
||||
(o: any) => o.CustomerOrderNumber === oo.CustomerOrderNumber
|
||||
)
|
||||
);
|
||||
|
||||
// filter out the blanks
|
||||
newOrders = newOrders.filter((z: any) => z.ITEM !== "");
|
||||
|
||||
// let postedOrders: any = [];
|
||||
// for (const [customerID, orders] of Object.entries(orderData)) {
|
||||
// // console.log(`Running for Customer ID: ${customerID}`);
|
||||
// const newOrders: any = orderData;
|
||||
|
||||
// // filter out the orders that have already been started just to reduce the risk of errors.
|
||||
// newOrders.filter((oo: any) =>
|
||||
// openOrders.some(
|
||||
// (o: any) => o.CustomerOrderNumber === oo.CustomerOrderNumber
|
||||
// )
|
||||
// );
|
||||
|
||||
// // map everything out for each order
|
||||
const nOrder = newOrders.map((o: any) => {
|
||||
const invoice = i.filter(
|
||||
(i: any) => i.deliveryAddress === parseInt(o.CUSTOMERID)
|
||||
);
|
||||
if (!invoice) {
|
||||
return;
|
||||
}
|
||||
return {
|
||||
customerId: parseInt(o.CUSTOMERID),
|
||||
invoiceAddressId: invoice[0].invoiceAddress, // matched to the default invoice address
|
||||
customerOrderNo: o.PO,
|
||||
orderDate: new Date(Date.now()).toLocaleString("en-US"),
|
||||
positions: [
|
||||
{
|
||||
deliveryAddressId: parseInt(o.CUSTOMERID),
|
||||
customerArticleNo: o.ITEM,
|
||||
quantity: parseInt(o.QTY),
|
||||
deliveryDate: o.DELDATE, //excelDateStuff(o.DELDATE),
|
||||
customerLineItemNo: o.ReleaseNo, // this is how it is currently sent over from abbott
|
||||
customerReleaseNo: o.ReleaseNo, // same as above
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
// // do that fun combining thing
|
||||
const updatedPredefinedObject = {
|
||||
...predefinedObject,
|
||||
orders: [...predefinedObject.orders, ...nOrder],
|
||||
};
|
||||
|
||||
// //console.log(updatedPredefinedObject);
|
||||
|
||||
// // post the orders to the server
|
||||
const posting: any = await postOrders(updatedPredefinedObject, user);
|
||||
|
||||
return {
|
||||
customer: nOrder[0].CUSTOMERID,
|
||||
//totalOrders: orders?.length(),
|
||||
success: posting.success,
|
||||
message: posting.message,
|
||||
data: posting.data,
|
||||
};
|
||||
// }
|
||||
|
||||
// return {
|
||||
// success: true,
|
||||
// message:
|
||||
// "Standard Template was just processed successfully, please check AlplaProd 2.0 to confirm no errors. ",
|
||||
// data: nOrder,
|
||||
// };
|
||||
};
|
||||
@@ -100,7 +100,27 @@ export const standardOrders = async (data: any, user: any) => {
|
||||
let postedOrders: any = [];
|
||||
for (const [customerID, orders] of Object.entries(groupedByCustomer)) {
|
||||
// console.log(`Running for Customer ID: ${customerID}`);
|
||||
const newOrders: any = orders;
|
||||
const filterOrders: any = orders;
|
||||
const newOrders: any = [];
|
||||
//newOrders.filter((oo) => openOrders.some((o) => String(o.CustomerOrderNumber) === String(oo.CustomerOrderNumber)));
|
||||
//console.log(newOrders)
|
||||
filterOrders.forEach((oo: any) => {
|
||||
const isMatch = openOrders.some(
|
||||
(o: any) =>
|
||||
String(o.CustomerOrderNumber).trim() ===
|
||||
String(oo.CustomerOrderNumber).trim()
|
||||
);
|
||||
if (!isMatch) {
|
||||
console.log(`ok to update: ${oo.CustomerOrderNumber}`);
|
||||
|
||||
newOrders.push(oo);
|
||||
} else {
|
||||
console.log(
|
||||
`Not valid order to update: ${oo.CustomerOrderNumber}`
|
||||
);
|
||||
//console.log(oo)
|
||||
}
|
||||
});
|
||||
|
||||
// filter out the orders that have already been started just to reduce the risk of errors.
|
||||
newOrders.filter((oo: any) =>
|
||||
@@ -119,7 +139,7 @@ export const standardOrders = async (data: any, user: any) => {
|
||||
}
|
||||
return {
|
||||
customerId: parseInt(customerID),
|
||||
invoiceAddressId: invoice[0].invoiceAddress, // matched to the default invoice address
|
||||
invoiceAddressId: invoice[0]?.invoiceAddress, // matched to the default invoice address
|
||||
customerOrderNo: o.CustomerOrderNumber,
|
||||
orderDate: new Date(Date.now()).toLocaleString("en-US"),
|
||||
positions: [
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { abbottOrders } from "./mappings/abbottTruckList.js";
|
||||
import { energizerOrders } from "./mappings/energizerOrdersIn.js";
|
||||
import { standardOrders } from "./mappings/standardOrders.js";
|
||||
|
||||
export const ordersIn = async (data: any, user: any) => {
|
||||
@@ -29,6 +30,10 @@ export const ordersIn = async (data: any, user: any) => {
|
||||
|
||||
if (data["fileType"] === "energizer") {
|
||||
// orders in
|
||||
const energizer = await energizerOrders(data["postOrders"], user);
|
||||
success = energizer.success ?? false;
|
||||
message = energizer.message ?? "Error posting Energizer Orders";
|
||||
orderData = energizer.data;
|
||||
}
|
||||
|
||||
if (data["fileType"] === "loreal") {
|
||||
|
||||
@@ -53,10 +53,11 @@ app.openapi(
|
||||
);
|
||||
|
||||
if (error) {
|
||||
console.log(error);
|
||||
return c.json(
|
||||
{
|
||||
success: false,
|
||||
message: "Error posting forecast",
|
||||
message: "Error posting Orders",
|
||||
data: error,
|
||||
},
|
||||
400
|
||||
|
||||
@@ -54,6 +54,7 @@ app.openapi(
|
||||
);
|
||||
|
||||
if (error) {
|
||||
console.log(error);
|
||||
return c.json(
|
||||
{
|
||||
success: false,
|
||||
|
||||
@@ -26,7 +26,13 @@
|
||||
|
||||
For security reasons, we strongly recommend changing your password as soon as possible.<br/><br/>
|
||||
|
||||
You can update it by logging into your account and navigating to the password settings section.<br/><br/>
|
||||
You can update it by logging into your account, clicking your profile at the top right and click password change.<br/><br/>
|
||||
|
||||
|
||||
Or <a href="http://{{server}}:{{port}}/passwordChange"
|
||||
style="display:inline-block; padding:10px 20px; text-decoration:none; border-radius:5px;">
|
||||
Click Here
|
||||
</a> to login and change your password.<br/><br/>
|
||||
|
||||
Best regards,<br/><br/>
|
||||
LST team<br/>
|
||||
|
||||
@@ -47,7 +47,7 @@ export const assignedPrinters = async () => {
|
||||
|
||||
//console.log(lots);
|
||||
|
||||
return;
|
||||
//return;
|
||||
for (let i = 0; i < printers.length; i++) {
|
||||
// is the printer assinged in alplalabel online?
|
||||
const assigned = lots?.filter(
|
||||
|
||||
@@ -1,8 +1,25 @@
|
||||
export const orderState = `
|
||||
SELECT top(500)
|
||||
SELECT top(10000)
|
||||
CustomerOrderNumber
|
||||
, OrderState
|
||||
, r.ReleaseState
|
||||
, h.CreatedByEdi
|
||||
|
||||
--, *
|
||||
FROM [test1_AlplaPROD2.0_Read].[order].[Header] (nolock)
|
||||
where OrderState = 0
|
||||
FROM [test1_AlplaPROD2.0_Read].[order].[Header] (nolock) h
|
||||
|
||||
/* get the line items to link to the headers */
|
||||
left join
|
||||
[test1_AlplaPROD2.0_Read].[order].[LineItem] (nolock) l on
|
||||
l.HeaderId = h.id
|
||||
|
||||
/* get the releases to link to the headers */
|
||||
left join
|
||||
[test1_AlplaPROD2.0_Read].[order].[Release] (nolock) r on
|
||||
r.LineItemId = l.id
|
||||
|
||||
where
|
||||
--h.CreatedByEdi = 1
|
||||
r.ReleaseState > 0
|
||||
--and CustomerOrderNumber in ( '2365862', '2360391')
|
||||
`;
|
||||
|
||||
Reference in New Issue
Block a user