Compare commits

...

28 Commits

Author SHA1 Message Date
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
15 changed files with 231 additions and 110 deletions

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

@@ -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

@@ -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

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

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">

View File

@@ -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": 585,
"build": 609,
"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

@@ -37,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

@@ -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: {

View File

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

View File

@@ -112,7 +112,7 @@ export const isMainMatStaged = async (lot: any) => {
);
if (
manualConsumeColor.some(
(n: any) => n.noMaterialShortage === "yes"
(n: any) => n.noManualShortage === "noOK"
)
) {
isStaged = {

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

@@ -121,7 +121,7 @@ V_Artikel.ProdArtikelBez as ProductFamily
FROM dbo.V_Artikel (nolock)
join
dbo.V_Artikelvarianten (nolock) on AlplaPROD_usbow1.dbo.V_Artikel.IdArtikelvarianten =
dbo.V_Artikelvarianten (nolock) on dbo.V_Artikel.IdArtikelvarianten =
dbo.V_Artikelvarianten.IdArtikelvarianten
join
@@ -159,7 +159,8 @@ left join
,GueltigabDatum as validDate
,EKPreis as price
,LiefArtNr as supplierNr
,case when len(Bemerkung) > 4 and Bemerkung like '%UOM%' then LEFT(Bemerkung, CHARINDEX(' ', Bemerkung) - 1) else 'UOM:1' end as UOM
,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

View File

@@ -25,6 +25,13 @@ 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.
*/
/*
Material demands for this lot
*/
select
@@ -45,30 +52,39 @@ MaterialHumanReadableId
,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 pkg.QuantityPosition >= 0.001 then ((lot.TotalProducedLoadingUnits+1) * pkg.QuantityPosition) else
(a.Weight *(cp.Percentage / 100) * ((lot.TotalProducedLoadingUnits+1) * p.LoadingUnitPieces)) / 1000 end totalNeeded
,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 totalNeeded
,case when IsMainMaterial = 1 then case when (case when x.ProvidedAmount <> 0
,case when IsMainMaterial = 1 then
case when (case when x.ProvidedAmount <> 0
then x.ProvidedAmount else x.EffectiveConsumption end) >
(case when pkg.QuantityPosition >= 0.001 then (lot.TotalProducedLoadingUnits+1) * pkg.QuantityPosition else
(a.Weight *(cp.Percentage / 100) * ((lot.TotalProducedLoadingUnits+1) * p.LoadingUnitPieces)) / 1000 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 noMaterialShortage
else 'noMM' end else null end as noMMShortage
-- 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
-- autoconsume
-- 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
,x.IsManualProcess as isManual
,IsMainMaterial
,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 */
@@ -105,10 +121,10 @@ IdArtikelVarianten
,ArtikelVariantenBez
,sum(VerfuegbareMengeSum) as qty
from AlplaPROD_usweb1.dbo.V_LagerPositionenBarcodes as i (nolock)
from AlplaPROD_test1.dbo.V_LagerPositionenBarcodes as i (nolock)
left join
AlplaPROD_usweb1.dbo.V_LagerAbteilungen as l (nolock) on
AlplaPROD_test1.dbo.V_LagerAbteilungen as l (nolock) on
l.IdLagerAbteilung = i.IdLagerAbteilung
where autoverbrauch = 1 and aktiv = 1
group by IdArtikelVarianten,ArtikelVariantenBez