Compare commits

...

15 Commits

Author SHA1 Message Date
90e9bb0ff6 refactor(rfid): refactored the way the wrapper works to indlude backup dyco plan 2025-03-26 22:10:39 -05:00
bd11feb136 refactor(rfid): refactored station 3 (lines) and complete logic 2025-03-26 22:10:05 -05:00
96e7f742fe refactor(ocme): removed some info logs as ocme calls alot 2025-03-26 22:09:23 -05:00
eb051d51f2 feat(notify): intial nofity system added to monitor crashes and rfid wrapper 2025-03-26 22:08:53 -05:00
7a1a4773e7 feat(ocp): create and book in plus dyco controller implemented 2025-03-26 22:07:19 -05:00
878e650e62 chore(release): bump build number to 92 2025-03-26 22:05:21 -05:00
a31e7ea163 chore(release): bump build number to 91 2025-03-26 16:17:53 -05:00
04aa943920 chore(release): bump build number to 90 2025-03-26 16:00:56 -05:00
af076b8e27 chore(release): bump build number to 89 2025-03-26 15:39:57 -05:00
c0a0589b3c chore(release): bump build number to 88 2025-03-26 15:19:55 -05:00
509ef84726 chore(release): bump build number to 87 2025-03-26 15:18:53 -05:00
5ab813f378 chore(release): bump build number to 86 2025-03-26 12:44:17 -05:00
5d61eb879e chore(release): bump build number to 85 2025-03-26 12:42:58 -05:00
2d4b1db5f4 fix(logistics): correction to the lane grab 2025-03-26 09:16:16 -05:00
58f7b4322d feat(logistics): added in return material by lane name and gets lane id 2025-03-26 08:36:47 -05:00
42 changed files with 2300 additions and 235 deletions

View File

