Compare commits
28 Commits
57966ac9de
...
79f1f8f91b
| Author | SHA1 | Date | |
|---|---|---|---|
| 79f1f8f91b | |||
| b677bc1498 | |||
| a53915ad8c | |||
| b3ce767b32 | |||
| 6caa5984e7 | |||
| 415d2e4a1d | |||
| 271cdbdbfa | |||
| 796a8dccd2 | |||
| e03e92c18d | |||
| dd2e5d04ae | |||
| 708b57b926 | |||
| 0444da8bbc | |||
| 6d49fae16d | |||
| be8a44f2dc | |||
| a3994a1f69 | |||
| 00eaf62d4c | |||
| 6851777faf | |||
| f9e97fc224 | |||
| 4e3c5e4191 | |||
| 172fd1d5c2 | |||
| 1094de2ebd | |||
| 7462b3d90b | |||
| 2045c13ef2 | |||
| 5fa9e83d5b | |||
| f48c944bd0 | |||
| dddd1d422e | |||
| 8133443ec9 | |||
| 28c7d30c1a |
8
.includes
Normal file
8
.includes
Normal file
@@ -0,0 +1,8 @@
|
||||
database
|
||||
dist
|
||||
frontend/dist
|
||||
CHANGELOG.md
|
||||
drizzle.config.ts
|
||||
package.json
|
||||
package-lock.json
|
||||
README.md
|
||||
@@ -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),
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -32,7 +32,10 @@ function RouteComponent() {
|
||||
<TransferToNextLot />
|
||||
</>
|
||||
) : (
|
||||
<TransferToNextLot />
|
||||
<>
|
||||
<ConsumeMaterial />
|
||||
<TransferToNextLot />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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": {
|
||||
|
||||
61
server/scripts/copyToLst.ps1
Normal file
61
server/scripts/copyToLst.ps1
Normal 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 wasn’t 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
|
||||
}
|
||||
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ export const isMainMatStaged = async (lot: any) => {
|
||||
);
|
||||
if (
|
||||
manualConsumeColor.some(
|
||||
(n: any) => n.noMaterialShortage === "yes"
|
||||
(n: any) => n.noManualShortage === "noOK"
|
||||
)
|
||||
) {
|
||||
isStaged = {
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user