Compare commits

...

84 Commits

Author SHA1 Message Date
8943407f27 feat(finaly): the final push before moving all to the new lst 2025-09-19 22:16:47 -05:00
0bbe411db0 feat(docs): added in link to the main docs and to the material xfer 2025-09-19 07:56:43 -05:00
99b3ad633c fix(materials): changes for consuming peices vs units 2025-09-18 11:00:54 -05:00
c892348d19 refactor(manual print): added a min length of 10 characters 2025-09-18 11:00:18 -05:00
360549aaf4 fix(consume material): changes made to remove the rest of the auth needs 2025-09-18 10:59:55 -05:00
bdc1e72fc1 refactor(frontend): comment required now when doing manual labels 2025-09-17 20:02:14 -05:00
4cae96b1ee refactor(detach): just a log to monitor better 2025-09-11 06:42:31 -05:00
1cde8ab2e6 fix(mm query): more changes to the material query to please more plants 2025-09-11 06:42:02 -05:00
03e8378213 fix(inhouse): changes to no longer error 2025-09-11 06:39:36 -05:00
275c93dc79 refactor(detach silo): changes to now show the error in the console in the browser 2025-09-11 06:39:07 -05:00
fbb8c21d5c feat(loreal forecast): added in an email to be sent when we are missing skus 2025-09-11 06:38:36 -05:00
dce93d3de2 ci(release): bump build number to 652 2025-09-11 06:32:08 -05:00
faf4e9f9ab ci(release): bump build number to 651 2025-09-11 06:30:48 -05:00
a9783a7d35 ci(release): bump build number to 650 2025-09-10 11:15:07 -05:00
e9ca6dbbb2 ci(release): bump build number to 649 2025-09-10 11:13:59 -05:00
e996f99400 ci(release): bump build number to 648 2025-09-10 06:59:19 -05:00
3b939ff2d3 ci(release): bump build number to 647 2025-09-09 21:21:08 -05:00
a7ff88025e chore(release): 2.27.0 2025-09-09 21:20:39 -05:00
00899a5b77 fix(materials): more fixes to try and please all plants to use this version and not call me 2025-09-09 21:20:23 -05:00
99ecf52218 fix(label query): fixes to only pull in active layouts 2025-09-09 21:19:39 -05:00
a6920d7cd8 ci(release): bump build number to 645 2025-09-09 17:52:15 -05:00
788efdf4b3 ci(release): bump build number to 644 2025-09-09 17:40:05 -05:00
a2a17beeeb ci(release): bump build number to 643 2025-09-09 17:28:29 -05:00
6c793c66a4 ci(release): bump build number to 642 2025-09-09 15:57:41 -05:00
6918a5a7d4 ci(release): bump build number to 641 2025-09-09 09:12:18 -05:00
ddd9b0e372 ci(release): bump build number to 640 2025-09-09 07:48:24 -05:00
41d921756b ci(release): bump build number to 638 2025-09-08 19:16:44 -05:00
d86ca7d3bf ci(release): bump build number to 636 2025-09-08 13:30:05 -05:00
932a72ba88 fix(db): changes to the user so it deletes correctly 2025-09-07 15:38:27 -05:00
b9c6d0ba57 ci(release): bump build number to 622 2025-09-06 16:33:56 -05:00
592e4c8cd7 ci(release): bump build number to 621 2025-09-06 16:02:36 -05:00
b772666905 ci(release): bump build number to 620 2025-09-06 14:56:05 -05:00
a6edcb71bf ci(release): bump build number to 619 2025-09-06 14:51:26 -05:00
76d929abea ci(release): bump build number to 618 2025-09-06 14:43:44 -05:00
da17defe82 ci(release): bump build number to 617 2025-09-06 14:37:44 -05:00
669f5ca33f ci(release): bump build number to 616 2025-09-06 14:31:51 -05:00
b649dca4c9 ci(release): bump build number to 615 2025-09-06 14:28:44 -05:00
04b8d041f9 ci(release): bump build number to 611 2025-09-06 09:24:09 -05:00
71bc7c29bc ci(release): bump build number to 610 2025-09-06 09:22:13 -05:00
79f1f8f91b fix(article check): corrected the query to not have a specfic plant in it 2025-09-06 09:04:00 -05:00
b677bc1498 refactor(rfid): changes to show all tags vs only 3 if there are more 2025-09-06 09:03:35 -05:00
a53915ad8c fix(material check): split manual material out of the mm to properly catch it 2025-09-06 09:03:11 -05:00
b3ce767b32 fix(bookin): corrections to only show the message on error vs the json 2025-09-06 09:02:42 -05:00
6caa5984e7 fix(eomservice): changes to stop a crash incase the sql returned nothing due to start up 2025-09-06 09:02:09 -05:00
415d2e4a1d fix(register): changes to not give everyone system admin 2025-09-06 09:01:42 -05:00
271cdbdbfa refactor(cosume): changes to allow non logged in users to use this function 2025-09-06 09:01:12 -05:00
796a8dccd2 refactor(silo card): changes to allow viewers to see and able to attach and detach 2025-09-06 09:00:46 -05:00
e03e92c18d ci(build): changes to build then copy to new version being rewritten 2025-09-06 09:00:11 -05:00
dd2e5d04ae ci(release): bump build number to 609 2025-09-06 08:54:39 -05:00
708b57b926 ci(release): bump build number to 608 2025-09-06 08:50:28 -05:00
0444da8bbc ci(release): bump build number to 607 2025-09-06 08:34:18 -05:00
6d49fae16d ci(release): bump build number to 602 2025-09-05 09:55:52 -05:00
be8a44f2dc ci(release): bump build number to 601 2025-09-05 09:52:25 -05:00
a3994a1f69 ci(release): bump build number to 600 2025-09-05 09:45:02 -05:00
00eaf62d4c ci(release): bump build number to 600 2025-09-05 09:44:58 -05:00
6851777faf ci(release): bump build number to 599 2025-09-05 09:43:27 -05:00
f9e97fc224 ci(release): bump build number to 598 2025-09-05 09:43:25 -05:00
4e3c5e4191 ci(release): bump build number to 595 2025-09-05 08:28:25 -05:00
172fd1d5c2 ci(release): bump build number to 594 2025-09-05 08:28:22 -05:00
1094de2ebd ci(release): bump build number to 593 2025-09-05 08:23:59 -05:00
7462b3d90b ci(release): bump build number to 592 2025-09-05 08:23:56 -05:00
2045c13ef2 ci(release): bump build number to 591 2025-09-05 08:22:41 -05:00
5fa9e83d5b ci(release): bump build number to 590 2025-09-05 08:22:39 -05:00
f48c944bd0 ci(release): bump build number to 589 2025-09-05 07:50:36 -05:00
dddd1d422e ci(release): bump build number to 588 2025-09-04 13:12:21 -05:00
8133443ec9 ci(release): bump build number to 587 2025-09-03 10:56:13 -05:00
28c7d30c1a ci(release): bump build number to 586 2025-09-03 10:54:37 -05:00
57966ac9de refactor(mm query): changes to the query to see pkg and materials properly and not duplicates 2025-09-01 11:08:47 -05:00
6910550de7 fix(main material check): corrections to properly ignore pkg during color checks 2025-09-01 11:08:16 -05:00
1f8b8a7248 fix(bookin): corrected the bookin in error response
this could still print a label if the system detects the material properly but some other issue with
alplaprod happened
2025-09-01 11:05:36 -05:00
cfed981928 refactor(sql): articles added in UOM 2025-09-01 11:02:32 -05:00
0efe74d4b1 ci(release): bump build number to 585 2025-09-01 07:31:05 -05:00
c35db2e209 ci(release): bump build number to 584 2025-08-29 19:01:12 -05:00
e1cdeb740b ci(release): bump build number to 583 2025-08-29 18:57:25 -05:00
3c9e75dc3c ci(release): bump build number to 582 2025-08-29 18:32:34 -05:00
64b5b0d248 ci(release): bump build number to 581 2025-08-29 11:37:47 -05:00
668eae9719 ci(release): bump build number to 580 2025-08-29 11:31:22 -05:00
7cc3778506 feat(eom): lastSales, lastPurch added to be pulled with new template 2025-08-29 11:26:26 -05:00
af47c1582e ci(release): bump build number to 579 2025-08-29 08:59:50 -05:00
081572c421 ci(release): bump build number to 578 2025-08-28 11:09:44 -05:00
c6f6ef6262 fix(frontend): typos 2025-08-28 10:56:49 -05:00
34849e15d1 ci(release): bump build number to 577 2025-08-28 10:19:10 -05:00
9bd66942f5 chore(release): 2.26.0 2025-08-28 10:18:13 -05:00
795da35141 ci(release): bump build number to 576 2025-08-28 10:17:15 -05:00
54 changed files with 3664 additions and 291 deletions

1
.gitignore vendored
View File

@@ -157,3 +157,4 @@ backend-0.1.3.zip
BulkForecastTemplate
BulkOrdersTemplate
check.json
server/services/ocp/controller/materials/materialcheck.bak

8
.includes Normal file
View File

@@ -0,0 +1,8 @@
database
dist
frontend/dist
CHANGELOG.md
drizzle.config.ts
package.json
package-lock.json
README.md

View File