@@ -17,8 +17,9 @@ export const prodlabels = pgTable(
line: integer("line"),
runningNr: integer("runningNr").notNull(),
status: text("status"),
add_date: timestamp("add_date"),
upd_date: timestamp("upd_date"),
add_user: text("add_user").default("lst"),
add_date: timestamp("add_date").defaultNow(),
upd_date: timestamp("upd_date").defaultNow(),
},
(table) => [
//uniqueIndex("emailUniqueIndex").on(sql`lower(${table.email})`),

View File

@@ -73,7 +73,7 @@ export default function LabelLog() {
</div>
);
}
const labelData = data ? data : [];
return (
<LstCard className="m-2 p-2 min-h-2/5">
<p className="text-center">Labels for the last 2 hours</p>
@@ -113,7 +113,7 @@ export default function LabelLog() {
</>
) : (
<TableBody>
{data?.map((label: any) => (
{labelData.map((label: any) => (
<TableRow key={label.runningNr}>
<TableCell className="font-medium">
{label.line}

361
package-lock.json generated
View File

@@ -13,13 +13,16 @@
"@hono/zod-openapi": "^0.19.2",
"@scalar/hono-api-reference": "^0.7.2",
"@types/jsonwebtoken": "^9.0.9",
"@types/nodemailer-express-handlebars": "^4.0.5",
"adm-zip": "^0.5.16",
"axios": "^1.8.4",
"bcryptjs": "^3.0.2",
"date-fns": "^4.1.0",
"drizzle-kit": "^0.30.5",
"drizzle-orm": "^0.41.0",
"drizzle-zod": "^0.7.0",
"fast-xml-parser": "^5.0.9",
"fs-extra": "^11.3.0",
"jsonwebtoken": "^9.0.2",
"mssql": "^11.0.1",
"nodemailer": "^6.10.0",
@@ -30,6 +33,7 @@
"pino-pretty": "^13.0.0",
"postgres": "^3.4.5",
"rimraf": "^6.0.1",
"st-ethernet-ip": "^2.7.3",
"ws": "^8.18.1",
"zod": "^3.24.2"
},
@@ -40,12 +44,11 @@
"@types/js-cookie": "^3.0.6",
"@types/mssql": "^9.1.7",
"@types/node": "^22.13.11",
"@types/nodemailer": "^6.4.17",
"@types/pg": "^8.11.11",
"@types/ws": "^8.18.0",
"concurrently": "^9.1.2",
"cz-conventional-changelog": "^3.3.0",
"drizzle-kit": "^0.30.5",
"fs-extra": "^11.3.0",
"standard-version": "^9.5.0",
"tsx": "^4.19.3",
"typescript": "^5.8.2"
@@ -520,7 +523,6 @@
"version": "0.10.2",
"resolved": "https://registry.npmjs.org/@drizzle-team/brocli/-/brocli-0.10.2.tgz",
"integrity": "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==",
"dev": true,
"license": "Apache-2.0"
},
"node_modules/@ecies/ciphers": {
@@ -542,7 +544,6 @@
"resolved": "https://registry.npmjs.org/@esbuild-kit/core-utils/-/core-utils-3.3.2.tgz",
"integrity": "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==",
"deprecated": "Merged into tsx: https://tsx.is",
"dev": true,
"license": "MIT",
"dependencies": {
"esbuild": "~0.18.20",
@@ -556,7 +557,6 @@
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -573,7 +573,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -590,7 +589,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -607,7 +605,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -624,7 +621,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -641,7 +637,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -658,7 +653,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -675,7 +669,6 @@
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -692,7 +685,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -709,7 +701,6 @@
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -726,7 +717,6 @@
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -743,7 +733,6 @@
"cpu": [
"mips64el"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -760,7 +749,6 @@
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -777,7 +765,6 @@
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -794,7 +781,6 @@
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -811,7 +797,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -828,7 +813,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -845,7 +829,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -862,7 +845,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -879,7 +861,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -896,7 +877,6 @@
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -913,7 +893,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -927,7 +906,6 @@
"version": "0.18.20",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz",
"integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"bin": {
@@ -966,7 +944,6 @@
"resolved": "https://registry.npmjs.org/@esbuild-kit/esm-loader/-/esm-loader-2.6.5.tgz",
"integrity": "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==",
"deprecated": "Merged into tsx: https://tsx.is",
"dev": true,
"license": "MIT",
"dependencies": {
"@esbuild-kit/core-utils": "^3.3.2",
@@ -980,7 +957,6 @@
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -997,7 +973,6 @@
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1014,7 +989,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1031,7 +1005,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1048,7 +1021,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1065,7 +1037,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1082,7 +1053,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1099,7 +1069,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1116,7 +1085,6 @@
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1133,7 +1101,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1150,7 +1117,6 @@
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1167,7 +1133,6 @@
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1184,7 +1149,6 @@
"cpu": [
"mips64el"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1201,7 +1165,6 @@
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1218,7 +1181,6 @@
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1235,7 +1197,6 @@
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1252,7 +1213,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1286,7 +1246,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1320,7 +1279,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1337,7 +1295,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1354,7 +1311,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1371,7 +1327,6 @@
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1388,7 +1343,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1592,7 +1546,6 @@
"version": "3.9.2",
"resolved": "https://registry.npmjs.org/@petamoriken/float16/-/float16-3.9.2.tgz",
"integrity": "sha512-VgffxawQde93xKxT3qap3OH+meZf7VaSB5Sqd4Rqc+FP5alWbpOyan/7tRbOAvynjpG3GpdtAuGU/NdhQpmrog==",
"devOptional": true,
"license": "MIT"
},
"node_modules/@scalar/core": {
@@ -1682,6 +1635,12 @@
"@types/node": "*"
}
},
"node_modules/@types/express-handlebars": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/@types/express-handlebars/-/express-handlebars-5.3.1.tgz",
"integrity": "sha512-DSzaERLO4gHb8AqnrL58jzSDyT0yDdl6HqDc+bGz1Hf0nrG1FK30nHGzv8NBEGR8QV9eUGB/YaE0Qj3NjF7siw==",
"license": "MIT"
},
"node_modules/@types/fs-extra": {
"version": "11.0.4",
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.4.tgz",
@@ -1754,6 +1713,25 @@
"undici-types": "~6.20.0"
}
},
"node_modules/@types/nodemailer": {
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.17.tgz",
"integrity": "sha512-I9CCaIp6DTldEg7vyUTZi8+9Vo0hi1/T8gv3C89yk1rSAAzoKQ8H8ki/jBYJSFoH/BisgLP8tkZMlQ91CIquww==",
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/nodemailer-express-handlebars": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/@types/nodemailer-express-handlebars/-/nodemailer-express-handlebars-4.0.5.tgz",
"integrity": "sha512-SuSYGNQPGtgMkDlQTO7zacXDENqQR3QXW1Ip5PvvookodvUKCbNVRF1tisY3Bgew1h8Wjfsf6dPQ5E45pJ1bJA==",
"license": "MIT",
"dependencies": {
"@types/express-handlebars": "^5",
"@types/nodemailer": "*"
}
},
"node_modules/@types/normalize-package-data": {
"version": "2.4.4",
"resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz",
@@ -2085,7 +2063,6 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"dev": true,
"license": "MIT"
},
"node_modules/bundle-name": {
@@ -2113,6 +2090,24 @@
"node": ">=6"
}
},
"node_modules/call-bind": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
"integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.0",
"es-define-property": "^1.0.0",
"get-intrinsic": "^1.2.4",
"set-function-length": "^1.2.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/call-bind-apply-helpers": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
@@ -2126,6 +2121,22 @@
"node": ">= 0.4"
}
},
"node_modules/call-bound": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"get-intrinsic": "^1.3.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/callsites": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
@@ -2993,7 +3004,6 @@
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz",
"integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": "*"
@@ -3060,6 +3070,26 @@
"dev": true,
"license": "MIT"
},
"node_modules/deep-equal": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz",
"integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==",
"license": "MIT",
"dependencies": {
"is-arguments": "^1.1.1",
"is-date-object": "^1.0.5",
"is-regex": "^1.1.4",
"object-is": "^1.1.5",
"object-keys": "^1.1.1",
"regexp.prototype.flags": "^1.5.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/default-browser": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz",
@@ -3101,6 +3131,23 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/define-data-property": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
"license": "MIT",
"dependencies": {
"es-define-property": "^1.0.0",
"es-errors": "^1.3.0",
"gopd": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/define-lazy-prop": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz",
@@ -3113,6 +3160,23 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/define-properties": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
"integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
"license": "MIT",
"dependencies": {
"define-data-property": "^1.0.1",
"has-property-descriptors": "^1.0.0",
"object-keys": "^1.1.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -3261,7 +3325,6 @@
"version": "0.30.5",
"resolved": "https://registry.npmjs.org/drizzle-kit/-/drizzle-kit-0.30.5.tgz",
"integrity": "sha512-l6dMSE100u7sDaTbLczibrQZjA35jLsHNqIV+jmhNVO3O8jzM6kywMOmV9uOz9ZVSCMPQhAZEFjL/qDPVrqpUA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@drizzle-team/brocli": "^0.10.2",
@@ -3536,7 +3599,6 @@
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz",
"integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"bin": {
@@ -3575,7 +3637,6 @@
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.6.0.tgz",
"integrity": "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==",
"dev": true,
"license": "MIT",
"dependencies": {
"debug": "^4.3.4"
@@ -3894,7 +3955,6 @@
"version": "11.3.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz",
"integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==",
"dev": true,
"license": "MIT",
"dependencies": {
"graceful-fs": "^4.2.0",
@@ -3936,11 +3996,19 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/functions-have-names": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
"integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/gel": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/gel/-/gel-2.0.1.tgz",
"integrity": "sha512-gfem3IGvqKqXwEq7XseBogyaRwGsQGuE7Cw/yQsjLGdgiyqX92G1xENPCE0ltunPGcsJIa6XBOTx/PK169mOqw==",
"devOptional": true,
"license": "Apache-2.0",
"dependencies": {
"@petamoriken/float16": "^3.8.7",
@@ -3961,7 +4029,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz",
"integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
@@ -3974,7 +4041,6 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz",
"integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==",
"devOptional": true,
"license": "ISC",
"engines": {
"node": ">=16"
@@ -3984,7 +4050,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz",
"integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==",
"devOptional": true,
"license": "ISC",
"dependencies": {
"isexe": "^3.1.1"
@@ -4122,7 +4187,6 @@
"version": "4.10.0",
"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz",
"integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==",
"dev": true,
"license": "MIT",
"dependencies": {
"resolve-pkg-maps": "^1.0.0"
@@ -4381,6 +4445,18 @@
"node": ">=4"
}
},
"node_modules/has-property-descriptors": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
"license": "MIT",
"dependencies": {
"es-define-property": "^1.0.0"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-symbols": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
@@ -4724,6 +4800,31 @@
"node": ">=8"
}
},
"node_modules/int64-buffer": {
"version": "0.99.1007",
"resolved": "https://registry.npmjs.org/int64-buffer/-/int64-buffer-0.99.1007.tgz",
"integrity": "sha512-XDBEu44oSTqlvCSiOZ/0FoUkpWu/vwjJLGSKDabNISPQNZ5wub1FodGHBljRsrR0IXRPq7SslshZYMuA55CgTQ==",
"license": "MIT",
"engines": {
"node": ">= 4.5.0"
}
},
"node_modules/is-arguments": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz",
"integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==",
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"has-tostringtag": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-arrayish": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
@@ -4747,6 +4848,22 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-date-object": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz",
"integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==",
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"has-tostringtag": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-docker": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz",
@@ -4852,6 +4969,24 @@
"node": ">=0.10.0"
}
},
"node_modules/is-regex": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
"integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"gopd": "^1.2.0",
"has-tostringtag": "^1.0.2",
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-stream": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
@@ -5030,7 +5165,6 @@
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"universalify": "^2.0.0"
@@ -5817,6 +5951,31 @@
"node": ">=8"
}
},
"node_modules/object-is": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz",
"integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==",
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.7",
"define-properties": "^1.2.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/object-keys": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/object-treeify": {
"version": "1.1.33",
"resolved": "https://registry.npmjs.org/object-treeify/-/object-treeify-1.1.33.tgz",
@@ -6757,6 +6916,26 @@
"node": ">=8"
}
},
"node_modules/regexp.prototype.flags": {
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
"integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==",
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.8",
"define-properties": "^1.2.1",
"es-errors": "^1.3.0",
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"set-function-name": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@@ -6828,7 +7007,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
"integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
@@ -6965,6 +7143,38 @@
"node": ">=10"
}
},
"node_modules/set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
"license": "MIT",
"dependencies": {
"define-data-property": "^1.1.4",
"es-errors": "^1.3.0",
"function-bind": "^1.1.2",
"get-intrinsic": "^1.2.4",
"gopd": "^1.0.1",
"has-property-descriptors": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/set-function-name": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
"integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
"license": "MIT",
"dependencies": {
"define-data-property": "^1.1.4",
"es-errors": "^1.3.0",
"functions-have-names": "^1.2.3",
"has-property-descriptors": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -6990,7 +7200,6 @@
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz",
"integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -7033,7 +7242,6 @@
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"dev": true,
"license": "MIT",
"dependencies": {
"buffer-from": "^1.0.0",
@@ -7105,6 +7313,18 @@
"integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
"license": "BSD-3-Clause"
},
"node_modules/st-ethernet-ip": {
"version": "2.7.3",
"resolved": "https://registry.npmjs.org/st-ethernet-ip/-/st-ethernet-ip-2.7.3.tgz",
"integrity": "sha512-pc7cjrLwlZGzezuqEThensjk8o9lvI73xlNf4Ufzsfl51Akfe8Td9RdQJPWaAjaCCYV3h0pgRp5NrudgKCMBww==",
"license": "MIT",
"dependencies": {
"dateformat": "^3.0.3",
"deep-equal": "^1.1.1",
"int64-buffer": "^0.99.1007",
"task-easy": "^0.2.0"
}
},
"node_modules/standard-version": {
"version": "9.5.0",
"resolved": "https://registry.npmjs.org/standard-version/-/standard-version-9.5.0.tgz",
@@ -7306,6 +7526,12 @@
"node": ">=8.0.0"
}
},
"node_modules/task-easy": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/task-easy/-/task-easy-0.2.1.tgz",
"integrity": "sha512-VMYezcVhfyaTkc3cWf4sSQG6YgYBdiNCAg4iXuUWRGB7tp7A/rZA9Nter0ZIG5chSoidLS0VWf87koFD9XHwDg==",
"license": "MIT"
},
"node_modules/tedious": {
"version": "18.6.1",
"resolved": "https://registry.npmjs.org/tedious/-/tedious-18.6.1.tgz",
@@ -7988,7 +8214,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
"integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 10.0.0"

View File

@@ -9,7 +9,7 @@
"dev:dbgen": " drizzle-kit generate --config=drizzle-dev.config.ts",
"dev:dbmigrate": " drizzle-kit migrate --config=drizzle-dev.config.ts",
"build": "npm run build:server && npm run build:frontend",
"build:server": "rimraf dist && tsc --build && npm run copy:scripts",
"build:server": "rimraf dist && tsc --build && npm run copy:scripts && xcopy server\\services\\notifications\\utils\\views\\ dist\\server\\services\\notifications\\utils\\views\\ /E /I /Y",
"build:frontend": "cd frontend && npm run build",
"copy:scripts": "tsx server/scripts/copyScripts.ts",
"copy:servers": "xcopy server\\services\\server\\utils\\serverData.json dist\\server\\services\\server\\utils /E /I /Y",
@@ -21,7 +21,8 @@
"deploy": "standard-version --conventional-commits && npm run prodBuild",
"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",
"prodBuild": "npm run v1Build && powershell -ExecutionPolicy Bypass -File server/scripts/build.ps1 -dir \"C:\\Users\\matthes01\\Documents\\lstv2-dev\" && npm run zipServer",
"scriptBuild": "powershell -ExecutionPolicy Bypass -File server/scripts/build.ps1 -dir \"C:\\Users\\matthes01\\Documents\\lstv2-dev\"",
"prodBuild": "npm run v1Build && npm run zipServer",
"commit": "cz",
"prodinstall": "npm i --omit=dev && npm run db:migrate",
"checkupdates": "npx npm-check-updates"
@@ -32,7 +33,7 @@
}
},
"admConfig": {
"build": 84,
"build": 92,
"oldBuild": "backend-0.1.3.zip"
},
"devDependencies": {
@@ -42,12 +43,11 @@
"@types/js-cookie": "^3.0.6",
"@types/mssql": "^9.1.7",
"@types/node": "^22.13.11",
"@types/nodemailer": "^6.4.17",
"@types/pg": "^8.11.11",
"@types/ws": "^8.18.0",
"concurrently": "^9.1.2",
"cz-conventional-changelog": "^3.3.0",
"drizzle-kit": "^0.30.5",
"fs-extra": "^11.3.0",
"standard-version": "^9.5.0",
"tsx": "^4.19.3",
"typescript": "^5.8.2"
@@ -58,13 +58,16 @@
"@hono/zod-openapi": "^0.19.2",
"@scalar/hono-api-reference": "^0.7.2",
"@types/jsonwebtoken": "^9.0.9",
"@types/nodemailer-express-handlebars": "^4.0.5",
"adm-zip": "^0.5.16",
"axios": "^1.8.4",
"bcryptjs": "^3.0.2",
"date-fns": "^4.1.0",
"drizzle-kit": "^0.30.5",
"drizzle-orm": "^0.41.0",
"drizzle-zod": "^0.7.0",
"fast-xml-parser": "^5.0.9",
"fs-extra": "^11.3.0",
"jsonwebtoken": "^9.0.2",
"mssql": "^11.0.1",
"nodemailer": "^6.10.0",
@@ -75,6 +78,7 @@
"pino-pretty": "^13.0.0",
"postgres": "^3.4.5",
"rimraf": "^6.0.1",
"st-ethernet-ip": "^2.7.3",
"ws": "^8.18.1",
"zod": "^3.24.2"
}

View File

@@ -21,7 +21,10 @@ import loggerService from "./services/logger/loggerService.js";
import ocpService from "./services/ocp/ocpService.js";
import { db } from "../database/dbclient.js";
import { settings } from "../database/schema/settings.js";
import { count } from "drizzle-orm";
import os from "os";
import { tryCatch } from "./globalUtils/tryCatch.js";
import { sendEmail } from "./services/notifications/controller/sendMail.js";
import notify from "./services/notifications/notifyService.js";
// create the main prodlogin here
const username = "lst_user";
@@ -29,9 +32,17 @@ const password = "Alpla$$Prod";
export const lstAuth = btoa(`${username}:${password}`);
// checking to make sure we have the settings intialized
const serverIntialized = await db.select({ count: count() }).from(settings);
const { data: settingsData, error: settingError } = await tryCatch(
db.select().from(settings)
);
if (settingError) {
throw Error("Error getting settings from the db. critical error.");
}
const serverIntialized: any = settingsData;
export const installed =
serverIntialized[0].count === 0 && process.env.NODE_ENV !== "development"
serverIntialized.length === 0 && process.env.NODE_ENV !== "development"
? false
: true;
createLog("info", "LST", "server", `Server is installed: ${installed}`);
@@ -88,6 +99,7 @@ const routes = [
printers,
loggerService,
ocpService,
notify,
] as const;
const appRoutes = routes.forEach((route) => {
@@ -146,7 +158,18 @@ process.on("SIGTERM", async () => {
process.on("uncaughtException", async (err) => {
console.log("Uncaught Exception:", err);
//await closePool();
process.exit(1);
const emailData = {
email: "blake.matthes@alpla.com", // should be moved to the db so it can be reused.
subject: `${os.hostname()} has just encountered a crash.`,
template: "serverCrash",
context: {
error: err,
plant: `${os.hostname()}`,
},
};
await sendEmail(emailData);
//process.exit(1);
});
process.on("beforeExit", async () => {

View File

@@ -1,7 +0,0 @@
import {createLog} from "../../logger/logger.js";
export const sendEmail = async () => {
createLog("info", "lst", "general", "Preparing to send an email");
// settings
};

View File

@@ -0,0 +1,102 @@
import { ConsoleLogWriter } from "drizzle-orm";
import { prodEndpointCreation } from "../../../globalUtils/createUrl.js";
import { createLog } from "../../logger/logger.js";
import { query } from "../../sqlServer/prodSqlServer.js";
import { labelData } from "../../sqlServer/querys/materialHelpers/labelInfo.js";
import axios from "axios";
import { laneInfo } from "../../sqlServer/querys/materialHelpers/laneInfo.js";
import { tryCatch } from "../../../globalUtils/tryCatch.js";
type Data = {
runningNr: string;
laneName: string;
};
export const returnMaterial = async (data: Data, prod: any) => {
const { runningNr, laneName } = data;
// replace the rn
const rnReplace = labelData.replaceAll("[rn]", runningNr);
// get the lane id by name
const laneQuery = laneInfo.replaceAll("[laneName]", laneName);
let barcode;
// get the barcode from the running number
try {
barcode = await query(rnReplace, "labelData");
} catch (error) {
console.log(error);
createLog(
"error",
prod.user.username,
"logistics",
`Error getting barcode: ${error}`
);
}
const { data: laneData, error: laneError } = await tryCatch(
query(laneQuery, "laneInfo")
);
if (laneError) {
return {
success: false,
message:
"The lane you entered is either deactivated or dose not exist.",
laneError,
};
}
if (!laneData) {
return {
success: false,
message:
"The lane you entered is either deactivated or dose not exist.",
};
}
if (laneData.length === 0) {
return {
success: false,
message:
"The lane you entered is either deactivated or dose not exist.",
};
}
if (barcode.length === 0) {
return {
success: false,
message: "The running number you've is not in stock.",
};
//throw Error("The provided runningNr is not in stock");
}
// create the url to post
const url = await prodEndpointCreation(
"/public/v1.0/IssueMaterial/ReturnPartiallyConsumedManualMaterial"
);
const returnSomething = {
laneId: laneData[0]?.laneID,
barcode: barcode[0]?.barcode,
};
try {
const results = await axios.post(url, returnSomething, {
headers: {
"Content-Type": "application/json",
Authorization: `Basic ${prod.user.prod}`,
},
});
//console.log(results);
return {
success: true,
message: "Material was returned",
status: results.status,
};
} catch (error: any) {
return {
success: false,
status: 200,
message: error.response?.data.errors[0].message,
};
}
};

View File

@@ -1,9 +1,10 @@
import { OpenAPIHono } from "@hono/zod-openapi";
import comsumeMaterial from "./route/consumeMaterial.js";
import returnMat from "./route/returnMaterial.js";
const app = new OpenAPIHono();
const routes = [comsumeMaterial] as const;
const routes = [comsumeMaterial, returnMat] as const;
// app.route("/server", modules);
const appRoutes = routes.forEach((route) => {

View File

@@ -0,0 +1,70 @@
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { authMiddleware } from "../../auth/middleware/authMiddleware.js";
import { apiHit } from "../../../globalUtils/apiHits.js";
import { verify } from "hono/jwt";
import { returnMaterial } from "../controller/returnMaterial.js";
const app = new OpenAPIHono();
const responseSchema = z.object({
success: z.boolean().optional().openapi({ example: true }),
message: z.string().optional().openapi({ example: "user access" }),
});
app.openapi(
createRoute({
tags: ["logistics"],
summary: "Retrns material based on its running number and laneName",
method: "post",
path: "/return",
middleware: authMiddleware,
description:
"Provided a running number and Lane to return the material.",
responses: {
200: {
content: { "application/json": { schema: responseSchema } },
description: "stopped",
},
400: {
content: { "application/json": { schema: responseSchema } },
description: "Failed to stop",
},
401: {
content: { "application/json": { schema: responseSchema } },
description: "Failed to stop",
},
},
}),
async (c) => {
apiHit(c, { endpoint: "api/sqlProd/close" });
const authHeader = c.req.header("Authorization");
const token = authHeader?.split("Bearer ")[1] || "";
try {
const payload = await verify(token, process.env.JWT_SECRET!);
try {
//return apiReturn(c, true, access?.message, access?.data, 200);
const data = await c.req.json();
const consume = await returnMaterial(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
);
}
} catch (error) {
return c.json({ success: false, message: "Unauthorized" }, 401);
}
}
);
export default app;

View File

@@ -0,0 +1,144 @@
import { tryCatch } from "../../../globalUtils/tryCatch.js";
import { db } from "../../../../database/dbclient.js";
import { settings } from "../../../../database/schema/settings.js";
import nodemailer from "nodemailer";
import type { Transporter } from "nodemailer";
import type SMTPTransport from "nodemailer/lib/smtp-transport/index.js";
import type Mail from "nodemailer/lib/mailer/index.js";
import type { Address } from "nodemailer/lib/mailer/index.js";
import path from "path";
import { fileURLToPath } from "url";
import hbs from "nodemailer-express-handlebars";
import { promisify } from "util";
import { createLog } from "../../logger/logger.js";
interface HandlebarsMailOptions extends Mail.Options {
template: string;
context: Record<string, unknown>; // Use a generic object for context
}
interface EmailData {
email: string;
subject: string;
template: string;
context: [];
}
export const sendEmail = async (data: any): Promise<any> => {
let transporter: Transporter;
let fromEmail: string | Address;
const { data: settingData, error: settingError } = await tryCatch(
db.select().from(settings)
);
if (settingError) {
return {
success: false,
message: "There was an error getting the settings.",
settingError,
};
}
// get the plantToken
const server = settingData.filter((n) => n.name === "server");
if (
server[0].value === "localhost" &&
process.env.EMAIL_USER &&
process.env.EMAIL_PASSWORD
) {
transporter = nodemailer.createTransport({
service: "gmail",
auth: {
user: process.env.EMAIL_USER,
pass: process.env.EMAIL_PASSWORD,
},
//debug: true,
});
// update the from email
fromEmail = process.env.EMAIL_USER;
} else {
// convert to the correct plant token.
const plantToken = settingData.filter((s) => s.name === "plantToken");
let host = `${plantToken[0].value}-smtp.alpla.net`;
const testServers = ["test1", "test2", "test3"];
if (testServers.includes(plantToken[0].value)) {
host = "USMCD1-smtp.alpla.net";
}
if (plantToken[0].value === "usiow2") {
host = "USIOW1-smtp.alpla.net";
}
transporter = nodemailer.createTransport({
host: host,
port: 25,
rejectUnauthorized: false,
//secure: false,
// auth: {
// user: "alplaprod",
// pass: "obelix",
// },
debug: true,
} as SMTPTransport.Options);
// update the from email
fromEmail = `noreply@alpla.com`;
}
// creating the handlbar options
const viewPath = path.resolve(
path.dirname(fileURLToPath(import.meta.url)),
"../utils/views/"
);
const handlebarOptions = {
viewEngine: {
extname: ".hbs",
//layoutsDir: path.resolve(viewPath, "layouts"), // Path to layouts directory
defaultLayout: "", // Specify the default layout
partialsDir: viewPath,
},
viewPath: viewPath,
extName: ".hbs", // File extension for Handlebars templates
};
transporter.use("compile", hbs(handlebarOptions));
const mailOptions: HandlebarsMailOptions = {
from: fromEmail,
to: data.email,
subject: data.subject,
//text: "You will have a reset token here and only have 30min to click the link before it expires.",
//html: emailTemplate("BlakesTest", "This is an example with css"),
template: data.template, // Name of the Handlebars template (e.g., 'welcome.hbs')
context: data.context,
};
// now verify and send the email
const sendMailPromise = promisify(transporter.sendMail).bind(transporter);
try {
// Send email and await the result
const info = await sendMailPromise(mailOptions);
createLog(
"info",
"notification",
"system",
`Email was sent to: ${data.email}`
);
return { success: true, message: "Email sent.", data: info };
} catch (err) {
console.log(err);
createLog(
"error",
"notification",
"system",
`Error sending Email: ${JSON.stringify(err)}`
);
return { success: false, message: "Error sending email.", error: err };
}
};

View File

@@ -0,0 +1,19 @@
import { OpenAPIHono } from "@hono/zod-openapi";
import sendemail from "./routes/sendMail.js";
const app = new OpenAPIHono();
const routes = [sendemail] as const;
const appRoutes = routes.forEach((route) => {
app.route("/notify", route);
});
app.all("/notify/*", (c) => {
return c.json({
success: false,
message: "you have encounted a notication route that dose not exist.",
});
});
export default app;

View File

@@ -0,0 +1,73 @@
// an external way to creating logs
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { responses } from "../../../globalUtils/routeDefs/responses.js";
import { authMiddleware } from "../../auth/middleware/authMiddleware.js";
import { sendEmail } from "../controller/sendMail.js";
import { tryCatch } from "../../../globalUtils/tryCatch.js";
const app = new OpenAPIHono({ strict: false });
const EmailSchema = z
.object({
email: z.string().email().openapi({ example: "smith@example.come" }),
subject: z.string().openapi({ example: "Welcome to LST" }),
template: z.string().openapi({ example: "exampleTemplate" }),
context: z
.object({
name: z.string().optional(),
score: z.string().optional(),
})
.optional()
.openapi({}),
})
.openapi("User");
app.openapi(
createRoute({
tags: ["server"],
summary: "Returns current active lots that are tech released",
method: "post",
path: "/sendmail",
middleware: authMiddleware,
request: {
body: {
content: {
"application/json": { schema: EmailSchema },
},
},
},
responses: responses(),
}),
async (c) => {
const { data: bodyData, error: bodyError } = await tryCatch(
c.req.json()
);
if (bodyError) {
return c.json(
{
success: false,
message: "There was an error sending the email",
data: bodyError,
},
400
);
}
const { data: emailData, error: emailError } = await tryCatch(
sendEmail(bodyData)
);
if (emailError) {
return c.json({
success: false,
message: "There was an error sending the email",
data: emailError,
});
}
return c.json({
success: emailData.success,
message: emailData.message,
data: emailData.data,
});
}
);
export default app;

View File

@@ -0,0 +1,33 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Order Summary</title>
{{> styles}}
{{!-- <link rel="stylesheet" href="styles/styles.css" /> --}}
</head>
<body>
<h1>{{name}}, your Order Summary</h1>
<p>All,
This is an example of the test email
</p>
<table>
<thead>
<tr>
<th>Item Name</th>
<th>Quantity</th>
<th>Price</th>
</tr>
</thead>
<tbody>
{{#each items}}
<tr>
<td>{{name}}</td>
<td>{{quantity}}</td>
<td>{{price}}</td>
</tr>
{{/each}}
</tbody>
</table>
</body>
</html>

View File

@@ -0,0 +1,35 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
{{!--<title>Order Summary</title> --}}
{{> styles}}
<style>
pre {
background-color: #f8f9fa;
color: #d63384;
padding: 10px;
border-radius: 5px;
white-space: pre-wrap;
font-family: monospace;
}
</style>
{{!-- <link rel="stylesheet" href="styles/styles.css" /> --}}
</head>
<body>
<h3>{{plant}},<br/> Has encountered an unexpected error.</h1>
<p>
Please see below the stack error from the crash.
</p>
<hr/>
<div>
<h3>Error Message: </h3>
<p>{{error.message}}</p>
</div>
<hr/>
<div>
<h3>Stack trace</h3>
<pre>{{{error.stack}}}</pre>
</div>
</body>
</html>

View File

@@ -0,0 +1,6 @@
<style>
table { width: 100%; background-color: #ffffff; border-collapse: collapse;
border-width: 2px; border-color: #14BDEA; border-style: solid; color:
#000000; } th, td { border: 1px solid #ddd; padding: 8px; } th {
background-color: #f4f4f4; }
</style>

View File

@@ -0,0 +1,19 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
{{!--<title>Order Summary</title> --}}
{{> styles}}
{{!-- <link rel="stylesheet" href="styles/styles.css" /> --}}
</head>
<body>
<p>All,<br/>
There has been {{count}} manual prints in the last {{hours}}.<br/>
Please consider checking the reason for this.<br/>
Thank you,<br/>
LST
</p>
</body>
</html>

View File

@@ -20,7 +20,7 @@ export const getInfo = async () => {
return { ...o, waitingFor: diff };
});
createLog(
"info",
"debug",
"ocme",
"ocme",
`There are ${ocmeInfo.length} pallet(s) to be picked up.`

View File

@@ -0,0 +1,89 @@
import axios from "axios";
import { prodEndpointCreation } from "../../../../globalUtils/createUrl.js";
import { lstAuth } from "../../../../index.js";
import { createLog } from "../../../logger/logger.js";
import { db } from "../../../../../database/dbclient.js";
import { prodlabels } from "../../../../../database/schema/prodLabels.js";
import { eq, sql } from "drizzle-orm";
export const bookInLabel = async (data: any) => {
// update sscc so we can book in
const SSCC = data.SSCC.slice(2);
// api url
const url = await prodEndpointCreation("public/v1.0/Warehousing/BookIn");
// create bookin
const newBookin = {
scannerId: 777,
sscc: SSCC,
};
try {
const res = await axios.post(url, newBookin, {
headers: {
Authorization: `Basic ${lstAuth}`,
accept: "text/plain",
},
});
if (res.data.Result !== 0) {
createLog(
"error",
"labeling",
"ocp",
`${data.printer.name}, Error:${res.data.Message}`
);
//printerUpdate(data.printer, 7, "Error while booking in.");
return {
success: false,
message: "There was an error booking in the label.",
data: res.data,
};
}
// update the label.
try {
await db
.update(prodlabels)
.set({
status: "Booked in",
upd_date: sql`NOW()`,
})
.where(
eq(prodlabels.runningNr, parseInt(data.SSCC.slice(10, -1)))
);
} catch (error) {
createLog(
"error",
"labeling",
"ocp",
`Error creating new runningNumber in the DB.`
);
}
// label was booked in
createLog(
"info",
"labeling",
"ocp",
`${parseInt(data.SSCC.slice(10, -1))}, was just booked in`
);
return {
success: true,
message: `${parseInt(data.SSCC.slice(10, -1))}, was just booked in`,
};
} catch (error) {
createLog(
"error",
"labeling",
"ocp",
`${data.printer.name}, "Error: ${error}`
);
return {
success: false,
message: "There was an error booking in the label.",
data: error,
};
}
};

View File

@@ -0,0 +1,158 @@
import { eq, gte, sql } from "drizzle-orm";
import { db } from "../../../../../database/dbclient.js";
import { printers } from "../../../../../database/schema/printers.js";
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
import { createLog } from "../../../logger/logger.js";
import { prodEndpointCreation } from "../../../../globalUtils/createUrl.js";
import { settings } from "../../../../../database/schema/settings.js";
import { lstAuth } from "../../../../index.js";
import axios from "axios";
import { prodlabels } from "../../../../../database/schema/prodLabels.js";
export const createLabel = async (data: any, userPrinted: any) => {
createLog("info", "labeling", "ocp", `Label being created`);
const { data: printer, error: printerError } = await tryCatch(
db
.select()
.from(printers)
.where(eq(printers.humanReadableId, data.printerID))
);
const { data: settingsData, error: settingsError } = await tryCatch(
db.select().from(settings)
);
if (printerError) {
return {
success: false,
message: "There was an error getting the printer.",
printerError,
};
}
if (settingsError) {
return {
success: false,
message: "There was an error getting the printer.",
settingsError,
};
}
const url = await prodEndpointCreation(
"/public/v1.0/Warehousing/GenerateAndPrintLabelExtended"
);
const plantToken = settingsData.filter((n) => n.name === "plantToken");
const newLabel = {
scannerId: 99,
lotNr: data.LOT,
machineId: data.machineID,
printerId: data.printerID,
//layoutId: cartonCustomers.includes(data.CustomerId.toString()) ? data.cartonLabel : data.palletLabel,
layoutId:
plantToken[0].value === "usksc1"
? data.cartonLabel
: data.palletLabel,
//numberOfCopies: cartonCustomers.includes(data.CustomerId.toString()) ? data.cartonCopies : data.pallerCopies,
numberOfCopies:
plantToken[0].value === "usksc1"
? data.cartonCopies
: data.pallerCopies,
};
// create the label
// create the label with the data we have
try {
const res = await axios.post(url, newLabel, {
headers: {
Authorization: `Basic ${lstAuth}`,
"Content-Type": "application/json",
},
});
// error handling
if (res.data.Result != 0) {
createLog(
"error",
"labeling",
"ocp",
`${data.MachineDescription}, has an error while printing: Error: ${res.data.Message}.`
);
return {
success: false,
mesasge: `${data.MachineDescription}, has an error while printing`,
data: res.data,
};
}
// save the data to lst db (only saved for x time see the db clean up functions)
let newlabel = res.data;
try {
await db.insert(prodlabels).values({
printerID: parseInt(printer[0]?.humanReadableId!, 10),
runningNr: parseInt(newlabel.SSCC.slice(10, -1)),
printerName: printer[0].name.toLowerCase(),
line: data.MachineLocation,
status: "printed",
add_user: userPrinted || "LST_System",
});
} catch (error) {
createLog(
"error",
"labeling",
"ocp",
`Error creating new runningNumber in the DB.`
);
}
createLog(
"info",
"labeling",
"ocp",
`New label was created for: ${
data.MachineDescription
}, Running number: ${parseInt(newlabel.SSCC.slice(10, -1))}`
);
const returnData = {
...newlabel,
printer,
};
// check if we can remove labels or not
deleteLabels();
return { sucess: true, message: "Label created", data: returnData }; // returning label data to be able to book in if active
} catch (error) {
createLog(
"info",
"labeling",
"ocp",
`${printer[0].name}, "Error: ${error}`
);
return {
success: false,
message: "There was an error creating the label",
data: error,
};
}
};
// run the label delete process we want to delate them older than 90 days right now
const deleteLabels = async () => {
/**
* Deletes labels older than 90 days from lst... all label data can be found in alpla prod.
*/
try {
await db
.delete(prodlabels)
.where(
gte(prodlabels.upd_date, sql.raw(`NOW() - INTERVAL '90 days'`))
);
} catch (error) {
createLog(
"error",
"labeling",
"ocp",
`Error deleting labels older than 90 days`
);
}
};

View File

@@ -20,7 +20,7 @@ export const getLabels = async (hours: string) => {
return {
success: false,
message: "There was an error getting the labels",
data: labelError,
data: [labelError],
};
}

View File

@@ -0,0 +1,236 @@
import { eq } from "drizzle-orm";
import { db } from "../../../../../database/dbclient.js";
import { printers } from "../../../../../database/schema/printers.js";
import { settings } from "../../../../../database/schema/settings.js";
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
import { createLog } from "../../../logger/logger.js";
import { getLots } from "../lots/lots.js";
import { getMac } from "../specialProcesses/utils/getMachineId.js";
import { billingCheck } from "../specialProcesses/billingCheck/billingCheck.js";
import { isMainMatStaged } from "../materials/mainMaterial.js";
import { firstLotLabel } from "../specialProcesses/lotChangeLabel/lotCHangeLabel.js";
import { prolinkCheck } from "../lots/prolinkCheck.js";
import { createLabel } from "./createLabel.js";
import { bookInLabel } from "./bookIn.js";
import { delieryInhouse } from "../specialProcesses/inhouse/inhouseDelivery.js";
interface Printer {
name: string;
// Add any other expected properties
}
export const labelingProcess = async ({
line = null as string | null,
printer = null as Printer | null,
userPrinted = null,
rfidTag = null,
} = {}) => {
/**
* Creates a label once all logic is passed
*/
let filteredLot: any = [];
createLog("debug", "labeling", "ocp", `Starting labeling process`);
const { data: settingData, error: settingError } = await tryCatch(
db.select().from(settings)
);
if (settingError) {
return {
success: false,
message: "There was an error getting the settings.",
settingError,
};
}
// get the plantToken
const plantToken = settingData.filter((n) => n.name === "plantToken");
// get the current lots
const lots = await getLots();
// if we got a line passed over we need to get the machine id from this.
if (line) {
const macId = await getMac(line);
// filter out the lot for the line
filteredLot = lots.data.filter((l: any) => l.machineId === macId);
if (filteredLot.length === 0) {
createLog(
"error",
"labeling",
"ocp",
`There is not a lot assigned to ${macId[0].Name}.`
);
return {
success: false,
message: `There is not a lot assigned to ${macId[0].Name}.`,
};
}
}
// if we came from a printer
if (printer) {
// filter the lot based on the printerID
// console.log(printer);
filteredLot = lots.data.filter((l: any) => l.printerID === printer);
if (filteredLot.length === 0) {
// console.log(`There is not a lot assigned to ${printer.name}`);
createLog(
"error",
"labeling",
"ocp",
`There is not a lot assigned to ${printer.name}`
);
//printerUpdate(printer, 7, `There is no lot assigned to this printer.`);
return {
success: false,
message: `There is not a lot assigned to ${printer.name}.`,
};
}
}
/**
*
* The checks we do before we can actually print a label will take place meow.
*
*/
// if the plant does not want to have dual printing and we have >2 assigned well return and send error.
let dualPrinting = settingData.filter((d) => d.name === "dualPrinting")[0]
?.value;
if (filteredLot.length > 1 && dualPrinting === "0") {
createLog(
"error",
"labeling",
"ocp",
`${printer?.name}, has more than one lot assigned to it, and dual printing shut off.`
);
return {
success: false,
message: `${printer?.name}, has more than one lot assigned to it, and dual printing shut off.`,
};
}
if (filteredLot.length > 1 && dualPrinting === "1") {
// send over for dual printing processing
createLog(
"info",
"labeling",
"ocp",
`${printer?.name}, being sent over for dual printing processing.`
);
// process what line to print the label for and return the lot info and change filteredLot to returned one.
//filteredLot = await dualPrintingProcess(filteredLot);
}
// if there are more than 2 lots it might be an auto labeler, autolabeler will be defined by its id for now only dayton
if (filteredLot.length > 2 && plantToken[0].value !== "usday1") {
createLog(
"error",
"labeling",
"ocp",
`${printer?.name}, has more than 2 lot assigned to it, and not in ${plantToken[0].value}`
);
return {
success: false,
message: `${printer?.name}, has more than 2 lot assigned to it, and not in ${plantToken[0].value}`,
};
}
// special process for florence
const isBillingTime = await billingCheck();
if (isBillingTime) {
// billing is inside the window we dont want to bill now.
return {
success: false,
message: "Billing time cant print.",
};
}
// check mm is good
const mmStaged = await isMainMatStaged(filteredLot[0]);
if (!mmStaged) {
createLog(
"error",
"labeling",
"ocp",
`Main material is not prepaired for lot ${filteredLot[0].lot}`
);
return;
}
// comment only but will check for color
createLog(
"info",
"labeling",
"ocp",
`Remaining pallets for: ${filteredLot[0].MachineDescription} is ${filteredLot[0].Remaining}`
);
// do we want to over run
if (filteredLot[0].overPrinting === "no" && filteredLot[0].Remaining <= 0) {
createLog(
"error",
"labeling",
"ocp",
`Over Printing on ${filteredLot[0].MachineDescription} is not allowed please change the lot`
);
// for slc we want to run the first label for henkel
firstLotLabel(filteredLot[0]);
return {
success: false,
message: `Over Printing on ${filteredLot[0].MachineDescription} is not allowed please change the lot`,
};
}
// prolink check by lot
const prolink = await prolinkCheck(filteredLot[0].lot);
if (!prolink) {
//console.error(`Prolink does not match for ${filteredLot[0].MachineDescription}`);
createLog(
"error",
"labeling",
"ocp",
`Prolink does not match for ${filteredLot[0].MachineDescription}`
);
return;
}
createLog("info", "labeling", "ocp", `Is prolink good? ${prolink}`);
// create the label
const label = await createLabel(filteredLot[0], userPrinted);
if (!label.success) {
return { sucess: false, message: label.message, data: label.data };
}
// send over to be booked in if we can do it.
const bookin = settingData.filter((s) => s.name === "bookin");
if (bookin[0].value === "1") {
const book = await bookInLabel(label.data);
} else {
createLog("info", "labeling", "ocp", "Bookin is turned off.");
// will add later!!! :P
}
// inhouse - if the inhouse funtion is turned on we will deliver to inhouse as long as we did not hit an error state
const inhouseDelivery = settingData.filter(
(s) => s.name === "inhouseDelivery"
);
if (inhouseDelivery[0].value === "1") {
const deliverPallet = await delieryInhouse(label);
}
return {
success: true,
message: "Label fully processed.",
data: label.data,
};
};

View File

@@ -0,0 +1,38 @@
import { createLog } from "../../../logger/logger.js";
import { query } from "../../../sqlServer/prodSqlServer.js";
import { mmQuery } from "../../../sqlServer/querys/ocp/mainMaterial.js";
export const isMainMatStaged = async (lot: any) => {
// make staged false by deefault and error logged if theres an issue
let isStaged = false;
// strangly the lot is not always sending over in slc so adding this in for now to see what line is cauing this issue
if (!lot) {
return isStaged;
}
const updateQuery = mmQuery.replaceAll("[lotNumber]", lot.lot);
try {
const res = await query(updateQuery, "Main Material Check");
createLog(
"info",
"mainMaterial",
"ocp",
`MainMaterial results: ${JSON.stringify(res)}`
);
if (res[0].Staged >= 1) {
isStaged = true;
}
} catch (err) {
createLog(
"error",
"mainMaterial",
"ocp",
`Error from running the Main Material query: ${err}`
);
}
return isStaged;
};

View File

@@ -73,7 +73,7 @@ export const updatePrinters = async () => {
);
}
createLog(
"info",
"debug",
"lst",
"ocp",
`${prodPrinterInfo[i].name} were just added/updated.`

View File

@@ -0,0 +1,54 @@
import { eq } from "drizzle-orm";
import { db } from "../../../../../../database/dbclient.js";
import { settings } from "../../../../../../database/schema/settings.js";
import { tryCatch } from "../../../../../globalUtils/tryCatch.js";
import { createLog } from "../../../../logger/logger.js";
const st = 5;
const sm = 55;
const et = 6;
const em = 5;
export const billingCheck = async () => {
const now = new Date();
const startTime = new Date();
const endTime = new Date();
let isOutsideBilling = false;
const { data, error } = await tryCatch(db.select().from(settings));
if (error) {
return { success: false, message: "Error in getting settings." };
}
const plant = data.filter((n) => n.name === "plantToken");
// set everything up
startTime.setHours(st, sm, 0, 0);
endTime.setHours(et, em, 0, 0);
if (plant[0].value === "usflo1") {
if (now >= startTime && now <= endTime) {
createLog(
"warn",
"specialProcess",
"ocp",
`You are inside the billing window no labels will print! please wait`
);
isOutsideBilling = true;
} else {
createLog(
"info",
"specialProcess",
"ocp",
"Out side billing window ok to print"
);
}
} else {
createLog(
"debug",
"specialProcess",
"ocp",
"This plant dose not check for billing"
);
}
return isOutsideBilling;
};

View File

@@ -0,0 +1,76 @@
import { Controller, Tag } from "st-ethernet-ip";
import { createLog } from "../../../../logger/logger.js";
import { labelerTagRead } from "./plcTags/labelerTag.js";
import { palletSendTag } from "./plcTags/palletSendTag.js";
let PLC = new Controller();
let isDycoRunning = false;
// PLC address
let plcAddress = "10.44.5.4";
// Initialize the interval variable outside the function
let plcCycle: any;
let plcInterval = 500;
// Create Tag Instances
const labelerTag: any = new Tag("labeler.line_info");
const palletSend = new Tag("Zone_6.Ready_to_Send");
const strapperError = new Tag("Zone_3.Strapper_Faulted");
export const dycoConnect = async () => {
// if we crash or start over reset the timers so we dont get duplicates
clearInterval(plcCycle);
if (isDycoRunning)
return { success: false, message: "Dyco is already connected." };
// Remove all listeners before adding a new one to prevent memory leaks
PLC.removeAllListeners("error");
try {
await PLC.connect(plcAddress, 0).then(async () => {
createLog("info", "dyco", "ocp", `We are connected to the dyco.`);
isDycoRunning = true;
let buffer = "";
plcCycle = setInterval(async () => {
await PLC.readTag(labelerTag);
await PLC.readTag(palletSend);
// send the labeler tag data over
labelerTagRead(labelerTag);
// send the end of line check over.
palletSendTag(palletSend);
}, 500);
});
} catch (error) {
createLog(
"error",
"dyco",
"ocp",
`There was an error in the dyco: ${error}`
);
isDycoRunning = false;
}
};
export const closeDyco = async () => {
if (!isDycoRunning)
return { success: false, message: "Dyco is not connected." };
console.log(`Closing the connection`);
try {
await PLC.disconnect();
isDycoRunning = false;
return {
success: true,
message: "Dyco Connection is now closed.",
};
} catch (error) {
console.log(error);
return {
success: false,
message: "There was an error closing the dyco connection.",
};
}
};

View File

@@ -0,0 +1,66 @@
import { db } from "../../../../../../../database/dbclient.js";
import { settings } from "../../../../../../../database/schema/settings.js";
import { tryCatch } from "../../../../../../globalUtils/tryCatch.js";
import { createLog } from "../../../../../logger/logger.js";
import { readTags } from "../../../../../rfid/controller/readTags.js";
import { labelingProcess } from "../../../labeling/labelProcess.js";
let lastProcessedTimestamp = 0;
export const labelerTagRead = async (tagData: any) => {
/**
* Reads the tag data from the Dyco PLC and processes it based on the feedback.
*/
// Convert tag data buffer to a string and extract numeric values
const buffer = Buffer.from(tagData.value);
const numericString = buffer.toString("utf8").replace(/[^0-9#]/g, "");
// Ignore empty or invalid tag data
if (numericString === "#") {
return;
}
const tagTime = new Date(tagData.state.timestamp).getTime();
// get the settings
const { data: settingData, error: settingError } = await tryCatch(
db.select().from(settings)
);
if (settingError) {
createLog(
"error",
"dyco",
"ocp",
"There was an error getting the settings"
);
return;
}
// check the dyco settings
const dycoPrint = settingData.filter((n) => n.name === "dycoPrint");
// Only process if this is a new timestamp within the last 5 seconds
if (tagTime !== lastProcessedTimestamp && Date.now() - tagTime <= 5000) {
lastProcessedTimestamp = tagTime;
//console.log(numericString, tagData.state.timestamp);
if (dycoPrint[0].value === "1") {
createLog("info", "dyco", "ocp", "Dyco will be printing the label");
// send over to print.
labelingProcess({ line: numericString });
}
if (dycoPrint[0].value === "0") {
createLog(
"info",
"dyco",
"ocp",
"Rfid system is contorlling the printing"
);
// trigger the reader so we can get the label from the tag readers.
await readTags("wrapper1");
}
}
};
/**
* setting to switch between rfid and dyco labeling
*/

View File

@@ -0,0 +1,54 @@
import { createLog } from "../../../../../logger/logger.js";
import { pickedup } from "../../../../../ocme/controller/pickedup.js";
import { triggerScanner } from "../../../../../ocme/controller/triggerCamera.js";
let lastProcessedTimestamp = 0;
export const palletSendTag = async (tagData: any) => {
/**
* Reads the tag data from the Dyco PLC and processes it based on the feedback.
* We will only trigger the camera and removal of pending tags
*/
const tagTime = new Date(tagData.state.timestamp).getTime();
// Only process if this is a new timestamp within the last 5 seconds
if (
tagTime !== lastProcessedTimestamp &&
Date.now() - tagTime <= 5000 &&
tagData.value
) {
lastProcessedTimestamp = tagTime;
//console.log(tagData.state.timestamp);
createLog(
"info",
"dyco",
"ocp",
`Station 6 is ${tagData.value ? "full" : "empty"}`
);
// take the picture
setTimeout(async () => {
const scan: any = await triggerScanner();
if (!scan.success) {
createLog(
"error",
"dyco",
"ocp",
`Scanner failed to take a picture trying one more time in 10 seconds`
);
setTimeout(async () => {
await triggerScanner();
}, 10 * 1000);
}
}, 15 * 1000);
}
if (
tagTime !== lastProcessedTimestamp &&
Date.now() - tagTime <= 5000 &&
!tagData.value
) {
await pickedup({ runningNr: 1234, all: true });
}
};

View File

@@ -0,0 +1,91 @@
import axios from "axios";
import { prodEndpointCreation } from "../../../../../globalUtils/createUrl.js";
import { lstAuth } from "../../../../../index.js";
import { createLog } from "../../../../logger/logger.js";
import { db } from "../../../../../../database/dbclient.js";
import { prodlabels } from "../../../../../../database/schema/prodLabels.js";
import { eq, sql } from "drizzle-orm";
export const delieryInhouse = async (data: any) => {
// update sscc so we can book in
const SSCC = data.SSCC.slice(2);
// api url
const url = await prodEndpointCreation(
"/public/v1.0/Warehousing/InhouseDelivery"
);
// create bookin
const newDelivery = {
scannerId: 99,
sscc: SSCC,
};
try {
const res = await axios.post(url, newDelivery, {
headers: {
Authorization: `Basic ${lstAuth}`,
accept: "text/plain",
},
});
if (res.data.Result !== 0) {
createLog(
"error",
"labeling",
"ocp",
`${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.`,
data: res.data,
};
} // label was just delivered
createLog(
"info",
"labeling",
"ocp",
`${parseInt(data.SSCC.slice(10, -1))}, was just delivered`
);
try {
await db
.update(prodlabels)
.set({
status: "Delivered",
upd_date: sql`NOW()`,
})
.where(
eq(prodlabels.runningNr, parseInt(data.SSCC.slice(10, -1)))
);
} catch (error) {
createLog(
"error",
"labeling",
"ocp",
`Error updating ${parseInt(data.SSCC.slice(10, -1))} in the DB.`
);
return {
success: true,
message: `Error updating ${parseInt(
data.SSCC.slice(10, -1)
)} in the DB.`,
data: error,
};
}
} catch (error) {
createLog(
"error",
"labeling",
"ocp",
`${data.printer.name}, "Error: ${error}`
);
return {
success: true,
message: `Error deliverying ${parseInt(data.SSCC.slice(10, -1))}.`,
data: error,
};
}
};

View File

@@ -0,0 +1,72 @@
import { db } from "../../../../../../database/dbclient.js";
import { settings } from "../../../../../../database/schema/settings.js";
import { tryCatch } from "../../../../../globalUtils/tryCatch.js";
import { createLog } from "../../../../logger/logger.js";
import { query } from "../../../../sqlServer/prodSqlServer.js";
export const firstLotLabel = async (lot: any) => {
/*
currently this is only requested by slc
when a lot is finished and not set to over run we will trigger this function to insert data into the custom T_firstLotLabel table.
in nice label we look for unique id to run the process and then if the add date is older than 7 days we delete it for tracablility purpose.
we will also only do this for specific customers currently henkel is the requested.
*/
/* work on the server side
new table created in the _cus db
CREATE TABLE T_firstLotLabel
(
ID INT IDENTITY(1,1) PRIMARY KEY,
printerName varchar(max),
add_date datetime
-- Add other columns here as needed
);
the nicelabel trigger to be activated.
*/
const { data: settingData, error: settingError } = await tryCatch(
db.select().from(settings)
);
if (settingError) {
return {
success: false,
message: "There was an error getting the settings.",
settingError,
};
}
// get the plantToken
const plantToken = settingData.filter((n) => n.name === "plantToken");
createLog(
"info",
"ocp",
"ocp",
`Checking if we can create the first label lot.`
);
if (plantToken[0].value === "usslc1") {
const newLabel = `insert into T_firstLotLabel (printerName, add_date) VALUES('${lot.PrinterName}', getdate())`;
// if (lot.CustomerId === 40) {
createLog(
"info",
"ocp",
"ocp",
`Creating first lot label for ${lot.MachineDescription}`
);
await query(newLabel, "newLotLabel");
createLog(
"info",
"ocp",
"ocp",
`Was created for ${lot.MachineDescription}`
);
//}
} else {
return;
}
};

View File

@@ -0,0 +1,27 @@
import { db } from "../../../../../../database/dbclient.js";
import { settings } from "../../../../../../database/schema/settings.js";
import { tryCatch } from "../../../../../globalUtils/tryCatch.js";
import { createLog } from "../../../../logger/logger.js";
import { query } from "../../../../sqlServer/prodSqlServer.js";
import { machineCheck } from "../../../../sqlServer/querys/ocp/machineId.js";
export const getMac = async (machine: string) => {
let updateQuery = machineCheck.replaceAll("[loc]", machine);
// create blank lots in case there is an error and dose not work
let mac = [];
try {
mac = await query(updateQuery, "Machine id check");
// console.log("Machine data", mac); // removed due to swr being activated
} catch (err) {
createLog(
"error",
"lst",
"ocp",
`Error with Machine id Check query: ${err}`
);
}
return mac;
};

View File

@@ -9,6 +9,9 @@ import updateprinters from "./routes/printers/updatePrinters.js";
import { updatePrinters } from "./controller/printers/updatePrinters.js";
import getLots from "./routes/lots/getLots.js";
import getLabels from "./routes/labeling/getLabels.js";
import { dycoConnect } from "./controller/specialProcesses/dyco/plcConnection.js";
import dycoCon from "./routes/specialProcesses/dyco/connection.js";
import dycoClose from "./routes/specialProcesses/dyco/closeConnection.js";
const app = new OpenAPIHono();
@@ -21,6 +24,9 @@ const routes = [
getLots,
// labeling
getLabels,
//dyco
dycoCon,
dycoClose,
] as const;
const setting = await db.select().from(settings);
@@ -40,4 +46,9 @@ setTimeout(() => {
updatePrinters();
}, 3 * 1000);
// do the intnal connection to the dyco
setTimeout(() => {
dycoConnect();
}, 3 * 1000);
export default app;

View File

@@ -0,0 +1,56 @@
// an external way to creating logs
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { responses } from "../../../../../globalUtils/routeDefs/responses.js";
import { authMiddleware } from "../../../../auth/middleware/authMiddleware.js";
import { tryCatch } from "../../../../../globalUtils/tryCatch.js";
import { closeDyco } from "../../../controller/specialProcesses/dyco/plcConnection.js";
const app = new OpenAPIHono({ strict: false });
app.openapi(
createRoute({
tags: ["ocp:dyco"],
summary: "Disconnect to the dyco.",
method: "get",
path: "/dycodisconnect",
middleware: authMiddleware,
description:
"Use this when you just want to stop the entire thing due to an error or what not.",
// request: {
// body: {content: {"application/json": {schema: CreateLog}}},
// },
responses: responses(),
}),
async (c) => {
//const body = await c.req.json();
//apiHit(c, {endpoint: `api/logger/logs/id`});
// const authHeader = c.req.header("Authorization");
// const token = authHeader?.split("Bearer ")[1] || "";
// let user: User;
// try {
// const payload = await verify(token, process.env.JWT_SECRET!);
// user = payload.user as User;
// } catch (error) {
// console.log(error);
// return c.json({message: "Unauthorized"}, 401);
// }
const { data, error } = await tryCatch(closeDyco());
if (error) {
return c.json({
success: false,
message: "Error in connecting to dyco",
data: error,
});
}
const getData: any = data;
return c.json({
success: getData?.success,
message: getData?.message,
});
}
);
export default app;

View File

@@ -0,0 +1,56 @@
// an external way to creating logs
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { responses } from "../../../../../globalUtils/routeDefs/responses.js";
import { authMiddleware } from "../../../../auth/middleware/authMiddleware.js";
import { tryCatch } from "../../../../../globalUtils/tryCatch.js";
import { dycoConnect } from "../../../controller/specialProcesses/dyco/plcConnection.js";
const app = new OpenAPIHono({ strict: false });
app.openapi(
createRoute({
tags: ["ocp:dyco"],
summary: "Connects to the dyco.",
method: "get",
path: "/dycoconnect",
middleware: authMiddleware,
//description: "This might be a temp soltuin during the transtion between versions",
// request: {
// body: {content: {"application/json": {schema: CreateLog}}},
// },
responses: responses(),
}),
async (c) => {
//const body = await c.req.json();
//apiHit(c, {endpoint: `api/logger/logs/id`});
// const authHeader = c.req.header("Authorization");
// const token = authHeader?.split("Bearer ")[1] || "";
// let user: User;
// try {
// const payload = await verify(token, process.env.JWT_SECRET!);
// user = payload.user as User;
// } catch (error) {
// console.log(error);
// return c.json({message: "Unauthorized"}, 401);
// }
const { data, error } = await tryCatch(dycoConnect());
const dataError: any = error;
if (error) {
return c.json({
success: false,
message: "Error in connecting to dyco",
data: dataError?.data,
});
}
const getData: any = data;
return c.json({
success: getData?.success,
message: getData?.message,
data: getData.data ?? [],
});
}
);
export default app;

View File

@@ -12,10 +12,18 @@ export const readTags = async (reader: string) => {
/**
* Start the read for x seconds then auto stop it
*/
const readers = await db.select().from(rfidReaders).where(eq(rfidReaders.active, true));
createLog("info", "rfid", "rfid", `Read was just triggered from ${reader}`);
const readers = await db
.select()
.from(rfidReaders)
.where(eq(rfidReaders.active, true));
if (readers.length === 0) {
createLog("error", "rfid", "rfid", `There are no active readers right now maybe one forgot to be activated`);
createLog(
"error",
"rfid",
"rfid",
`There are no active readers right now maybe one forgot to be activated`
);
return;
}
// get the auth token
@@ -67,7 +75,12 @@ const startRead = async () => {
startRead();
}, 1000);
}
createLog("error", "rfid", "rfid", `There was an error Starting the read: ${error.response.data.message}`);
createLog(
"error",
"rfid",
"rfid",
`There was an error Starting the read: ${error.response.data.message}`
);
}
};
const stopRead = async () => {
@@ -80,6 +93,11 @@ const stopRead = async () => {
}
);
} catch (error: any) {
createLog("error", "rfid", "rfid", `There was an error Stopping the read: ${error.response.data.message}`);
createLog(
"error",
"rfid",
"rfid",
`There was an error Stopping the read: ${error.response.data.message}`
);
}
};

View File

@@ -17,11 +17,25 @@ export const station3Tags = async (tagData: TagData[]) => {
`There are ${tagData.length} tags, and ${tagData[0].reader} only allows 1 tag to create a label.`
);
// get tag data
tagStuff(tagData);
for (let i = 0; i < tagData.length; i++) {
const tag = {
...tagData[i],
runningNr: 0,
lastareaIn: "NeedsChecked",
};
tagStuff([tag]);
}
} else {
//console.log("Generate the label and link it to the tag.");
const tagdata = await tagStuff(tagData);
const tag = { ...tagData[0], runningNr: 0 };
const tagdata = await tagStuff([tag]);
createLog("info", "rfid", "rfid", "Generate a label and link it to this tag.");
createLog(
"debug",
"rfid",
"rfid",
"Generate a label and link it to this tag."
);
}
};

View File

@@ -2,12 +2,34 @@
* Phase 1 we will just follow the logic of printing a label when we are told requested to based on this tag.
* Phase 2 we will just reprint the tag that was generated at the line
*/
import os from "os";
import { createLog } from "../../../logger/logger.js";
import { labelingProcess } from "../../../ocp/controller/labeling/labelProcess.js";
import type { TagData } from "../tagData.js";
import { tagStuff } from "../tags/crudTag.js";
import { sendEmail } from "../../../notifications/controller/sendMail.js";
export const wrapperStuff = async (tagData: TagData[]) => {
if (tagData[0]?.lastareaIn === "NeedsChecked") {
createLog(
"error",
"rfid",
"rfid",
`The tags on this pallet need to be checked as it was flagged as more than 1 tag number. please validate and looks at both sides.`
);
// just making sure we clear out the running number if one really came over.
for (let i = 0; i < tagData.length; i++) {
const tag = { ...tagData[i], runningNr: 0 };
tagStuff([tag]);
}
monitorChecks();
return {
success: false,
message:
"The tags on this pallet need to be checked as it was flagged as more than 1 tag number. please validate and looks at both sides.",
};
}
if (tagData.length != 1) {
createLog(
"error",
@@ -15,52 +37,123 @@ export const wrapperStuff = async (tagData: TagData[]) => {
"rfid",
`There are ${tagData.length} tags and this ${tagData[0].reader} only allows 1 tag to create a label.`
);
tagStuff(tagData);
const tag = { ...tagData[0], runningNr: 0 };
tagStuff([tag]);
monitorChecks();
} else {
const tagdata = await tagStuff(tagData);
if (!tagData) {
createLog("error", "rfid", "rfid", `No tagData was grabbed.`);
monitorChecks();
}
const tagdata = await tagStuff(tagData);
/**
* we want to make sure this pallet came from a line as its last spot if not we need to have a manual check.
*/
if (
!Array.isArray(tagdata) &&
tagdata?.some((n: any) => n.lastareaIn.includes("line3"))
) {
createLog("error", "rfid", "rfid", `Data passed over is not an array.`);
return;
}
const station3 = tagdata; //?.some((n: any) => n.lastareaIn.includes("line3"));
if (!station3) {
const lines = tagdata[0]?.lastareaIn.includes("line3");
if (!lines) {
createLog(
"error",
"rfid",
"rfid",
`${tagdata[0].tag}, Did not come from a line please check the pallet and manually print the label.`
);
monitorChecks();
return {
success: false,
message: `${tagdata[0].tag}, Did not come from a line please check the pallet and manually print the label.`,
};
// when we manually run again we want to make sure we read from the 3rd antenna this way we do not get the wrong info.
// more testing will need to be done on this.
}
// check if a running number exists
if (station3.runningNumber) {
if (lines[0].runningNumber) {
createLog(
"info",
"rfid",
"rfid",
`Reprint label ${station3.runningNumber}`
`Reprint label ${lines[0].runningNumber}`
);
} else {
createLog(
"info",
"rfid",
"rfid",
`A new labels will be created and linked to this ${tagdata.tag} tag`
`A new label will be created and linked to this ${tagdata[0].tag} tag`
);
// get the actaul line number from the last area in
const lineNum = parseInt(
tagdata[0]?.lastareaIn.repalceAll("line3", "")
);
createLog(
"info",
"rfid",
"rfid",
`Line to be checked for printing: ${lineNum}`
);
const genlabel = await labelingProcess({
line: lineNum.toString(),
});
if (genlabel?.success) {
// update the tag and add the label into it
const createPrintData = {
...tagData[0],
runnungNr: parseInt(genlabel.data?.SSCC.slice(10, -1)),
};
}
}
}
};
const monitorErrorTags: any = [];
const monitorChecks = () => {
/**
* If we have to check more than 10 tags in an hour send an email to alert everyone.
*/
const now = new Date(Date.now()).getTime();
monitorErrorTags.push({ timestamp: now });
// remove if creater than 1 hour
const removalTiming = now - 1 * 60 * 60 * 1000; // 1 hour
while (
monitorErrorTags > 0 &&
monitorErrorTags[0].timestamp < removalTiming
) {
monitorErrorTags.shift();
}
if (monitorErrorTags > 10) {
// send the email.
const emailData = {
email: "blake.matthes@alpla.com", // should be moved to the db so it can be reused.
subject: `${os.hostname()} has had ${monitorErrorTags}.`,
template: "toManyManualPrints",
context: {
count: monitorErrorTags,
hours: "1",
},
};
sendEmail(emailData);
}
};
// if (
// !Array.isArray(tagdata) &&
// tagdata?.some((n: any) => n.lastareaIn.includes("line3"))
// ) {
// createLog(
// "error",
// "rfid",
// "rfid",
// `Data passed over is not an array.`
// );
// return;
// }

View File

@@ -8,6 +8,7 @@ export type TagData = {
timeStamp: Date;
antenna: number;
tagStrength: number;
lastareaIn?: string;
};
export const tagData = async (data: TagData[]) => {
/**

View File

@@ -45,10 +45,13 @@ export const tagStuff = async (tagData: TagData[]): Promise<any> => {
// update tag
//console.log("Updating existing tag");
// make sure we actually have an array here
const countsArray = (tag[0]?.counts as {area: string; timesHere: number}[]) ?? [];
const countsArray =
(tag[0]?.counts as { area: string; timesHere: number }[]) ?? [];
// check if the reader exists on the array
const areaExists = countsArray.some((t) => t.area === tagData[0].reader);
const areaExists = countsArray.some(
(t) => t.area === tagData[0].reader
);
// run the update on the array
const updateCount = areaExists
@@ -56,7 +59,11 @@ export const tagStuff = async (tagData: TagData[]): Promise<any> => {
if (t.area === tagData[0].reader) {
return { ...t, timesHere: t.timesHere + 1 };
} else {
return {...t, area: tagData[i].reader, timesHere: 1};
return {
...t,
area: tagData[i].reader,
timesHere: 1,
};
}
})
: [...countsArray, { area: tagData[i].reader, timesHere: 1 }];
@@ -70,7 +77,11 @@ export const tagStuff = async (tagData: TagData[]): Promise<any> => {
};
try {
await db.update(rfidTags).set(updateTag).where(eq(rfidTags.tagHex, tagData[0].tagHex)).returning({
await db
.update(rfidTags)
.set(updateTag)
.where(eq(rfidTags.tagHex, tagData[0].tagHex))
.returning({
tag: rfidTags.tag,
runningNumber: rfidTags.runningNumber,
counts: rfidTags.counts,

View File

@@ -9,14 +9,35 @@ import {settings} from "../../../../database/schema/settings.js";
import { createLog } from "../../logger/logger.js";
// "view", "technician", "supervisor","manager", "admin", "systemAdmin"
const newSettings = [
{name: "server", value: "localhost", description: "Where the app runs at", moduleName: "server"},
{name: "serverPort", value: "4400", description: "What are we listening on", moduleName: "server"},
{name: "dbUser", value: "alplaprod", description: "What is the db username", moduleName: "server"},
{name: "dbPass", value: "b2JlbGl4", description: "What is the db password", moduleName: "server"},
{
name: "server",
value: "localhost",
description: "Where the app runs at",
moduleName: "server",
},
{
name: "serverPort",
value: "4400",
description: "What are we listening on",
moduleName: "server",
},
{
name: "dbUser",
value: "alplaprod",
description: "What is the db username",
moduleName: "server",
},
{
name: "dbPass",
value: "b2JlbGl4",
description: "What is the db password",
moduleName: "server",
},
{
name: "tcpPort",
value: "2222",
description: "TCP port for printers to connect send data and the zedra cameras",
description:
"TCP port for printers to connect send data and the zedra cameras",
moduleName: "server",
},
{
@@ -59,13 +80,15 @@ const newSettings = [
{
name: "ocmeService",
value: "0",
description: "Is the ocme service enabled. this is gernerally only for Dayton.",
description:
"Is the ocme service enabled. this is gernerally only for Dayton.",
moduleName: "ocme",
},
{
name: "fifoCheck",
value: "45",
description: "How far back do we want to check for fifo default 45, putting 0 will ignore.",
description:
"How far back do we want to check for fifo default 45, putting 0 will ignore.",
moduleName: "ocme",
},
{
@@ -83,7 +106,8 @@ const newSettings = [
{
name: "monitorAddress",
value: "8",
description: "What address is monitored to be limited to the amount of lots that can be added to a truck.",
description:
"What address is monitored to be limited to the amount of lots that can be added to a truck.",
moduleName: "ocme",
},
{
@@ -96,7 +120,8 @@ const newSettings = [
{
name: "devDir",
value: "C:\\Users\\matthes01\\Documents\\lstv2",
description: "This is the dev dir and strictly only for updating the servers.",
description:
"This is the dev dir and strictly only for updating the servers.",
moduleName: "server",
},
{
@@ -116,7 +141,30 @@ const newSettings = [
{
name: "ocpLogsCheck",
value: "4",
description: "How long do we want to allow logs to show that have not been cleared?",
description:
"How long do we want to allow logs to show that have not been cleared?",
roles: "admin",
module: "ocp",
},
{
name: "inhouseDelivery",
value: "0",
description: "Are we doing auto inhouse delivery?",
roles: "admin",
module: "ocp",
},
// dyco settings
{
name: "dycoConnect",
value: "0",
description: "Are we running the dyco system?",
roles: "admin",
module: "ocp",
},
{
name: "dycoPrint",
value: "0",
description: "Are we using the dyco to get the labels or the rfid?",
roles: "admin",
module: "ocp",
},
@@ -133,12 +181,27 @@ export const areSettingsIn = async () => {
.values(newSettings)
.onConflictDoNothing() // this will only update the ones that are new :D
.returning({ name: settings.name });
createLog("info", "lst", "server", "Settingss were just added due to missing them on server startup");
createLog(
"info",
"lst",
"server",
"Settingss were just added due to missing them on server startup"
);
} catch (error) {
createLog("error", "lst", "server", "There was an error adding new roles to the db");
createLog(
"error",
"lst",
"server",
"There was an error adding new roles to the db"
);
}
}
} catch (error) {
createLog("error", "lst", "server", "There was an error getting or adding new Settingss");
createLog(
"error",
"lst",
"server",
"There was an error getting or adding new Settingss"
);
}
};

View File

@@ -0,0 +1,7 @@
export const laneInfo = `
select IdLagerAbteilung as laneID,
Bezeichnung as laneName
from AlplaPROD_test1.dbo.T_LagerAbteilungen
where Aktiv = 1
and Bezeichnung = '[laneName]'
`;

View File

@@ -0,0 +1,9 @@
export const machineCheck = `
SELECT [HumanReadableId]
,[Name]
,[Location]
,[Active]
,[ImportSource]
,[StagingMainMaterialMandatory]
FROM [test1_AlplaPROD2.0_Read].[masterData].[Machine] (nolock)
where Active = 1 and [Location] = [loc]`;

View File

@@ -0,0 +1,17 @@
export const mmQuery = `
SELECT lot.ProductionLotHumanReadableId,
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.IsManualProcess as isManual,
MaterialHumanReadableId
FROM [test1_AlplaPROD2.0_Read].[issueMaterial].[MaterialDemand] x (nolock)
left join
[test1_AlplaPROD2.0_Read].[issueMaterial].[ProductionLot] as lot on
x.ProductionLotId = lot.Id
where lot.ProductionLotHumanReadableId = [lotNumber]
and IsMainMaterial = 1
`;