@@ -1,5 +1,73 @@
# All CHanges to LST can be found below.
## [2.27.0](https://git.tuffraid.net/cowch/lstV2/compare/v2.26.0...v2.27.0) (2025-09-10)
### 🌟 Enhancements
* **eom:** lastSales, lastPurch added to be pulled with new template ([7cc3778](https://git.tuffraid.net/cowch/lstV2/commits/7cc3778506fc92392ca8431aee0edb203861e10d))
### 🛠️ Code Refactor
* **cosume:** changes to allow non logged in users to use this function ([271cdbd](https://git.tuffraid.net/cowch/lstV2/commits/271cdbdbfa2478ecf56e9b01a4474508acacda2e))
* **mm query:** changes to the query to see pkg and materials properly and not duplicates ([57966ac](https://git.tuffraid.net/cowch/lstV2/commits/57966ac9de72543014451b7ccd75539296ccaa51))
* **rfid:** changes to show all tags vs only 3 if there are more ([b677bc1](https://git.tuffraid.net/cowch/lstV2/commits/b677bc14981faff30c91f6ffe4602319dd3c6016))
* **silo card:** changes to allow viewers to see and able to attach and detach ([796a8dc](https://git.tuffraid.net/cowch/lstV2/commits/796a8dccd2807890abdff7c8dacf8b2246eb265e))
* **sql:** articles added in UOM ([cfed981](https://git.tuffraid.net/cowch/lstV2/commits/cfed981928a56389e09ef428c43ceabc1caec28e))
### 🐛 Bug fixes
* **article check:** corrected the query to not have a specfic plant in it ([79f1f8f](https://git.tuffraid.net/cowch/lstV2/commits/79f1f8f91ba33533de7f4a7cc91503cfd8dd4ce5))
* **bookin:** corrected the bookin in error response ([1f8b8a7](https://git.tuffraid.net/cowch/lstV2/commits/1f8b8a7248c11c7e264c8c5ae7c042c5a0878c46))
* **bookin:** corrections to only show the message on error vs the json ([b3ce767](https://git.tuffraid.net/cowch/lstV2/commits/b3ce767b323c990c0ccf35ad6c2c67136a27272e))
* **db:** changes to the user so it deletes correctly ([932a72b](https://git.tuffraid.net/cowch/lstV2/commits/932a72ba884673471f0056e721cc3f2c8e34b4f3))
* **eomservice:** changes to stop a crash incase the sql returned nothing due to start up ([6caa598](https://git.tuffraid.net/cowch/lstV2/commits/6caa5984e7a3e7b48b119c176835663ffec71151))
* **frontend:** typos ([c6f6ef6](https://git.tuffraid.net/cowch/lstV2/commits/c6f6ef626295f452cdf26f6776b74cfb3b1a10f5))
* **label query:** fixes to only pull in active layouts ([99ecf52](https://git.tuffraid.net/cowch/lstV2/commits/99ecf52218556e048ba9262e74f9b3d020dea31d))
* **main material check:** corrections to properly ignore pkg during color checks ([6910550](https://git.tuffraid.net/cowch/lstV2/commits/6910550de769dce04b1045f96ab19cf7b8d1ef8c))
* **material check:** split manual material out of the mm to properly catch it ([a53915a](https://git.tuffraid.net/cowch/lstV2/commits/a53915ad8cbec5bd8d6ba4643c460ad0162249e2))
* **materials:** more fixes to try and please all plants to use this version and not call me ([00899a5](https://git.tuffraid.net/cowch/lstV2/commits/00899a5b778eab792b350a0b47589de1524d91c8))
* **register:** changes to not give everyone system admin ([415d2e4](https://git.tuffraid.net/cowch/lstV2/commits/415d2e4a1d851cc46ac64ffc814a280a02293bbc))
## [2.26.0](https://git.tuffraid.net/cowch/lstV2/compare/v2.25.0...v2.26.0) (2025-08-28)
### 🛠️ Code Refactor
* **labeling:** moved bookin fails inside bookin as it could be off ([df42319](https://git.tuffraid.net/cowch/lstV2/commits/df423192bfc5e2389872147e92b7d22e648a2927))
* **labeling:** removed the wrong import ([788d636](https://git.tuffraid.net/cowch/lstV2/commits/788d6367a380a81722a76bd6adbe18831d88eeb5))
* **materials:** changes for permissions on material consume ([3148aa7](https://git.tuffraid.net/cowch/lstV2/commits/3148aa79d73823499824cc0601fcabec97bb4f9d))
* **materials:** changes to allow exact and eom transfers ([0a6ddea](https://git.tuffraid.net/cowch/lstV2/commits/0a6ddea8c0d2773aba00266df7e2839879d10cb1))
* **notifcations:** changed hour to min in ti intergrations ([73d38ba](https://git.tuffraid.net/cowch/lstV2/commits/73d38ba3fe7ab4d5ca3a4a1e1c99fdd7bf5e92dc))
* **tms intergration:** corrected how we added gl coding ([37f82a9](https://git.tuffraid.net/cowch/lstV2/commits/37f82a9710cf20e6d0d056893c9da43c70b9e619))
### 🌟 Enhancements
* **materials:** added in a bigger window on eom transfer lots ([53ed2c4](https://git.tuffraid.net/cowch/lstV2/commits/53ed2c4e6a0d3fafafbcb655b5d06cff6324363d))
* **ocp:** zechetti 1 added in ([27586e9](https://git.tuffraid.net/cowch/lstV2/commits/27586e923a106f2b8dd804e9c8292edd5d009cf0))
* **rfid:** new check to remove tags that have been at a line longer than 6 hours ([0ba338d](https://git.tuffraid.net/cowch/lstV2/commits/0ba338d48037f7def74196ca3f41de5807e2cb31))
* **tms:** a clean up function was added to remove releases added as blockers older than 45d ([662a951](https://git.tuffraid.net/cowch/lstV2/commits/662a951b9871d5dfc21f01a76ba23be77b475757))
### 📝 Testing Code
* **forklifts:** forklift starting process ([8c296c5](https://git.tuffraid.net/cowch/lstV2/commits/8c296c5b783f42f85c30a955d6e9d540c50dcfbe))
### 🐛 Bug fixes
* **bookin:** corrected the error received from the book in fail ([369d160](https://git.tuffraid.net/cowch/lstV2/commits/369d16018c8be9fdb936afbc3749b3f9fcea58c8))
* **dm:** corrected the remark section so its properly sent over ([68901a8](https://git.tuffraid.net/cowch/lstV2/commits/68901a857ae5161f024da9cdefc0a981a4907205))
* **eom stats:** corrections to the eom inv stuff to be proper tiems ([468f933](https://git.tuffraid.net/cowch/lstV2/commits/468f933168cc40be0c1b159c31948a2c97600390))
* **fake edi:** removed console log ([24a97af](https://git.tuffraid.net/cowch/lstV2/commits/24a97afe064d5c44872e24e6e3299ed5f2977a78))
* **material check:** alt mm causing issues and utilizing an 80% to just be ok ([f4f3de4](https://git.tuffraid.net/cowch/lstV2/commits/f4f3de49cae277ffa158116d1802495b27fa8e75))
* **ocp:** zechetti type correction to include the printer name ([4486fe2](https://git.tuffraid.net/cowch/lstV2/commits/4486fe24362b4811d7cff0467c7f2f85e0c9e3c4))
* **produser:** changes to include DM ([8d6ead3](https://git.tuffraid.net/cowch/lstV2/commits/8d6ead3aa11aed95ffa3537fbe72cfa9bbceb380))
* **transferlots:** missed adding this ([846ac47](https://git.tuffraid.net/cowch/lstV2/commits/846ac479b1bf211a7891ae362525ea14580ff0cc))
## [2.25.0](https://git.tuffraid.net/cowch/lstV2/compare/v2.24.1...v2.25.0) (2025-08-21)

View File

@@ -1,3 +1,7 @@
# THIS VERSION IS NO LONGER BEING UPDATED PLEASE GO TO THE NEW REPO LINK BELOW
[NEW LST REPO](https://git.tuffraid.net/cowch/lst)
# lstV2
Logistics Support Tool V2

View File

@@ -0,0 +1,3 @@
ALTER TABLE "userRoles" DROP CONSTRAINT "userRoles_user_id_users_user_id_fk";
--> statement-breakpoint
ALTER TABLE "userRoles" ADD CONSTRAINT "userRoles_user_id_users_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("user_id") ON DELETE cascade ON UPDATE no action;

File diff suppressed because it is too large Load Diff

View File

@@ -505,6 +505,13 @@
"when": 1754768521841,
"tag": "0071_fantastic_old_lace",
"breakpoints": true
},
{
"idx": 72,
"version": "7",
"when": 1757167736042,
"tag": "0072_round_black_knight",
"breakpoints": true
}
]
}

View File

@@ -27,7 +27,7 @@ export const userRoles = pgTable(
{
user_id: uuid("user_id")
.notNull()
.references(() => users.user_id),
.references(() => users.user_id, { onDelete: "cascade" }),
role_id: uuid("role_id")
.notNull()
.references(() => roles.role_id),

View File

@@ -6,7 +6,10 @@ import Barcode from "react-barcode";
import { BarcodePDFExport } from "./BarcodeExport";
import { BulkBarcodePDFExport } from "./BulkExport";
const commoncmd = [{ name: "Relocate", commandId: 33 }];
const commoncmd = [
{ name: "Relocate", commandId: 33 },
//-{ name: "Stock in", commandId: 22 },
];
export default function CommonCommands() {
const [checked, setChecked] = useState([]);

View File

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

View File

@@ -14,16 +14,19 @@ import {
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { useSettingStore } from "@/lib/store/useSettings";
export default function TransferToNextLot() {
const [gaylordFilled, setGaylordFilled] = useState([0]);
const [actualAmount, setActualAmount] = useState(0);
const [tab, setTab] = useState("esitmate");
const [typeSwitch, setTypeSwitch] = useState(false);
const { settings } = useSettingStore();
const server = settings.filter((n: any) => n.name === "dbServer");
const form = useAppForm({
defaultValues: {
runnungNumber: "",
runningNumber: "",
lotNumber: "",
originalAmount: "",
amount: "",
@@ -33,7 +36,7 @@ export default function TransferToNextLot() {
//toast.success("603468: qty: 361, was transfered to lot:24897");
try {
const res = await axios.post("/api/ocp/materiallottransfer", {
runnungNumber: Number(value.runnungNumber),
runningNumber: Number(value.runningNumber),
lotNumber: Number(value.lotNumber),
originalAmount: Number(value.originalAmount),
level: Number(
@@ -111,7 +114,7 @@ export default function TransferToNextLot() {
}
>
<p className="text-center">
Almost full
Almost full - 95%
</p>
</button>
<button
@@ -129,7 +132,7 @@ export default function TransferToNextLot() {
}
>
<p className="text-center">
About 75% full
About full - 75%
</p>
</button>
<button
@@ -145,7 +148,7 @@ export default function TransferToNextLot() {
}
>
<p className="text-center">
Half full
Half full - 50%
</p>
</button>
<button
@@ -163,7 +166,7 @@ export default function TransferToNextLot() {
}
>
<p className="text-center">
Almost empty
Almost empty - 25%
</p>
</button>
</div>
@@ -215,10 +218,10 @@ export default function TransferToNextLot() {
>
<div className="mt-3 p-2">
<form.AppField
name="runnungNumber"
name="runningNumber"
children={(field) => (
<field.InputField
label="Runnung Number"
label="Running Number"
inputType="number"
required={true}
/>
@@ -398,6 +401,19 @@ export default function TransferToNextLot() {
process, this process will just get
the gaylord to the next lot.
</p>
<br />
{settings.length > 0 && (
<p>
For more in depth instructions
please{" "}
<a
href={`https://${server[0].value}.alpla.net/lst/d/docs/ocp/ocp#tranfer-partial-estimated-quantity-to-the-next-lot`}
target="_blank"
>
<em>CLICK HERE</em>
</a>
</p>
)}
</div>
) : (
<div>
@@ -437,6 +453,19 @@ export default function TransferToNextLot() {
process, this process will just get
the gaylord to the next lot.
</p>
<br />
{settings.length > 0 && (
<p>
For more in depth instructions
please{" "}
<a
href={`https://${server[0].value}.alpla.net/lst/d/docs/ocp/ocp#tranfer-partial-estimated-quantity-to-the-next-lot`}
target="_blank"
>
<em>CLICK HERE</em>
</a>
</p>
)}
</div>
)}
</LstCard>

View File

@@ -48,6 +48,7 @@ export function DetachSilo(props: any) {
);
if (res.status === 200) {
console.log(res.data.data);
toast.success(res.data.message);
refetch();

View File

@@ -21,13 +21,28 @@ import { toast } from "sonner";
import ChartData from "./ChartData";
import { AttachSilo } from "./AttachSilo";
import { DetachSilo } from "./DetachSilo";
import { useSessionStore } from "@/lib/store/sessionStore";
import { useModuleStore } from "@/lib/store/useModuleStore";
import { useGetUserRoles } from "@/lib/store/useGetRoles";
export default function SiloCard(data: any) {
const token = localStorage.getItem("auth_token");
const [submitting, setSubmitting] = useState(false);
const { refetch } = useQuery(getStockSilo());
const { user } = useSessionStore();
const { userRoles } = useGetUserRoles();
const { modules } = useModuleStore();
const silo = data.silo;
// roles that can do the silo adjustments
const roles = ["systemAdmin", "technician", "admin", "manager"];
const module = modules.filter((n) => n.name === "logistics");
const accessRoles = userRoles.filter(
(n) => n.module_id === module[0]?.module_id
) as any;
const form = useForm({
defaultValues: {
newLevel: "",
@@ -46,7 +61,7 @@ export default function SiloCard(data: any) {
dataToSubmit,
{ headers: { Authorization: `Bearer ${token}` } }
);
console.log(res.data);
//console.log(res.data);
if (res.data.success) {
toast.success(res.data.message);
@@ -70,6 +85,8 @@ export default function SiloCard(data: any) {
}
},
});
console.log(accessRoles);
return (
<LstCard>
<div className="flex flex-row">
@@ -109,82 +126,98 @@ export default function SiloCard(data: any) {
</ul>
</div>
) : (
<form
onSubmit={(e) => {
e.preventDefault();
e.stopPropagation();
}}
>
<form.Field
name="newLevel"
validators={{
// We can choose between form-wide and field-specific validators
onChange: ({ value }) =>
value.length > 1
? undefined
: "You must enter a value greate than 1",
}}
children={(field) => {
return (
<div className="m-2 min-w-48 max-w-96 p-2">
<div className="flex flex-row">
<Label htmlFor="newLevel">
New level
</Label>
<div>
<Disclaimer />
</div>
</div>
<div className="flex flex-row">
<Input
name={field.name}
value={
field.state.value
}
onBlur={
field.handleBlur
}
type="decimal"
onChange={(e) =>
field.handleChange(
e.target.value
)
}
/>
<Button
className="ml-1"
variant="outline"
type="submit"
onClick={
form.handleSubmit
}
disabled={submitting}
>
{submitting ? (
<span className="w-24">
Submitting...
</span>
) : (
<span className="w-24">
Submit
</span>
)}
</Button>
</div>
<>
{user &&
roles.includes(accessRoles[0]?.role) && (
<form
onSubmit={(e) => {
e.preventDefault();
e.stopPropagation();
}}
>
<form.Field
name="newLevel"
validators={{
// We can choose between form-wide and field-specific validators
onChange: ({ value }) =>
value.length > 1
? undefined
: "You must enter a value greate than 1",
}}
children={(field) => {
return (
<div className="m-2 min-w-48 max-w-96 p-2">
<div className="flex flex-row">
<Label htmlFor="newLevel">
New level
</Label>
<div>
<Disclaimer />
</div>
</div>
<div className="flex flex-row">
<Input
name={
field.name
}
value={
field
.state
.value
}
onBlur={
field.handleBlur
}
type="decimal"
onChange={(
e
) =>
field.handleChange(
e
.target
.value
)
}
/>
<Button
className="ml-1"
variant="outline"
type="submit"
onClick={
form.handleSubmit
}
disabled={
submitting
}
>
{submitting ? (
<span className="w-24">
Submitting...
</span>
) : (
<span className="w-24">
Submit
</span>
)}
</Button>
</div>
{field.state.meta.errors
.length ? (
<em>
{field.state.meta.errors.join(
","
)}
</em>
) : null}
</div>
);
}}
/>
</form>
{field.state.meta
.errors
.length ? (
<em>
{field.state.meta.errors.join(
","
)}
</em>
) : null}
</div>
);
}}
/>
</form>
)}
</>
)}
</div>
</LstCard>

View File

@@ -243,7 +243,8 @@ export default function ManualPrintForm() {
<Textarea
//label="Comments"
placeholder="add more info as needed."
{...register("additionalComments")}
{...(register("additionalComments"),
{ required: true, minLength: 10 })}
/>
</div>

View File

@@ -32,7 +32,10 @@ function RouteComponent() {
<TransferToNextLot />
</>
) : (
<TransferToNextLot />
<>
<ConsumeMaterial />
<TransferToNextLot />
</>
)}
</div>
);

View File

@@ -28,6 +28,7 @@ import { useLogout } from "@/hooks/useLogout";
import ExportInventoryData from "@/components/logistics/warehouse/ExportInventoryData";
import { AddCards } from "@/components/dashboard/AddCards";
import DMButtons from "@/components/logistics/dm/DMButtons";
import { useSettingStore } from "@/lib/store/useSettings";
//import { AddCards } from "@/components/dashboard/AddCards";
// same as the layout
@@ -38,6 +39,9 @@ export const Route = createRootRoute({
const { user } = useSessionStore();
const logout = useLogout();
const location = useLocation();
const { settings } = useSettingStore();
const server = settings.filter((n: any) => n.name === "dbServer");
return (
<div className="overflow-hidden">
@@ -61,6 +65,17 @@ export const Route = createRootRoute({
<div className="m-1">
<ModeToggle />
</div>
<div className="mr-1 ml-1">
{settings.length > 0 && (
<a
href={`https://${server[0].value}.alpla.net/lst/d`}
target="_blank"
>
LST - Docs
</a>
)}
</div>
{session ? (
<div className="m-1">
<DropdownMenu>

View File

@@ -33,13 +33,12 @@ function RouteComponent() {
<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>
The username, email, and password are
only for LST you <em>DO NOT</em>Need to
use Windows username if you do not wish
to.
</span>
. These credentials are used solely for
authentication purposes.
</li>
{/* <li>
<span className="font-bold">

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "lstv2",
"version": "2.25.0",
"version": "2.27.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "lstv2",
"version": "2.25.0",
"version": "2.27.0",
"dependencies": {
"@dotenvx/dotenvx": "^1.45.1",
"@hono/node-server": "^1.14.4",

View File

@@ -1,6 +1,6 @@
{
"name": "lstv2",
"version": "2.25.0",
"version": "2.27.0",
"type": "module",
"scripts": {
"dev": "concurrently -n \"server,frontend\" -c \"#007755,#2f6da3\" \"npm run dev:server\" \"cd frontend && npm run dev\"",
@@ -21,8 +21,8 @@
"db:dev": "npm run build && npm run db:generate && npm run db:migrate",
"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\"",
"newBuild": "npm run build:server && npm run build:frontend && npm run zipServer && npm run copyToNew",
"copyToNew": "powershell -ExecutionPolicy Bypass -File server/scripts/copyToLst.ps1 -dir \"C:\\Users\\matthes01\\Documents\\lstv2\"",
"removeOld": "rimraf dist && rimraf frontend/dist",
"prodBuild": "npm run v1Build && npm run build && npm run zipServer && npm run dev",
"commit": "cz",
@@ -36,7 +36,7 @@
}
},
"admConfig": {
"build": 575,
"build": 661,
"oldBuild": "backend-0.1.3.zip"
},
"devDependencies": {

View File

@@ -0,0 +1,61 @@
param(
[string]$IncludesFile = ".includes",
[string]$Destination = "C:\Users\matthes01\Documents\lst\lstV2",
[string]$BaseDir = "C:\Users\matthes01\Documents\lst"
)
# .\copy-includes.ps1 will run with defaults
# .\copy-includes.ps1 -IncludesFile ".\mylist.txt" -Destination "D:\build\lstV2" will override defaults
if (-Not (Test-Path $IncludesFile)) {
Write-Error "Includes file not found: $IncludesFile"
exit 1
}
# Ensure destination exists
if (!(Test-Path -Path $Destination)) {
New-Item -ItemType Directory -Path $Destination | Out-Null
Write-Host "Folder created: $Destination"
}
# Empty the destination folder
Get-ChildItem -Path $Destination -Recurse -Force | Remove-Item -Recurse -Force
# If BaseDir wasnt explicitly passed in, use IncludesFile directory
if (-not $PSBoundParameters.ContainsKey('BaseDir')) {
$BaseDir = Split-Path -Parent (Resolve-Path $IncludesFile)
}
# Read includes list (ignore blank lines & comments)
$items = Get-Content $IncludesFile |
ForEach-Object { $_.Trim() } |
Where-Object { $_ -and -not $_.StartsWith("#") }
foreach ($item in $items) {
if ([System.IO.Path]::IsPathRooted($item)) {
# Absolute path (rare case)
$sourcePath = $item
$relative = Split-Path $item -Leaf # just take folder/file name
} else {
# Relative to BaseDir
$sourcePath = Join-Path $BaseDir $item
$relative = $item # keep full relative path e.g. "frontend\dist"
}
if (-Not (Test-Path $sourcePath)) {
Write-Warning "Skipping missing path: $sourcePath"
continue
}
# Destination path should preserve the relative structure
$targetPath = Join-Path $Destination $relative
# Ensure the parent folder exists
$targetDir = Split-Path $targetPath -Parent
if (-not (Test-Path $targetDir)) {
New-Item -ItemType Directory -Path $targetDir -Force | Out-Null
}
Write-Host "Copying $sourcePath -> $targetPath" -ForegroundColor Cyan
Copy-Item -Path $sourcePath -Destination $targetPath -Recurse -Force
}

View File

@@ -37,7 +37,7 @@ export const registerUser = async (
.values({ username, email, password })
.returning({ user: users.username, email: users.email });
if (usercount.length <= 1) {
if (usercount.length === 0) {
createLog(
"info",
"auth",

View File

@@ -0,0 +1,63 @@
import { and, between, inArray, sql } from "drizzle-orm";
import { db } from "../../../../database/dbclient.js";
import { invHistoricalData } from "../../../../database/schema/historicalINV.js";
import { tryCatch } from "../../../globalUtils/tryCatch.js";
import { createLog } from "../../logger/logger.js";
// type ArticleData = {
// id: string
// }
export const psiGetInventory = async (
avs: string,
startDate: string,
endDate: string
) => {
let articles: any = [];
if (!avs) {
return {
success: false,
message: `Missing av's please send at least one over`,
data: [],
};
}
const ids = avs.split(",").map((id) => id.trim());
const { data, error } = (await tryCatch(
db
.select()
.from(invHistoricalData)
.where(
and(
inArray(invHistoricalData.article, ids),
between(invHistoricalData.histDate, startDate, endDate)
)
)
//.limit(100)
)) as any;
if (error) {
createLog(
"error",
"datamart",
"datamart",
`There was an error getting the planning info: ${JSON.stringify(
error
)}`
);
return {
success: false,
messsage: `There was an error getting the planning info`,
data: error,
};
}
articles = data;
console.log(articles.length);
return {
success: true,
message: "PSI planning Data",
data: articles,
};
};

View File

@@ -0,0 +1,63 @@
import { tryCatch } from "../../../globalUtils/tryCatch.js";
import { createLog } from "../../logger/logger.js";
import { query } from "../../sqlServer/prodSqlServer.js";
import { planningNumbersByAVDate } from "../../sqlServer/querys/psiReport/planningNumbersByAv.js";
// type ArticleData = {
// id: string
// }
export const psiGetPlanningData = async (
avs: string,
startDate: string,
endDate: string
) => {
let articles: any = [];
if (!avs) {
return {
success: false,
message: `Missing av's please send at least one over`,
data: [],
};
}
const { data, error } = (await tryCatch(
query(
planningNumbersByAVDate
.replace("[articles]", avs)
.replace("[startDate]", startDate)
.replace("[endDate]", endDate),
"PSI planning info"
)
)) as any;
if (error) {
createLog(
"error",
"datamart",
"datamart",
`There was an error getting the planning info: ${JSON.stringify(
error
)}`
);
return {
success: false,
messsage: `There was an error getting the planning info`,
data: error,
};
}
articles = data.data;
return {
success: true,
message: "PSI planning Data",
data: articles.map((n: any) => {
if (n.PalDay) {
return { ...n, PalDay: n.PalDay.toFixed(2) };
}
return n;
}),
};
};

View File

@@ -0,0 +1,63 @@
import { tryCatch } from "../../../globalUtils/tryCatch.js";
import { createLog } from "../../logger/logger.js";
import { query } from "../../sqlServer/prodSqlServer.js";
import { productionNumbers } from "../../sqlServer/querys/psiReport/prodcuctionNumbers.js";
// type ArticleData = {
// id: string
// }
export const psiGetProductionData = async (
avs: string,
startDate: string,
endDate: string
) => {
let articles: any = [];
if (!avs) {
return {
success: false,
message: `Missing av's please send at least one over`,
data: [],
};
}
const { data, error } = (await tryCatch(
query(
productionNumbers
.replace("[articles]", avs)
.replace("[startDate]", startDate)
.replace("[endDate]", endDate),
"PSI production info"
)
)) as any;
if (error) {
createLog(
"error",
"datamart",
"datamart",
`There was an error getting the planning info: ${JSON.stringify(
error
)}`
);
return {
success: false,
messsage: `There was an error getting the planning info`,
data: error,
};
}
articles = data.data;
return {
success: true,
message: "PSI planning Data",
data: articles.map((n: any) => {
if (n.PalDay) {
return { ...n, PalDay: n.PalDay.toFixed(2) };
}
return n;
}),
};
};

View File

@@ -10,6 +10,9 @@ import addressCorrections from "./route/getCityStateData.js";
import fifoIndex from "./route/getFifoIndex.js";
import financeAudit from "./route/getFinanceAudit.js";
import psiArticleData from "./route/getPsiArticleData.js";
import psiPlanningData from "./route/getPsiPlanningData.js";
import psiProductionData from "./route/getPsiProductionData.js";
import psiInventory from "./route/getPsiinventory.js";
const app = new OpenAPIHono();
@@ -25,6 +28,9 @@ const routes = [
fifoIndex,
financeAudit,
psiArticleData,
psiPlanningData,
psiProductionData,
psiInventory,
] as const;
const appRoutes = routes.forEach((route) => {

View File

@@ -0,0 +1,64 @@
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { responses } from "../../../globalUtils/routeDefs/responses.js";
import { tryCatch } from "../../../globalUtils/tryCatch.js";
import { apiHit } from "../../../globalUtils/apiHits.js";
import { psiGetPlanningData } from "../controller/psiGetPlanningData.js";
const app = new OpenAPIHono({ strict: false });
const Body = z.object({
includeRunnningNumbers: z.string().openapi({ example: "x" }),
});
app.openapi(
createRoute({
tags: ["dataMart"],
summary: "Returns the psiarticleData.",
method: "get",
path: "/psiplanningdata",
request: {
body: {
content: {
"application/json": { schema: Body },
},
},
},
responses: responses(),
}),
async (c) => {
const q: any = c.req.queries();
// make sure we have a vaid user being accessed thats really logged in
apiHit(c, { endpoint: "/psiplanningdata" });
//console.log(articles["avs"][0]);
const { data, error } = await tryCatch(
psiGetPlanningData(
q["avs"] ? q["avs"][0] : null,
q["startDate"] ? q["startDate"][0] : null,
q["endDate"] ? q["endDate"][0] : null
)
);
if (error) {
console.log(error);
return c.json(
{
success: false,
message: "There was an error getting the planning.",
data: error,
},
400
);
}
//console.log(data);
return c.json(
{
success: data.success,
message: data.message,
data: data.data,
},
data.success ? 200 : 400
);
}
);
export default app;

View File

@@ -0,0 +1,64 @@
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { responses } from "../../../globalUtils/routeDefs/responses.js";
import { tryCatch } from "../../../globalUtils/tryCatch.js";
import { apiHit } from "../../../globalUtils/apiHits.js";
import { psiGetProductionData } from "../controller/psiGetProductionData.js";
const app = new OpenAPIHono({ strict: false });
const Body = z.object({
includeRunnningNumbers: z.string().openapi({ example: "x" }),
});
app.openapi(
createRoute({
tags: ["dataMart"],
summary: "Returns the psiproductiondata.",
method: "get",
path: "/psiproductiondata",
request: {
body: {
content: {
"application/json": { schema: Body },
},
},
},
responses: responses(),
}),
async (c) => {
const q: any = c.req.queries();
// make sure we have a vaid user being accessed thats really logged in
apiHit(c, { endpoint: "/psiproductiondata" });
//console.log(articles["avs"][0]);
const { data, error } = await tryCatch(
psiGetProductionData(
q["avs"] ? q["avs"][0] : null,
q["startDate"] ? q["startDate"][0] : null,
q["endDate"] ? q["endDate"][0] : null
)
);
if (error) {
console.log(error);
return c.json(
{
success: false,
message: "There was an error getting the production.",
data: error,
},
400
);
}
//console.log(data);
return c.json(
{
success: data.success,
message: data.message,
data: data.data,
},
data.success ? 200 : 400
);
}
);
export default app;

View File

@@ -0,0 +1,64 @@
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { responses } from "../../../globalUtils/routeDefs/responses.js";
import { tryCatch } from "../../../globalUtils/tryCatch.js";
import { apiHit } from "../../../globalUtils/apiHits.js";
import { psiGetInventory } from "../controller/psiGetInventory.js";
const app = new OpenAPIHono({ strict: false });
const Body = z.object({
includeRunnningNumbers: z.string().openapi({ example: "x" }),
});
app.openapi(
createRoute({
tags: ["dataMart"],
summary: "Returns the getPsiinventory.",
method: "get",
path: "/getpsiinventory",
request: {
body: {
content: {
"application/json": { schema: Body },
},
},
},
responses: responses(),
}),
async (c) => {
const q: any = c.req.queries();
// make sure we have a vaid user being accessed thats really logged in
apiHit(c, { endpoint: "/getpsiinventory" });
//console.log(articles["avs"][0]);
const { data, error } = await tryCatch(
psiGetInventory(
q["avs"] ? q["avs"][0] : null,
q["startDate"] ? q["startDate"][0] : null,
q["endDate"] ? q["endDate"][0] : null
)
);
if (error) {
console.log(error);
return c.json(
{
success: false,
message: "There was an error getting the production.",
data: error,
},
400
);
}
//console.log(data);
return c.json(
{
success: data.success,
message: data.message,
data: data.data,
},
data.success ? 200 : 400
);
}
);
export default app;

View File

@@ -0,0 +1,32 @@
import { eq } from "drizzle-orm";
import { db } from "../../../../database/dbclient.js";
import { invHistoricalData } from "../../../../database/schema/historicalINV.js";
import { tryCatch } from "../../../globalUtils/tryCatch.js";
import { format } from "date-fns";
export const historicalInvByDate = async (date: string) => {
const histDate = new Date(date);
const { data, error } = (await tryCatch(
db
.select()
.from(invHistoricalData)
.where(
eq(invHistoricalData.histDate, format(histDate, "yyyy-MM-dd"))
)
)) as any;
if (error) {
return {
success: false,
message: "There was an error with getting the inventory",
data: error,
};
}
return {
success: true,
message: `Historical inventory for ${date}`,
data: data,
};
};

View File

@@ -0,0 +1,24 @@
import { tryCatch } from "../../../globalUtils/tryCatch.js";
import { format } from "date-fns";
import { query } from "../../sqlServer/prodSqlServer.js";
import { lastPurchasePrice } from "../../sqlServer/querys/eom/lstPurchasePrice.js";
export const lastPurchase = async () => {
const { data, error } = (await tryCatch(
query(lastPurchasePrice, "Last purchase price")
)) as any;
if (error) {
return {
success: false,
message: "Error getting the last purchase price",
data: error,
};
}
return {
success: true,
message: `Last purchase price for all av in the last 5 years`,
data: data.data,
};
};

View File

@@ -0,0 +1,23 @@
import { tryCatch } from "../../../globalUtils/tryCatch.js";
import { query } from "../../sqlServer/prodSqlServer.js";
import { lastSalesPriceCheck } from "../../sqlServer/querys/eom/lastSalesprice.js";
export const lastSales = async (date: string) => {
const { data, error } = (await tryCatch(
query(lastSalesPriceCheck.replace("[date]", date), "Last sales price")
)) as any;
if (error) {
return {
success: false,
message: "Error getting the last sales price",
data: error,
};
}
return {
success: true,
message: `Last sales price for all av in the last 5 years`,
data: data.data,
};
};

View File

@@ -10,7 +10,10 @@ import { tryCatch } from "../../globalUtils/tryCatch.js";
import { query } from "../sqlServer/prodSqlServer.js";
import { shiftChange } from "../sqlServer/querys/misc/shiftChange.js";
import { createLog } from "../logger/logger.js";
const routes = [stats, history] as const;
import lastPurch from "./route/getLastPurchPrice.js";
import lastSales from "./route/getLastSalesPrice.js";
const routes = [stats, history, lastPurch, lastSales] as const;
const appRoutes = routes.forEach((route) => {
app.route("/eom", route);
@@ -34,9 +37,9 @@ setTimeout(async () => {
const shiftTimeSplit = shift?.data[0]?.shiftChange.split(":");
const cronSetup = `${
shiftTimeSplit.length > 0 ? `${parseInt(shiftTimeSplit[1])}` : "0"
shiftTimeSplit?.length > 0 ? `${parseInt(shiftTimeSplit[1])}` : "0"
} ${
shiftTimeSplit.length > 0 ? `${parseInt(shiftTimeSplit[0])}` : "7"
shiftTimeSplit?.length > 0 ? `${parseInt(shiftTimeSplit[0])}` : "7"
} * * *`;
//console.log(cronSetup);

View File

@@ -0,0 +1,41 @@
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { apiHit } from "../../../globalUtils/apiHits.js";
import { responses } from "../../../globalUtils/routeDefs/responses.js";
import { lastPurchase } from "../controller/getLastPurchasesPrice.js";
const app = new OpenAPIHono({ strict: false });
app.openapi(
createRoute({
tags: ["eom"],
summary: "Returns last sales price.",
method: "get",
path: "/lastpurchprice",
responses: responses(),
}),
async (c) => {
//const body = await c.req.json();
// make sure we have a vaid user being accessed thats really logged in
apiHit(c, { endpoint: "/lastpurchprice" });
try {
const res = await lastPurchase();
return c.json(
{ success: res.success, message: res.message, data: res.data },
200
);
} catch (error) {
return c.json(
{
success: false,
message: "There was an error posting the eom stat.",
data: error,
},
400
);
}
}
);
export default app;

View File

@@ -0,0 +1,43 @@
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { apiHit } from "../../../globalUtils/apiHits.js";
import { responses } from "../../../globalUtils/routeDefs/responses.js";
import { lastPurchase } from "../controller/getLastPurchasesPrice.js";
import { lastSales } from "../controller/getLastestSalesPrice.js";
const app = new OpenAPIHono({ strict: false });
app.openapi(
createRoute({
tags: ["eom"],
summary: "Returns last sales price.",
method: "get",
path: "/lastsalesprice",
responses: responses(),
}),
async (c) => {
//const body = await c.req.json();
const month: string = c.req.query("month") ?? "";
// make sure we have a vaid user being accessed thats really logged in
apiHit(c, { endpoint: "/lastsalesprice" });
try {
const res = await lastSales(month);
return c.json(
{ success: res.success, message: res.message, data: res.data },
200
);
} catch (error) {
return c.json(
{
success: false,
message: "There was an error posting the eom stat.",
data: error,
},
400
);
}
}
);
export default app;

View File

@@ -1,6 +1,7 @@
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { apiHit } from "../../../globalUtils/apiHits.js";
import { responses } from "../../../globalUtils/routeDefs/responses.js";
import { historicalInvByDate } from "../controller/getHistoricalInvByDate.js";
const app = new OpenAPIHono({ strict: false });
const EomStat = z.object({
@@ -12,20 +13,24 @@ const EomStat = z.object({
app.openapi(
createRoute({
tags: ["eom"],
summary: "Gets the correct eom history.",
method: "post",
summary: "Gets History Data by date.",
method: "get",
path: "/histinv",
request: {
params: EomStat,
},
responses: responses(),
}),
async (c) => {
//const body = await c.req.json();
// make sure we have a vaid user being accessed thats really logged in
const month: string = c.req.query("month") ?? "";
apiHit(c, { endpoint: "/histinv" });
try {
return c.json({ success: true, message: "", data: [] }, 200);
const res = await historicalInvByDate(month);
return c.json(
{ success: res.success, message: res.message, data: res.data },
200
);
} catch (error) {
return c.json(
{

View File

@@ -8,6 +8,7 @@ import { totalInvNoRn } from "../../sqlServer/querys/dataMart/totalINV.js";
import { format } from "date-fns-tz";
import { serverSettings } from "../../server/controller/settings/getSettings.js";
import { deleteHistory } from "./removeHistorical.js";
import { activeArticle } from "../../sqlServer/querys/dataMart/article.js";
export const historicalInvIMmport = async () => {
const plantToken = serverSettings.filter((n) => n.name === "plantToken");
@@ -52,6 +53,12 @@ export const historicalInvIMmport = async () => {
return;
}
const { data: articles, error: avError } = (await tryCatch(
query(activeArticle, "Get active articles")
)) as any;
const av = articles.data.length > 0 ? articles.data : ([] as any);
const importInv = inv.data ? inv.data : [];
const eomImportData = importInv.map((i: any) => {
return {
@@ -59,7 +66,13 @@ export const historicalInvIMmport = async () => {
plantToken: plantToken[0].value,
article: i.av,
articleDescription: i.Alias,
materialType: "",
materialType:
av.filter((a: any) => a.IdArtikelvarianten === i.av)
.length > 0
? av.filter(
(a: any) => a.IdArtikelvarianten === i.av
)[0]?.TypeOfMaterial
: "Item not defined",
total_QTY: i.Total_PalletQTY,
avaliable_QTY: i.Avaliable_PalletQTY,
coa_QTY: i.COA_QTY,

View File

@@ -27,7 +27,7 @@ export const deleteHistory = async () => {
.where(
lte(
invHistoricalData.histDate,
sql`(NOW() - INTERVAL '45 day')::date`
sql`(NOW() - INTERVAL '365 day')::date`
)
)
);

View File

@@ -7,6 +7,8 @@ import { postForecast } from "../postForecast.js";
import { query } from "../../../../../sqlServer/prodSqlServer.js";
import { activeArticle } from "../../../../../sqlServer/querys/dataMart/article.js";
import { addDays } from "date-fns";
import { sendEmail } from "../../../../../notifications/controller/sendMail.js";
import { createLog } from "../../../../../logger/logger.js";
let customerID = 4;
export const lorealForecast = async (data: any, user: any) => {
@@ -111,6 +113,9 @@ export const lorealForecast = async (data: any, user: any) => {
);
if (activeAV.length === 0) {
if (typeof forcast.customerArticleNo === "number") {
missingSku.push(forcast);
}
continue;
}
@@ -181,6 +186,9 @@ export const lorealForecast = async (data: any, user: any) => {
);
if (activeAV.length === 0) {
if (typeof forcast.customerArticleNo === "number") {
missingSku.push(forcast);
}
continue;
}
@@ -190,6 +198,56 @@ export const lorealForecast = async (data: any, user: any) => {
//console.log(comForecast);
// email the for the missing ones
const missedGrouped = Object.values(
missingSku.reduce((acc: any, item: any) => {
const key = item.customerArticleNo;
if (!acc[key]) {
// first time we see this customer
acc[key] = item;
} else {
// compare dates and keep the earliest
if (
new Date(item.requirementDate) <
new Date(acc[key].requirementDate)
) {
acc[key] = item;
}
}
return acc;
}, {})
);
const emailSetup = {
email: "Blake.matthes@alpla.com; Stuart.Gladney@alpla.com; Harold.Mccalister@alpla.com; Jenn.Osbourn@alpla.com",
subject:
missedGrouped.length > 0
? `Alert! There are ${missedGrouped.length}, missing skus.`
: `Alert! There is a missing SKU.`,
template: "missingLorealSkus",
context: {
items: missedGrouped,
},
};
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",
};
}
// if the customerarticle number is not matching just ignore it
const predefinedObject = {
receivingPlantId: plantToken[0].value,

View File

@@ -13,7 +13,7 @@ type Data = {
runningNr: string;
lotNum: number;
};
export const consumeMaterial = async (data: Data, prod: any) => {
export const consumeMaterial = async (data: Data) => {
const { runningNr, lotNum } = data;
// replace the rn
@@ -28,12 +28,7 @@ export const consumeMaterial = async (data: Data, prod: any) => {
barcode = r?.data;
} catch (error) {
console.log(error);
createLog(
"error",
prod.user.username,
"logistics",
`Error getting barcode: ${error}`
);
createLog("error", "", "logistics", `Error getting barcode: ${error}`);
}
if (barcode.length === 0) {

View File

@@ -19,7 +19,7 @@ app.openapi(
summary: "Consumes material based on its running number",
method: "post",
path: "/consume",
middleware: authMiddleware,
//middleware: authMiddleware,
description:
"Provided a running number and lot number you can consume material.",
responses: {
@@ -51,33 +51,29 @@ app.openapi(
);
}
apiHit(c, { endpoint: "/consume", lastBody: data });
const authHeader = c.req.header("Authorization");
const token = authHeader?.split("Bearer ")[1] || "";
//const authHeader = c.req.header("Authorization");
//const token = authHeader?.split("Bearer ")[1] || "";
//const payload = await verify(token, process.env.JWT_SECRET!);
try {
const payload = await verify(token, process.env.JWT_SECRET!);
try {
//return apiReturn(c, true, access?.message, access?.data, 200);
//return apiReturn(c, true, access?.message, access?.data, 200);
const consume = await consumeMaterial(data, payload);
return c.json(
{ success: consume?.success, message: consume?.message },
200
);
} catch (error) {
//console.log(error);
//return apiReturn(c, false, "Error in setting the user access", error, 400);
return c.json(
{
success: false,
message: "Missing data please try again",
error,
},
400
);
}
const consume = await consumeMaterial(data);
return c.json(
{ success: consume?.success, message: consume?.message },
200
);
} catch (error) {
return c.json({ success: false, message: "Unauthorized" }, 401);
//console.log(error);
//return apiReturn(c, false, "Error in setting the user access", error, 400);
return c.json(
{
success: false,
message: "Missing data please try again",
error,
},
400
);
}
}
);

View File

@@ -57,6 +57,7 @@ app.openapi(
});
}
console.log(silo);
return c.json({
success: silo.success,
message: silo.message,

View File

@@ -0,0 +1,41 @@
<!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>The below SKU's do not currently have an av and will be ignored in the forcast import.</p>
<p>The date and qty are the first time needed showing from teh vmi report</p>
<table >
<thead>
<tr>
<th>Customer Article Number</th>
<th>First Date Needed</th>
<th>Quantity</th>
</tr>
</thead>
<tbody>
{{#each items}}
<tr>
<td>{{customerArticleNo}}</td>
<td>{{requirementDate}}</td>
<td>{{quantity}}</td>
</tr>
{{/each}}
</tbody>
</table>
<div>
<p>Thank you,</p>
<p>LST Team</p>
</div>
</body>
</html>

View File

@@ -285,9 +285,17 @@ export const labelingProcess = async ({
// "ocp",
// `Error Booking in label: ${book.errors[0].message}`
// );
createLog(
"error",
"labeling",
"ocp",
`There was an error booking in the label: ${JSON.stringify(
book.data
)}`
);
return {
success: false,
message: `Error Booking in label: ${book.errors[0]?.message}`,
message: `Error Booking in label`,
data: book,
};
}

View File

@@ -60,13 +60,47 @@ export const isMainMatStaged = async (lot: any) => {
// isStaged = true;
// }
type CheckConditionArgs = {
results: any[];
filterFn: (n: any) => boolean;
failCondition: (n: any) => boolean;
failMessage: string;
successMessage: string;
lot: { lot: string | number };
};
const checkCondition = ({
results,
filterFn,
failCondition,
failMessage,
successMessage,
lot,
}: CheckConditionArgs): { message: string; success: boolean } => {
const subset = results.filter(filterFn);
if (subset.some(failCondition)) {
const failing = subset.filter(failCondition);
return {
message: `lot: ${lot.lot}, is missing: ${failing
.map(
(o: any) =>
`${o.MaterialHumanReadableId} - ${o.MaterialDescription}`
)
.join(",\n ")} ${failMessage}`,
success: false,
};
} else {
return { message: successMessage, success: true };
}
};
createLog("info", "mainMaterial", "ocp", `Maint material query ran.`);
const mainMateiral = res.filter((n: any) => n.IsMainMaterial);
if (mainMateiral[0]?.noMaterialShortage === "no") {
isStaged = {
message: `Main material: ${mainMateiral[0].MaterialHumanReadableId} - ${mainMateiral[0].MaterialDescription}: is not staged for ${lot.lot} `,
const mainMaterial = res.find((n: any) => n.IsMainMaterial);
if (mainMaterial?.noMMShortage === "noMM") {
return {
message: `Main material: ${mainMaterial.MaterialHumanReadableId} - ${mainMaterial.MaterialDescription}: is not staged for ${lot.lot}`,
success: false,
};
}
@@ -75,48 +109,39 @@ export const isMainMatStaged = async (lot: any) => {
// for manual consume color if active to check colors
const checkColorSetting = set.filter((n) => n.name === "checkColor");
// 2. Auto color
if (checkColorSetting[0].value === "1") {
const autoConsumeColor = res.filter(
(n: any) => !n.IsMainMaterial && !n.isManual
);
if (
autoConsumeColor.some(
(n: any) => n.autoConsumeCheck === "autoConsumeNOK"
)
) {
const onlyNOK = autoConsumeColor.filter(
(n: any) => n.autoConsumeCheck === "autoConsumeNOK"
);
isStaged = {
message: `lot: ${lot.lot}, is missing: ${onlyNOK
.map(
(o: any) =>
`${o.MaterialHumanReadableId} - ${o.MaterialDescription}`
)
.join(",\n ")} for autoconsume`,
success: false,
};
}
// auto check
// 2. Auto color
const autoColor = checkCondition({
results: res,
lot,
filterFn: (n) =>
n.isManual &&
!("noPKGAutoShortage" in n) &&
!("noPKGManualShortage" in n), // pool = non-main, auto
failCondition: (n) => n.autoConsumeCheck === "autoConsumeNOK", // column = autoConsumeCheck
failMessage: "for autoconsume",
successMessage: "auto color is good",
});
if (!autoColor.success) return autoColor;
console.log(autoColor);
// // for manual consume color
const manualConsumeColor = res.filter(
(n: any) => !n.IsMainMaterial && n.isManual
);
if (
manualConsumeColor.some(
(n: any) => n.noMaterialShortage === "yes"
)
) {
isStaged = {
message: `lot: ${lot.lot}, is missing: ${manualConsumeColor
.map(
(o: any) =>
`${o.MaterialHumanReadableId} - ${o.MaterialDescription}`
)
.join(",\n ")} for manual Material`,
success: false,
};
}
// 3. Manual color
const manualColor = checkCondition({
results: res,
lot,
filterFn: (n) =>
!n.IsMainMaterial &&
n.isManual &&
!("noPKGAutoShortage" in n) &&
!("noPKGManualShortage" in n), // pool = non-main, manual
failCondition: (n) => n.noManualShortage === "noOK", // column = noManualShortage
failMessage: "for manual material",
successMessage: "manual color is good",
});
if (!manualColor.success) return manualColor;
console.log(manualColor);
} else {
createLog(
"info",
@@ -129,11 +154,58 @@ export const isMainMatStaged = async (lot: any) => {
// // if we want to check the packaging
const checkPKGSetting = set.filter((n) => n.name === "checkPKG");
if (checkPKGSetting[0].value === "1") {
const packagingCheck = res.filter(
(n: any) => !n.IsMainMaterial && n.isManual
const pkgAuto = checkCondition({
results: res,
lot,
filterFn: (n) =>
!n.IsMainMaterial &&
!n.isManual &&
"noPKGAutoShortage" in n,
failCondition: (n) => n.noPKGAutoShortage === "noAutoPkg",
failMessage: "for pkg",
successMessage: "auto PKG is good",
});
if (!pkgAuto.success) return pkgAuto;
console.log(pkgAuto);
// 5. Packaging manual
const pkgManual = checkCondition({
results: res,
lot,
filterFn: (n) =>
!n.IsMainMaterial &&
n.isManual &&
"noPKGManualShortage" in n,
failCondition: (n) => n.noPKGManualShortage === "noManPkg",
failMessage: "for pkg",
successMessage: "manual PKG is good",
});
if (!pkgManual.success) return pkgManual;
console.log(pkgManual);
} else {
createLog(
"info",
"mainMaterial",
"ocp",
"PKG check is not active."
);
if (packagingCheck.some((n: any) => n.noPKGShortage === "noPkg")) {
isStaged = {
}
// manual pkg
if (checkPKGSetting[0].value === "1") {
const packagingCheck = res.filter(
(n: any) =>
!n.IsMainMaterial &&
n.isManual &&
"noPKGManualShortage" in n
);
if (
packagingCheck.some(
(n: any) => n.noPKGManualShortage === "noManPkg"
)
) {
return (isStaged = {
message: `lot: ${lot.lot}, is missing: ${packagingCheck
.map(
(o: any) =>
@@ -141,7 +213,7 @@ export const isMainMatStaged = async (lot: any) => {
)
.join(",\n ")} for pkg`,
success: false,
};
});
}
} else {
createLog(

View File

@@ -33,13 +33,13 @@ export const delieryInhouse = async (data: any) => {
"error",
"labeling",
"ocp",
`${data.printer.name}, Error:${res.data.Message}`
`${data.printer?.name}, Error:${res.data.Message}`
);
//printerUpdate(data.printer, 7, "Error while deliverying inhouse.");
return {
success: true,
message: `${data.printer.name} had an error while trying to deliver.`,
message: `${data.printer?.name} had an error while trying to deliver.`,
data: res.data,
};
} // label was just delivered

View File

@@ -43,9 +43,9 @@ export const wrapperStuff = async (tagData: any) => {
"rfid",
`There are ${tagData.length} tags and this ${
tagData[0].reader
} only allows 1 tag to create a label: tag ${tagData[0].tag}, ${
tagData[1].tag
}, ${tagData.length === 3 && tagData[2].tag}`
} only allows 1 tag to create a label: tag ${tagData
.map((o: any) => `${o.tag}`)
.join(",\n ")}`
);
const tag = { ...tagData[0], runningNr: 0 };
//tagStuff([tag]);

View File

@@ -1,4 +1,6 @@
export const activeArticle = `
use AlplaPROD_test1
SELECT V_Artikel.IdArtikelvarianten,
V_Artikel.Bezeichnung,
V_Artikel.ArtikelvariantenTypBez,
@@ -43,7 +45,12 @@ V_Artikel.ArtikelvariantenTypBez = 'Gaylord' or
V_Artikel.ArtikelvariantenTypBez = 'Misc. Packaging' or
V_Artikel.ArtikelvariantenTypBez = 'Sleeve' or
V_Artikel.ArtikelvariantenTypBez = 'Plastic Bag' or
V_Artikel.ArtikelvariantenTypBez = 'Purch Spout'
V_Artikel.ArtikelvariantenTypBez = 'Purch Spout' or
V_Artikel.ArtikelvariantenTypBez = 'Seal' or
V_Artikel.ArtikelvariantenTypBez = 'Tape' or
V_Artikel.ArtikelvariantenTypBez = 'Box' or
V_Artikel.ArtikelvariantenTypBez = 'Label IML' or
V_Artikel.ArtikelvariantenTypBez = 'Pallet Runner'
THEN 'PKG'
WHEN V_Artikel.ArtikelvariantenTypBez='HD-PE' or
V_Artikel.ArtikelvariantenTypBez='HD-PE PCR' or
@@ -77,7 +84,8 @@ V_Artikel.ArtikelvariantenTypBez = 'Purchased Caps' or
V_Artikel.ArtikelvariantenTypBez = 'Purchased_preform'
THEN 'Purchased_preform'
When
V_Artikel.ArtikelvariantenTypBez = 'Closures'
V_Artikel.ArtikelvariantenTypBez = 'Closures' or
V_Artikel.ArtikelvariantenTypBez = 'Cap'
THEN 'Caps'
When
V_Artikel.ArtikelvariantenTypBez = 'Dummy'
@@ -95,7 +103,8 @@ V_Artikel.ProdBereichBez = 'IM-Caps' or
V_Artikel.ProdBereichBez = 'IM-PET' or
V_Artikel.ProdBereichBez = 'PRINT OFFICE' or
V_Artikel.ProdBereichBez = 'EBM' or
V_Artikel.ProdBereichBez = 'ISBM'
V_Artikel.ProdBereichBez = 'ISBM' or
V_Artikel.ProdBereichBez = 'IM-Finishing'
Then 'FG'
Else 'not Defined Profit Center'
end,
@@ -107,16 +116,17 @@ sales.[KdArtBez] as CustomerArticleDescription,
round(V_Artikel.Zyklus, 2) as CycleTime,
Sypronummer as salesAgreement,
V_Artikel.ProdArtikelBez as ProductFamily
,REPLACE(pur.UOM,'UOM:','') as UOM
--,*
FROM AlplaPROD_test1.dbo.V_Artikel (nolock)
FROM dbo.V_Artikel (nolock)
join
AlplaPROD_test1.dbo.V_Artikelvarianten on AlplaPROD_test1.dbo.V_Artikel.IdArtikelvarianten =
AlplaPROD_test1.dbo.V_Artikelvarianten.IdArtikelvarianten
dbo.V_Artikelvarianten (nolock) on dbo.V_Artikel.IdArtikelvarianten =
dbo.V_Artikelvarianten.IdArtikelvarianten
join
AlplaPROD_test1.dbo.V_FibuKonten_BASIS on AlplaPROD_test1.dbo.V_Artikelvarianten.IdFibuKonto =
AlplaPROD_test1.dbo.V_FibuKonten_BASIS.IdFibuKonto
dbo.V_FibuKonten_BASIS (nolock) on dbo.V_Artikelvarianten.IdFibuKonto =
dbo.V_FibuKonten_BASIS.IdFibuKonto
-- adding in the sales price
@@ -130,7 +140,7 @@ left join
,[KdArtNr]
,[KdArtBez]
--,*
from AlplaPROD_test1.dbo.T_HistoryVK (nolock)
from dbo.T_HistoryVK (nolock)
where
--GueltigabDatum > getDate() - 120
--and
@@ -138,7 +148,26 @@ left join
and StandardKunde = 1 -- default address
) a
where RN = 1) as sales
on AlplaPROD_test1.dbo.V_Artikel.IdArtikelvarianten = sales.av
on dbo.V_Artikel.IdArtikelvarianten = sales.av
/* adding the purchase price info */
left join
(select * from
(select
ROW_NUMBER() OVER (PARTITION BY IdArtikelvarianten ORDER BY GueltigabDatum DESC) AS RN,
IdArtikelvarianten as av
,GueltigabDatum as validDate
,EKPreis as price
,LiefArtNr as supplierNr
,case when Bemerkung is not null and Bemerkung like '%UOM:%' then LEFT(Bemerkung, CHARINDEX(' ', Bemerkung)) else 'UOM:1' end as UOM
,Bemerkung
--,*
from dbo.T_HistoryEK (nolock)
where
StandardLieferant = 1 -- default address
) a
where RN = 1) as pur
on dbo.V_Artikel.IdArtikelvarianten = pur.av
where V_Artikel.aktiv = 1

View File

@@ -0,0 +1,17 @@
export const lastSalesPriceCheck = `
use AlplaPROD_test1
select * from
(select IdArtikelvarianten as av,
VKPreis as salesPrice,
MPB, FWMPAlpla,
FWMPB,
ROW_NUMBER() over(partition by IdArtikelVarianten order by gueltigabdatum desc) rn,
convert(date, gueltigabdatum, 120) as validDate
from dbo.T_HistoryVK (nolock)
where convert(date, gueltigabdatum, 120) <= '[date]' and StandardKunde = 1) a
where rn =1
order by av asc,
validDate desc
`;

View File

@@ -0,0 +1,17 @@
export const lastPurchasePrice = `
use AlplaPROD_test1
SELECT plant=(SELECT Wert FROM dbo.T_SystemParameter (nolock) WHERE (Bezeichnung = 'Werkskuerzel')),
plantName=(SELECT Wert FROM dbo.T_SystemParameter AS T_SystemParameter (nolock) WHERE (Bezeichnung = 'Mandant-intern')),*
from
(Select IdBestellung as 'Purchase order number',
IdArtikelVarianten AS AV,
BestellMenge,
BestellMengeVPK,
PreisProEinheit,
convert(varchar,Lieferdatum,23) as deliveryDate,
ROW_NUMBER() over(partition by IdArtikelVarianten order by Lieferdatum desc) rn
from dbo.V_Bestellpositionen_PURCHASE (nolock)
where PositionsStatus = '7' or PositionsStatus = '6' or PositionsStatus = '5' and convert(varchar,Lieferdatum,23) > DATEADD(year, -5, GetDate()) )a
where rn = 1
`;

View File

@@ -23,69 +23,78 @@
export const mmQuery = `
use [test1_AlplaPROD2.0_Read]
declare @lot as NVARCHAR(max) = [lotNumber]
/*
checks all needed material including pkg
we only want to monitor the manual materials and the mm materail to make sure they are good.
for auto consume materails this will be compared with another query.
*/
SELECT lot.ProductionLotHumanReadableId
,MaterialHumanReadableId
,MaterialDescription
--IsMainMaterial,
,case when SourcingState in (1, 2) then 1
/*
Material demands for this lot
*/
select
MaterialHumanReadableId
,MaterialDescription
-- check box is staged so we could book in even if we used preprint.
,case when SourcingState in (1, 2) then 1
when x.ProvidedAmount > 0 then 1
when x.EffectiveConsumption > 0 then 1
else 0 end as Staged
,x.ProvidedAmount as Provided
,x.EffectiveConsumption as consumption
,x.TotalDemand as totalDemand ,
case when cp.Pieces = 1 then (lot.TotalProducedLoadingUnits+1) * p.LoadingUnitPieces else
(a.Weight *((case when cp.Percentage is null then 80.25 else cp.Percentage end) / 100) * ((lot.TotalProducedLoadingUnits+1) * p.LoadingUnitPieces)) / 1000 end totalNeeded
,l.qty as invForAutoConsume
/* remaining needed to complete the lot */
--,x.TotalDemand - x.EffectiveConsumption as remainingNeeded
/* do we have enough staged or scanned to the lot? */
,case when (case when x.ProvidedAmount <> 0
then x.ProvidedAmount else x.EffectiveConsumption end) >
(case when cp.Pieces = 1 then (lot.TotalProducedLoadingUnits+1) * p.LoadingUnitPieces else
(a.Weight *((case when cp.Percentage is null then 80.25 else cp.Percentage end) / 100) * ((lot.TotalProducedLoadingUnits+1) * p.LoadingUnitPieces)) / 1000 end)
then 'good'
else 'no' end as noMaterialShortage
-- pkg check
,case when pkg.QuantityPosition is null then null else
(case when l.qty > (lot.TotalProducedLoadingUnits+1) * pkg.QuantityPosition then 'pkgGood' else 'noPkg' end) end as noPKGShortage
,case when cp.Percentage is null then
case when l.qty > ((lot.TotalProducedLoadingUnits +1) * pkg.QuantityPosition) then 'autoConsumeOk' else 'autoConsumeNOK' end else
(case when l.qty > (a.Weight *((case when cp.Percentage is null then 80.25 else cp.Percentage end) / 100) * ((lot.TotalProducedLoadingUnits+1) * p.LoadingUnitPieces)) / 1000 and IsManualProcess = 0
then 'autoConsumeOk' else 'autoConsumeNOK' end) end as autoConsumeCheck
,x.IsManualProcess as isManual
,IsMainMaterial
-- lot stuff
,lot.TotalPlannedLoadingUnits
,lot.TotalProducedLoadingUnits
,lot.TotalPlannedLoadingUnits - lot.TotalProducedLoadingUnits as remainingPallets
,case when cp.Percentage is null then 80.25 else cp.Percentage end as Percentage -- this is to over come the alternate mm put in planning
,case when cp.Pieces is not null then cp.Pieces else pkg.QuantityPosition end as peices
FROM [issueMaterial].[MaterialDemand] x (nolock)
,x.ProvidedAmount as Provided -- this is what has been provided most of the time this is due to a silo attachment
,x.EffectiveConsumption as consumption -- this is how much was consummed via cmd 112
,x.TotalDemand as totalDemand -- the total demand needed to finish the lot out
,case when cp.Pieces >= 0.001 then (lot.TotalProducedLoadingUnits+1) * cp.Pieces else
(a.Weight *((case when cp.Percentage is null then 80 else cp.Percentage end) / 100) * ((lot.TotalProducedLoadingUnits+1) * p.LoadingUnitPieces)) / 1000 end totalNeeded
,case when IsMainMaterial = 1 then
case when (case when x.ProvidedAmount <> 0
then x.ProvidedAmount else x.EffectiveConsumption end) >
(case when cp.Pieces >= 0.001 then (lot.TotalProducedQuantity+1) * cp.Pieces else
(a.Weight *((case when cp.Percentage is null then 80 else cp.Percentage end) / 100) * ((lot.TotalProducedLoadingUnits+1) * p.LoadingUnitPieces)) / 1000 end)
then 'mmGood'
else 'noMM' end else null end as noMMShortage
-- pkg check auto
,case when pkg.QuantityPosition is null then null else
(case when l.qty > ((lot.TotalProducedLoadingUnits+1) * pkg.QuantityPosition) and IsManualProcess = 0 then 'pkgAutoGood' else 'noAutoPkg' end) end as noPKGAutoShortage
-- plg check manual
,case when pkg.QuantityPosition is null then null else
(case when x.EffectiveConsumption > ((lot.TotalProducedLoadingUnits+1) * pkg.QuantityPosition) and IsManualProcess = 1 then 'pkgManGood' else 'noManPkg' end) end as noPKGManualShortage
-- manualMateiral
,case when IsMainMaterial = 0 and IsManualProcess = 1 then
case when (case when x.ProvidedAmount <> 0
then x.ProvidedAmount else x.EffectiveConsumption end) >
(case when cp.Pieces >= 0.001 then (lot.TotalProducedQuantity+1) * cp.Pieces else
(a.Weight *((case when cp.Percentage is null then 80 else cp.Percentage end) / 100) * ((lot.TotalProducedLoadingUnits+1) * p.LoadingUnitPieces)) / 1000 end)
then 'manualGood'
else 'noOK' end else null end as noManualShortage
-- autoconsume
,case when cp.Percentage is null then
case when l.qty > ((lot.TotalProducedLoadingUnits +1) * pkg.QuantityPosition) then 'autoConsumeOk' else 'autoConsumeNOK' end else
(case when l.qty > (a.Weight *(cp.Percentage / 100) * ((lot.TotalProducedLoadingUnits+1) * p.LoadingUnitPieces)) / 1000 and IsManualProcess = 0
then 'autoConsumeOk' else 'autoConsumeNOK' end) end as autoConsumeCheck
-- stock amounts
,l.qty as invForAutoConsume
,case when cp.Percentage is null then 0 else cp.Percentage end as Percentage
,pkg.QuantityPosition
,(lot.TotalProducedQuantity+1) * cp.Pieces
from [issueMaterial].[MaterialDemand] x (nolock)
/* production lot info */
left join
[productionControlling].[ProducedLot] as lot on
lot.Id = x.ProductionLotId
/* av data */
left join
[masterData].[Article] as a on
a.id = lot.ArticleId
/* compound*/
left join
[masterData].[CompoundPosition] as cp on
cp.CompoundId = a.CompoundId
and cp.ArticleId = x.MaterialId
/* packagaing */
left join
[masterData].[PackagingInstructionPosition] as pkg on
@@ -97,6 +106,17 @@ left join
[masterData].[PackagingInstruction] as p on
p.id = lot.PackagingId
/* av data */
left join
[masterData].[Article] as a on
a.id = lot.ArticleId
/* compound*/
left join
[masterData].[CompoundPosition] as cp on
cp.CompoundId = a.CompoundId
and cp.ArticleId = x.MaterialId
/* current stock info for auto consumption*/
left join
(select
@@ -113,5 +133,8 @@ where autoverbrauch = 1 and aktiv = 1
group by IdArtikelVarianten,ArtikelVariantenBez
) as l on
l.IdArtikelVarianten = MaterialHumanReadableId
where lot.ProductionLotHumanReadableId = [lotNumber]
where lot.ProductionLotHumanReadableId = @lot and MaterialDescription not like '%nopal%'
and MaterialDescription NOT LIKE '%bb%'
and MaterialDescription NOT LIKE '%mcg%'
`;

View File

@@ -1,33 +1,34 @@
export const planningNumbersByAVDate = `
use AlplaPROD_test1
declare @start_date nvarchar(30) = [startDate] --'2025-01-01'
declare @end_date nvarchar(30) = [endDate] --'2025-08-09'
declare @start_date nvarchar(30) = '[startDate]' --'2025-01-01'
declare @end_date nvarchar(30) = '[endDate]' --'2025-08-09'
/*
articles will need to be passed over as well as the date structure we want to see
*/
-- planned lots in planning
select V_ProdLosProduktionJeProdTag_PLANNING.IdArtikelvarianten As Article,
select x.IdArtikelvarianten As Article,
ProduktionAlias as Description,
standort as MachineId,
MaschinenBezeichnung as MachineName,
--MaschZyklus as PlanningCycleTime,
V_ProdLosProduktionJeProdTag_PLANNING.IdProdPlanung as LotNumber,
x.IdProdPlanung as LotNumber,
FORMAT(ProdTag, 'MM/dd/yyyy') as ProductionDay,
V_ProdLosProduktionJeProdTag_PLANNING.planMenge as TotalPlanned,
x.planMenge as TotalPlanned,
ProduktionMenge as QTYPerDay,
round(ProduktionMengeVPK, 2) PalDay,
Status as finished
--MaschStdAuslastung as nee
from dbo.V_ProdLosProduktionJeProdTag_PLANNING (nolock)
from dbo.V_ProdLosProduktionJeProdTag_PLANNING (nolock) as x
left join
dbo.V_ProdPlanung (nolock) on
V_ProdLosProduktionJeProdTag_PLANNING .IdProdPlanung = V_ProdPlanung.IdProdPlanung
dbo.V_ProdPlanung (nolock) as p on
x.IdProdPlanung = p.IdProdPlanung
where V_ProdLosProduktionJeProdTag_PLANNING.IdArtikelvarianten in ([articles]) and ProdTag between @start_date and @end_date --and IdProdPlanung = 18442
where ProdTag between @start_date and @end_date
and p.IdArtikelvarianten in ([articles])
--and V_ProdLosProduktionJeProdTag_PLANNING.IdKunde = 10
--and IdProdPlanung = 18442
order by ProdTag
order by ProdTag desc
`;

View File

@@ -1,8 +1,8 @@
export const productionNumbers = `
use [test1_AlplaPROD2.0_Reporting]
declare @startDate nvarchar(30) = [startDate] --'2024-12-30'
declare @endDate nvarchar(30) = [endDate] --'2025-08-09'
declare @startDate nvarchar(30) = '[startDate]' --'2024-12-30'
declare @endDate nvarchar(30) = '[endDate]' --'2025-08-09'
select MachineLocation,
ArticleHumanReadableId as article,

View File

@@ -0,0 +1,34 @@
export const planningNumbersByAVDate = `
use AlplaPROD_test1
declare @start_date nvarchar(30) = '[startDate]' --'2025-01-01'
declare @end_date nvarchar(30) = '[endDate]' --'2025-08-09'
/*
articles will need to be passed over as well as the date structure we want to see
*/
select x.IdArtikelvarianten As Article,
ProduktionAlias as Description,
standort as MachineId,
MaschinenBezeichnung as MachineName,
--MaschZyklus as PlanningCycleTime,
x.IdProdPlanung as LotNumber,
FORMAT(ProdTag, 'MM/dd/yyyy') as ProductionDay,
x.planMenge as TotalPlanned,
ProduktionMenge as QTYPerDay,
round(ProduktionMengeVPK, 2) PalDay,
Status as finished
--MaschStdAuslastung as nee
from dbo.V_ProdLosProduktionJeProdTag_PLANNING (nolock) as x
left join
dbo.V_ProdPlanung (nolock) as p on
x.IdProdPlanung = p.IdProdPlanung
where ProdTag between @start_date and @end_date
and p.IdArtikelvarianten in ([articles])
--and V_ProdLosProduktionJeProdTag_PLANNING.IdKunde = 10
--and IdProdPlanung = 18442
order by ProdTag desc
`;

View File

@@ -21,7 +21,7 @@ select ext.Barcode
,RunningNumber as runnungNumber
,SsccEanRunningNumber as externalRunningNumber
,ArticleHumanReadableId
,case when LabelManagementHumanReadableId is null then (select HumanReadableId from [test1_AlplaPROD2.0_Read].[masterData].[LabelManagement] (nolock) where LabelMarkerId = 7) else LabelManagementHumanReadableId end as labelLayout
,case when LabelManagementHumanReadableId is null then (select HumanReadableId from [test1_AlplaPROD2.0_Read].[masterData].[LabelManagement] (nolock) where LabelMarkerId = 7 and Active = 1) else LabelManagementHumanReadableId end as labelLayout
,case when EinlagerungsMengeSum IS NULL then 'notOnStock' else 'onStock' end as stockStatus
from [test1_AlplaPROD2.0_Read].[labelling].[ExternalLabel] (nolock) as ext