Compare commits

..

120 Commits

Author SHA1 Message Date
63b1151cb7 fix(misc): work on ocp to improve the errors that were missed and better logging 2025-03-30 10:11:58 -05:00
a5dee58223 refactor(server): removed console logs 2025-03-30 10:11:29 -05:00
9784072aab refactor(format changes): changes to the file formats to match across computers 2025-03-30 10:10:53 -05:00
f9096b54f5 fix(admin auth): added in role change for v1 2025-03-30 10:10:01 -05:00
11e5cf4d86 refactor(lst): added huston backin 2025-03-30 10:09:32 -05:00
a647d05d3b chore(release): bump build number to 125 2025-03-30 10:03:20 -05:00
098c477119 chore(release): bump build number to 124 2025-03-30 09:44:19 -05:00
3228ad7892 feat(lst): script added for the test server to readd the permissions once it boots up 2025-03-30 08:41:55 -05:00
c27ad7cf6a refactor(lst): added in a removal of old files so we can keep the server clean 2025-03-30 08:41:26 -05:00
a48d4bd5af feat(auth): admin user updates added
if a password change happens then an email will be sent to the user.
2025-03-30 08:40:49 -05:00
09c0825194 chore(release): bump build number to 123 2025-03-30 05:09:52 -05:00
28fbf2c1e4 chore(release): bump build number to 122 2025-03-29 18:26:57 -05:00
af5dc9266f chore(release): bump build number to 121 2025-03-29 12:16:23 -05:00
b903c8ee2d chore(release): bump build number to 120 2025-03-29 12:15:02 -05:00
035eda9aa8 chore(release): bump build number to 119 2025-03-29 12:13:16 -05:00
1f7c33d871 chore(release): bump build number to 118 2025-03-29 07:54:44 -05:00
d046c4ea41 chore(release): bump build number to 117 2025-03-29 07:39:34 -05:00
88258baf9d chore(release): bump build number to 116 2025-03-28 14:50:34 -05:00
82acfcc4a9 chore(release): bump build number to 116 2025-03-28 14:20:37 -05:00
ba3d721940 refactor(ocp): lots of work for rfid and dyco contorl 2025-03-27 21:12:22 -05:00
27d6b6e884 refactor(ocme): added new error in posting where we know when the pallet is not instock 2025-03-27 21:11:42 -05:00
2c8d1fb710 fix(logger): changes to get the most recent verse aged 2025-03-27 21:10:57 -05:00
b5de6445b3 feat(rfid): work on the readers and there functions 2025-03-27 21:08:05 -05:00
f9f68ce969 refactor(logger): changed log level to be in the env file vs hardcoded 2025-03-27 21:07:15 -05:00
0ced135ec3 feat(updater): added in a delete function for the server side 2025-03-27 21:06:45 -05:00
7b1c6e1361 refactor(ocp): finished the dashboard and move logs and labels to a tab style 2025-03-27 21:06:25 -05:00
e3ba45ae13 fix(ocme): fixed to make sure we can always just update a runnning nunmber 2025-03-27 21:05:49 -05:00
ac7859fda3 chore(release): bump build number to 115 2025-03-27 20:21:24 -05:00
fb31ae79d1 chore(release): bump build number to 114 2025-03-27 18:50:04 -05:00
ff1dfdde68 chore(release): bump build number to 113 2025-03-27 18:44:11 -05:00
f0b9bd599a chore(release): bump build number to 112 2025-03-27 18:42:43 -05:00
f3103d8c1a chore(release): bump build number to 111 2025-03-27 18:22:13 -05:00
d557728fa2 chore(release): bump build number to 110 2025-03-27 17:26:30 -05:00
d58cb5286e chore(release): bump build number to 109 2025-03-27 17:03:39 -05:00
7d4733896e chore(release): bump build number to 108 2025-03-27 16:48:14 -05:00
175c7226ed chore(release): bump build number to 107 2025-03-27 15:00:51 -05:00
c32547ceb8 chore(release): bump build number to 106 2025-03-27 14:47:42 -05:00
a01c0566c2 chore(release): bump build number to 105 2025-03-27 14:46:43 -05:00
ca4106945b chore(release): bump build number to 104 2025-03-27 14:45:41 -05:00
1386e0f00f chore(release): bump build number to 103 2025-03-27 14:44:10 -05:00
290f20b86b chore(release): bump build number to 102 2025-03-27 14:33:34 -05:00
52171c87fc chore(release): bump build number to 101 2025-03-27 14:31:22 -05:00
c474536992 chore(release): bump build number to 100 2025-03-27 14:07:33 -05:00
600a989226 chore(release): bump build number to 99 2025-03-27 11:55:35 -05:00
ea7801fccf chore(release): bump build number to 98 2025-03-27 10:59:53 -05:00
c03b61f48a chore(release): bump build number to 97 2025-03-27 10:33:59 -05:00
ca552d5587 chore(release): bump build number to 96 2025-03-27 10:12:23 -05:00
278c5538bc chore(release): bump build number to 95 2025-03-27 09:21:15 -05:00
f39ae0f590 chore(release): bump build number to 94 2025-03-27 09:10:01 -05:00
b4e0f4c666 chore(release): bump build number to 93 2025-03-26 22:12:03 -05:00
db66302415 chore(release): 2.10.0 2025-03-26 22:11:27 -05:00
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
3b5e82fdc1 feat(ocp): added wrappercard into the mix 2025-03-25 18:57:00 -05:00
f9cd3fb881 feat(ocp): prodlink check added 2025-03-25 18:56:36 -05:00
51267f5202 fix(ocme): fixed the camera routes 2025-03-25 18:55:57 -05:00
ceaa25f31e feat(ocp): added labeling logs in 2025-03-25 18:55:23 -05:00
416254353c chore(release): bump build number to 84 2025-03-25 18:21:47 -05:00
7f946c095b chore(release): bump build number to 83 2025-03-25 18:03:32 -05:00
c2aa69ab0a chore(release): bump build number to 82 2025-03-25 18:02:14 -05:00
250988800e chore(release): bump build number to 81 2025-03-25 17:57:13 -05:00
cacfd6d2e0 chore(release): bump build number to 80 2025-03-25 17:49:07 -05:00
8d2721b0c2 chore(release): bump build number to 79 2025-03-25 17:44:41 -05:00
36cdc7b4bf chore(release): bump build number to 78 2025-03-25 17:39:26 -05:00
4d4d6fc7a4 chore(release): bump build number to 77 2025-03-25 15:48:28 -05:00
030f9f9aac refactor(ocp): moved printers to there own folder to keep everything clean 2025-03-25 13:39:39 -05:00
9e9a56cbb1 feat(ocp): add lots with scroll view was added 2025-03-25 13:39:18 -05:00
b01980e1c5 fix(ocme): fixed some import errors 2025-03-25 12:48:18 -05:00
fe0c500dcf feat(server): clearn up code 2025-03-25 12:47:52 -05:00
8a040d15db fix(servers): fixed the weird conflict import that happened 2025-03-25 12:47:36 -05:00
f90066c090 feat(ocp): added in printers get and add 2025-03-25 12:47:15 -05:00
04eb2e3e14 refactor(tcpserver): just the tcp server doing something 2025-03-25 07:58:37 -05:00
90fb0d364d Merge branch 'main' of https://git.tuffraid.net/cowch/lstV2 2025-03-25 07:57:55 -05:00
e6e1cecce3 refactor(ocme): corrections to endpoints to work with ocnme as intneeded 2025-03-25 07:54:58 -05:00
73aa95a693 refactor(ocme): cleaup on pickedup 2025-03-25 07:54:22 -05:00
b9f19095cb refactor(ocme): clean up on the getInfo endpoint 2025-03-25 07:54:00 -05:00
dcb56d4274 fix(ocme): corrections to posting data for the response was added 2025-03-25 07:53:30 -05:00
bc1821132e feat(ocme): manual camera trigger for the wrapper added 2025-03-25 07:52:40 -05:00
2551d6c907 refactor(updateserver): removed ocme from starting back up as it was migrated 2025-03-25 07:41:10 -05:00
adf0880659 refactor(server): changed to log only when in dev, and removed the redirect of the url 2025-03-25 07:40:15 -05:00
5149de3199 ci(lst): changes made to the settings file to work across all pvs 2025-03-25 07:39:32 -05:00
c71b514d9a refactor(frontend): prettier change to formatting 2025-03-25 07:27:45 -05:00
9254e52808 chore(release): bump build number to 76 2025-03-25 06:17:31 -05:00
b8c028a6c1 chore(release): bump build number to 75 2025-03-24 20:20:55 -05:00
529e922485 chore(release): bump build number to 74 2025-03-24 20:13:07 -05:00
5201012235 chore(release): bump build number to 73 2025-03-24 20:08:59 -05:00
abe53b8f5d chore(release): bump build number to 72 2025-03-24 20:06:15 -05:00
836f3e294b chore(release): bump build number to 71 2025-03-24 19:56:03 -05:00
96abef762b chore(release): bump build number to 70 2025-03-24 19:40:39 -05:00
2c227f9428 chore(release): bump build number to 69 2025-03-24 18:33:12 -05:00
46647687dc chore(release): bump build number to 68 2025-03-24 18:23:24 -05:00
cb01ef1af1 chore(release): bump build number to 67 2025-03-24 17:16:23 -05:00
b3b5fcec65 chore(release): bump build number to 66 2025-03-24 17:14:25 -05:00
3a4dc47a36 chore(release): bump build number to 65 2025-03-24 17:06:23 -05:00
63177b523e chore(release): bump build number to 64 2025-03-24 17:00:20 -05:00
e1cad027d2 chore(release): bump build number to 63 2025-03-24 16:42:53 -05:00
c1cc355f4f chore(release): bump build number to 62 2025-03-24 16:40:50 -05:00
5ed67f3fc0 chore(release): bump build number to 61 2025-03-24 16:28:32 -05:00
57e82d2360 chore(release): bump build number to 60 2025-03-24 16:26:04 -05:00
9395ec6cd4 chore(release): bump build number to 59 2025-03-24 15:50:29 -05:00
0475bb30f9 chore(release): bump build number to 58 2025-03-24 15:49:37 -05:00
6843368c36 chore(release): bump build number to 57 2025-03-24 15:47:16 -05:00
335ea2deca chore(release): bump build number to 56 2025-03-24 15:39:33 -05:00
96814c1115 Merge branch 'main' of https://git.tuffraid.net/cowch/lstV2 2025-03-24 15:31:35 -05:00
6dd9ed848b test(ocme): lots of changes to get it working in production 2025-03-24 15:31:31 -05:00
0c5fc1dfb0 chore(release): bump build number to 55 2025-03-24 15:28:10 -05:00
5886bea85d chore(release): bump build number to 52 2025-03-24 11:43:52 -05:00
136 changed files with 16138 additions and 1691 deletions

50
.vscode/settings.json vendored
View File

@@ -1,26 +1,28 @@
{
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"[javascript]": {
"editor.formatOnSave": true
},
"[javascriptreact]": {
"editor.formatOnSave": true
},
"[typescript]": {
"editor.formatOnSave": true
},
"[typescriptreact]": {
"editor.formatOnSave": true
},
"[json]": {
"editor.formatOnSave": true
},
"[graphql]": {
"editor.formatOnSave": true
},
"[handlebars]": {
"editor.formatOnSave": true
}
"editor.defaultFormatter": "esbenp.prettier-vscode",
"workbench.colorTheme": "Default Dark+",
"prettier.tabWidth": 4,
"terminal.integrated.env.windows": {},
"editor.formatOnSave": true,
"[javascript]": {
"editor.formatOnSave": true
},
"[javascriptreact]": {
"editor.formatOnSave": true
},
"[typescript]": {
"editor.formatOnSave": true
},
"[typescriptreact]": {
"editor.formatOnSave": true
},
"[json]": {
"editor.formatOnSave": true
},
"[graphql]": {
"editor.formatOnSave": true
},
"[handlebars]": {
"editor.formatOnSave": true
}
}

View File

@@ -1,5 +1,100 @@
# All CHanges to LST can be found below.
## [2.10.0](https://git.tuffraid.net/cowch/lstV2/compare/v2.9.0...v2.10.0) (2025-03-27)
### 📝 Testing Code
* **ocme:** lots of changes to get it working in production ([6dd9ed8](https://git.tuffraid.net/cowch/lstV2/commits/6dd9ed848bc7d4e8a62778cfe36f89e077187157))
### 📈 Project changes
* **lst:** changes made to the settings file to work across all pvs ([5149de3](https://git.tuffraid.net/cowch/lstV2/commits/5149de3199d3aaf349b8a4c99d5db83f8d04ae49))
### 🐛 Bug fixes
* **logistics:** correction to the lane grab ([2d4b1db](https://git.tuffraid.net/cowch/lstV2/commits/2d4b1db5f4697770aee8829764bd85643893d3e8))
* **lst:** missing , in versionRc ([c35726b](https://git.tuffraid.net/cowch/lstV2/commits/c35726bf5ccd6565abda37c6618a34e975e70d41))
* **ocme:** corrections to posting data for the response was added ([dcb56d4](https://git.tuffraid.net/cowch/lstV2/commits/dcb56d427458c774b462e78daba6fee4afefd525))
* **ocme:** fixed some import errors ([b01980e](https://git.tuffraid.net/cowch/lstV2/commits/b01980e1c5a8833b25ea557a2da07b74560526e3))
* **ocme:** fixed the camera routes ([51267f5](https://git.tuffraid.net/cowch/lstV2/commits/51267f5202ceebe1c31c819395e1588d47657c38))
* **servers:** fixed the weird conflict import that happened ([8a040d1](https://git.tuffraid.net/cowch/lstV2/commits/8a040d15dbf5de5fbb9949b7834c39b93b145aa7))
### 📝 Chore
* bump build number to 50 ([9bdca33](https://git.tuffraid.net/cowch/lstV2/commits/9bdca3317c7c213f9c5853222eafe1ab028b5f64))
* **release:** bump build number to 52 ([5886bea](https://git.tuffraid.net/cowch/lstV2/commits/5886bea85da30fe43635e05de1e9bc4f5789fa64))
* **release:** bump build number to 55 ([0c5fc1d](https://git.tuffraid.net/cowch/lstV2/commits/0c5fc1dfb0a8bee5cf7414733a555fe1b5888b8e))
* **release:** bump build number to 56 ([335ea2d](https://git.tuffraid.net/cowch/lstV2/commits/335ea2deca54dacda2117849104bf4c24faee3e8))
* **release:** bump build number to 57 ([6843368](https://git.tuffraid.net/cowch/lstV2/commits/6843368c3682bb56e5ce4aafbb18367e96a6016e))
* **release:** bump build number to 58 ([0475bb3](https://git.tuffraid.net/cowch/lstV2/commits/0475bb30f9d6d4e2d132b15b24d9ab225d8de3b9))
* **release:** bump build number to 59 ([9395ec6](https://git.tuffraid.net/cowch/lstV2/commits/9395ec6cd4483f52fcca949a95a4ceecaa843f65))
* **release:** bump build number to 60 ([57e82d2](https://git.tuffraid.net/cowch/lstV2/commits/57e82d23603622c301c7e6d636f9cec07d44e0b2))
* **release:** bump build number to 61 ([5ed67f3](https://git.tuffraid.net/cowch/lstV2/commits/5ed67f3fc0f99ca5344da8b73fd005184b89670b))
* **release:** bump build number to 62 ([c1cc355](https://git.tuffraid.net/cowch/lstV2/commits/c1cc355f4f4e74c3897cada64d961b28d24c07b2))
* **release:** bump build number to 63 ([e1cad02](https://git.tuffraid.net/cowch/lstV2/commits/e1cad027d2714ddf3289e31b5c3bbb96306f1f56))
* **release:** bump build number to 64 ([63177b5](https://git.tuffraid.net/cowch/lstV2/commits/63177b523e2dd1fabefe52f52dd3c6b3fcff9bcf))
* **release:** bump build number to 65 ([3a4dc47](https://git.tuffraid.net/cowch/lstV2/commits/3a4dc47a368bb20f622b7e4647337c5e68150db9))
* **release:** bump build number to 66 ([b3b5fce](https://git.tuffraid.net/cowch/lstV2/commits/b3b5fcec651e2bc585ecd4be03be4288867b214f))
* **release:** bump build number to 67 ([cb01ef1](https://git.tuffraid.net/cowch/lstV2/commits/cb01ef1af17e9c83753e09a1528e6140a4104273))
* **release:** bump build number to 68 ([4664768](https://git.tuffraid.net/cowch/lstV2/commits/46647687dc9938ecf6e72a63f15afc0e29bebcc4))
* **release:** bump build number to 69 ([2c227f9](https://git.tuffraid.net/cowch/lstV2/commits/2c227f94287a6ce9c06b0a41772085ba1f4f0cd3))
* **release:** bump build number to 70 ([96abef7](https://git.tuffraid.net/cowch/lstV2/commits/96abef762b77361c857642a33acfb69c0bc00666))
* **release:** bump build number to 71 ([836f3e2](https://git.tuffraid.net/cowch/lstV2/commits/836f3e294b4d92673388023503e409592ef95ba3))
* **release:** bump build number to 72 ([abe53b8](https://git.tuffraid.net/cowch/lstV2/commits/abe53b8f5d9bfbf517c7f56c5d4df2e4586aedbd))
* **release:** bump build number to 73 ([5201012](https://git.tuffraid.net/cowch/lstV2/commits/5201012235181975cb89aee8dbc644ca4aa42210))
* **release:** bump build number to 74 ([529e922](https://git.tuffraid.net/cowch/lstV2/commits/529e922485303251349c081ad8b2e9bee08dd420))
* **release:** bump build number to 75 ([b8c028a](https://git.tuffraid.net/cowch/lstV2/commits/b8c028a6c1fa54afeb049fd42e666bc40690aa4e))
* **release:** bump build number to 76 ([9254e52](https://git.tuffraid.net/cowch/lstV2/commits/9254e528086b95ada8c9dc4468f4fbb5b39fbd68))
* **release:** bump build number to 77 ([4d4d6fc](https://git.tuffraid.net/cowch/lstV2/commits/4d4d6fc7a4885b4b1652ac125a2b39b8325b0d6e))
* **release:** bump build number to 78 ([36cdc7b](https://git.tuffraid.net/cowch/lstV2/commits/36cdc7b4bf3bf90a785bab4d9892e65f84cb162a))
* **release:** bump build number to 79 ([8d2721b](https://git.tuffraid.net/cowch/lstV2/commits/8d2721b0c2f6255affcd9ec08427e1b4e6771107))
* **release:** bump build number to 80 ([cacfd6d](https://git.tuffraid.net/cowch/lstV2/commits/cacfd6d2e0e11ab7dbc5cb443a58df7bf8d2b8bb))
* **release:** bump build number to 81 ([2509888](https://git.tuffraid.net/cowch/lstV2/commits/250988800e1429a1f46005ae54a2a07d31fac3a8))
* **release:** bump build number to 82 ([c2aa69a](https://git.tuffraid.net/cowch/lstV2/commits/c2aa69ab0a2f925944abd1b78af6a8698249bff8))
* **release:** bump build number to 83 ([7f946c0](https://git.tuffraid.net/cowch/lstV2/commits/7f946c095b8c0208c97bd1bb2c33cf466a04d125))
* **release:** bump build number to 84 ([4162543](https://git.tuffraid.net/cowch/lstV2/commits/416254353cd0a926aaf14c343db2ad18f025b230))
* **release:** bump build number to 85 ([5d61eb8](https://git.tuffraid.net/cowch/lstV2/commits/5d61eb879e102939df56928cd8d57eda561aabca))
* **release:** bump build number to 86 ([5ab813f](https://git.tuffraid.net/cowch/lstV2/commits/5ab813f37894136549de0a05e5b4e2491220d16d))
* **release:** bump build number to 87 ([509ef84](https://git.tuffraid.net/cowch/lstV2/commits/509ef8472688ba655c524a1068c3721559f5da11))
* **release:** bump build number to 88 ([c0a0589](https://git.tuffraid.net/cowch/lstV2/commits/c0a0589b3c860ae8202a5dd230c18a3463cce857))
* **release:** bump build number to 89 ([af076b8](https://git.tuffraid.net/cowch/lstV2/commits/af076b8e27b599c479e4e51f38487cf4cb3cfa34))
* **release:** bump build number to 90 ([04aa943](https://git.tuffraid.net/cowch/lstV2/commits/04aa9439205f12bfe10b3fdf76a211a7b8178ac1))
* **release:** bump build number to 91 ([a31e7ea](https://git.tuffraid.net/cowch/lstV2/commits/a31e7ea1634fd6b10e22dff4ba93157c2be711ac))
* **release:** bump build number to 92 ([878e650](https://git.tuffraid.net/cowch/lstV2/commits/878e650e6237345d825632dff0387a89c7eee088))
### 🌟 Enhancements
* **logistics:** added in return material by lane name and gets lane id ([58f7b43](https://git.tuffraid.net/cowch/lstV2/commits/58f7b4322d3e523620f827a580ff5534b0be5f6c))
* **notify:** intial nofity system added to monitor crashes and rfid wrapper ([eb051d5](https://git.tuffraid.net/cowch/lstV2/commits/eb051d51f21b1ad617851fa3f4a1b8ba2f4fe4ac))
* **ocme:** manual camera trigger for the wrapper added ([bc18211](https://git.tuffraid.net/cowch/lstV2/commits/bc1821132e30be6b3a36bae63ce52fd4007f74dd))
* **ocp:** add lots with scroll view was added ([9e9a56c](https://git.tuffraid.net/cowch/lstV2/commits/9e9a56cbb15782770daf7e4ab08b31ad23df6c27))
* **ocp:** added in printers get and add ([f90066c](https://git.tuffraid.net/cowch/lstV2/commits/f90066c09020ebac03a93059c8e41f8531812c8a))
* **ocp:** added labeling logs in ([ceaa25f](https://git.tuffraid.net/cowch/lstV2/commits/ceaa25f31e6da526abd0350881e21984c66b455a))
* **ocp:** added wrappercard into the mix ([3b5e82f](https://git.tuffraid.net/cowch/lstV2/commits/3b5e82fdc122824b4f59f00f2ed59b90813694ba))
* **ocp:** create and book in plus dyco controller implemented ([7a1a477](https://git.tuffraid.net/cowch/lstV2/commits/7a1a4773e71cab93f36071530dbb5561e7592ec7))
* **ocp:** prodlink check added ([f9cd3fb](https://git.tuffraid.net/cowch/lstV2/commits/f9cd3fb8815635fdd0736b573dec86d14b24a6a7))
* **server:** clearn up code ([fe0c500](https://git.tuffraid.net/cowch/lstV2/commits/fe0c500dcfe317b3f67d67474fda7cf6872f3f37))
### 🛠️ Code Refactor
* **frontend:** prettier change to formatting ([c71b514](https://git.tuffraid.net/cowch/lstV2/commits/c71b514d9add69c63e608b22bd8a936fa770b167))
* **ocme:** clean up on the getInfo endpoint ([b9f1909](https://git.tuffraid.net/cowch/lstV2/commits/b9f19095cbd86569b58bec99575d924db997e385))
* **ocme:** cleaup on pickedup ([73aa95a](https://git.tuffraid.net/cowch/lstV2/commits/73aa95a6937129a36f6ece10ef8d6fd5f01a2b27))
* **ocme:** corrections to endpoints to work with ocnme as intneeded ([e6e1cec](https://git.tuffraid.net/cowch/lstV2/commits/e6e1cecce33b3c8cd94cf6372601c92f268b12a5))
* **ocme:** removed some info logs as ocme calls alot ([96e7f74](https://git.tuffraid.net/cowch/lstV2/commits/96e7f742fe68cc98de3039bd3dbfb2d27f6d7204))
* **ocp:** moved printers to there own folder to keep everything clean ([030f9f9](https://git.tuffraid.net/cowch/lstV2/commits/030f9f9aacdfcca1298a26be4442f5629626ba79))
* **rfid:** refactored station 3 (lines) and complete logic ([bd11feb](https://git.tuffraid.net/cowch/lstV2/commits/bd11feb1365ffb058283eb9384684c199ef9fd21))
* **rfid:** refactored the way the wrapper works to indlude backup dyco plan ([90e9bb0](https://git.tuffraid.net/cowch/lstV2/commits/90e9bb0ff6a2f598b055fae931a0d3c78f93e868))
* **server:** changed to log only when in dev, and removed the redirect of the url ([adf0880](https://git.tuffraid.net/cowch/lstV2/commits/adf08806593fdcd3a3d9d0a6d07f0262501e21ad))
* **tcpserver:** just the tcp server doing something ([04eb2e3](https://git.tuffraid.net/cowch/lstV2/commits/04eb2e3e145ba99b330ab627fcd9bae436e17fcf))
* **updateserver:** removed ocme from starting back up as it was migrated ([2551d6c](https://git.tuffraid.net/cowch/lstV2/commits/2551d6c9074a0338224d81e690600a7a4b9c9777))
## [2.9.0](https://git.tuffraid.net/cowch/lstV2/compare/v2.8.0...v2.9.0) (2025-03-23)

View File

@@ -0,0 +1,17 @@
CREATE TABLE "printers" (
"printer_id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"humanReadableId" text,
"name" text NOT NULL,
"ipAddress" text,
"port" numeric NOT NULL,
"status" text,
"statusText" text NOT NULL,
"lastTimePrinted" text,
"assigned" boolean DEFAULT false NOT NULL,
"remark" text,
"monitorState" boolean DEFAULT false NOT NULL,
"add_Date" timestamp DEFAULT now(),
"upd_date" timestamp DEFAULT now()
);
--> statement-breakpoint
CREATE UNIQUE INDEX "humanReadableId" ON "printers" USING btree ("name");

View File

@@ -0,0 +1,3 @@
ALTER TABLE "printers" ALTER COLUMN "statusText" DROP NOT NULL;--> statement-breakpoint
ALTER TABLE "printers" ALTER COLUMN "assigned" DROP NOT NULL;--> statement-breakpoint
ALTER TABLE "printers" ALTER COLUMN "monitorState" DROP NOT NULL;

View File

@@ -0,0 +1 @@
ALTER TABLE "printers" ALTER COLUMN "port" DROP NOT NULL;

View File

@@ -0,0 +1,2 @@
DROP INDEX "humanReadableId";--> statement-breakpoint
CREATE UNIQUE INDEX "humanReadableId" ON "printers" USING btree ("humanReadableId");

View File

@@ -0,0 +1,4 @@
CREATE TABLE "prodlabels" (
"label_id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"runningNr" integer NOT NULL
);

View File

@@ -0,0 +1,7 @@
ALTER TABLE "prodlabels" ADD COLUMN "printerID" integer;--> statement-breakpoint
ALTER TABLE "prodlabels" ADD COLUMN "printerName" text;--> statement-breakpoint
ALTER TABLE "prodlabels" ADD COLUMN "line" integer;--> statement-breakpoint
ALTER TABLE "prodlabels" ADD COLUMN "status" text;--> statement-breakpoint
ALTER TABLE "prodlabels" ADD COLUMN "add_date" timestamp;--> statement-breakpoint
ALTER TABLE "prodlabels" ADD COLUMN "upd_date" timestamp;--> statement-breakpoint
CREATE UNIQUE INDEX "runningNr" ON "prodlabels" USING btree ("runningNr");

View File

@@ -0,0 +1,4 @@
ALTER TABLE "prodlabels" ALTER COLUMN "add_date" SET DEFAULT now();--> statement-breakpoint
ALTER TABLE "prodlabels" ALTER COLUMN "upd_date" SET DEFAULT now();--> statement-breakpoint
ALTER TABLE "prodlabels" ADD COLUMN "add_user" text DEFAULT 'lst';--> statement-breakpoint
CREATE UNIQUE INDEX "ocme_runningNr" ON "ocmeData" USING btree ("runningNr");

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -183,6 +183,55 @@
"when": 1742655504936,
"tag": "0025_amusing_sugar_man",
"breakpoints": true
},
{
"idx": 26,
"version": "7",
"when": 1742914066219,
"tag": "0026_daily_the_twelve",
"breakpoints": true
},
{
"idx": 27,
"version": "7",
"when": 1742917145140,
"tag": "0027_needy_sleepwalker",
"breakpoints": true
},
{
"idx": 28,
"version": "7",
"when": 1742917676211,
"tag": "0028_fast_wong",
"breakpoints": true
},
{
"idx": 29,
"version": "7",
"when": 1742917978318,
"tag": "0029_giant_blue_blade",
"breakpoints": true
},
{
"idx": 30,
"version": "7",
"when": 1742938986653,
"tag": "0030_conscious_cable",
"breakpoints": true
},
{
"idx": 31,
"version": "7",
"when": 1742939306614,
"tag": "0031_loud_alex_power",
"breakpoints": true
},
{
"idx": 32,
"version": "7",
"when": 1743124980863,
"tag": "0032_tough_iron_monger",
"breakpoints": true
}
]
}

View File

@@ -1,6 +1,15 @@
import {text, pgTable, numeric, index, timestamp, boolean, uuid, uniqueIndex} from "drizzle-orm/pg-core";
import {createInsertSchema, createSelectSchema} from "drizzle-zod";
import {z} from "zod";
import {
text,
pgTable,
numeric,
index,
timestamp,
boolean,
uuid,
uniqueIndex,
} from "drizzle-orm/pg-core";
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
import { z } from "zod";
export const ocmeData = pgTable(
"ocmeData",
@@ -20,6 +29,7 @@ export const ocmeData = pgTable(
(table) => [
// uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`),
// uniqueIndex("role_name").on(table.name),
uniqueIndex("ocme_runningNr").on(table.runningNr),
]
);

View File

@@ -0,0 +1,42 @@
import {
text,
pgTable,
numeric,
index,
timestamp,
boolean,
uuid,
uniqueIndex,
} from "drizzle-orm/pg-core";
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
import { z } from "zod";
export const printers = pgTable(
"printers",
{
printer_id: uuid("printer_id").defaultRandom().primaryKey(),
humanReadableId: text("humanReadableId"),
name: text("name").notNull(),
ipAddress: text("ipAddress"),
port: numeric("port"),
status: text("status"),
statusText: text("statusText"),
lastTimePrinted: text("lastTimePrinted"),
assigned: boolean("assigned").default(false),
remark: text("remark"),
monitorState: boolean("monitorState").default(false),
add_Date: timestamp("add_Date").defaultNow(),
upd_date: timestamp("upd_date").defaultNow(),
},
(table) => [
//uniqueIndex("emailUniqueIndex").on(sql`lower(${table.email})`),
uniqueIndex("humanReadableId").on(table.humanReadableId),
]
);
// Schema for inserting a user - can be used to validate API requests
// export const insertRolesSchema = createInsertSchema(roles, {
// name: z.string().min(3, {message: "Role name must be more than 3 letters"}),
// });
// Schema for selecting a Expenses - can be used to validate API responses
export const selectRolesSchema = createSelectSchema(printers);

View File

@@ -0,0 +1,30 @@
import {
integer,
pgTable,
uuid,
uniqueIndex,
text,
timestamp,
} from "drizzle-orm/pg-core";
import { createSelectSchema } from "drizzle-zod";
export const prodlabels = pgTable(
"prodlabels",
{
label_id: uuid("label_id").defaultRandom().primaryKey(),
printerID: integer("printerID"),
printerName: text("printerName"),
line: integer("line"),
runningNr: integer("runningNr").notNull(),
status: text("status"),
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})`),
uniqueIndex("runningNr").on(table.runningNr),
]
);
export const prodlabelsSchema = createSelectSchema(prodlabels);

View File

@@ -1,7 +1,14 @@
import {text, pgTable, timestamp, uuid, uniqueIndex, jsonb} from "drizzle-orm/pg-core";
import {createSelectSchema} from "drizzle-zod";
import {z} from "zod";
import {modules} from "./modules.js";
import {
text,
pgTable,
timestamp,
uuid,
uniqueIndex,
jsonb,
} from "drizzle-orm/pg-core";
import { createSelectSchema } from "drizzle-zod";
import { z } from "zod";
import { modules } from "./modules.js";
export const settings = pgTable(
"settings",

File diff suppressed because it is too large Load Diff

View File

@@ -8,11 +8,12 @@
"build": "rimraf dist && tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview",
"shad": "npx shadcn@canary add ",
"shad": "npx shadcn@latest add ",
"checkupdates": "npm-check-updates"
},
"dependencies": {
"@hookform/resolvers": "^4.1.3",
"@radix-ui/react-accordion": "^1.2.3",
"@radix-ui/react-avatar": "^1.1.3",
"@radix-ui/react-checkbox": "^1.1.4",
"@radix-ui/react-collapsible": "^1.1.3",
@@ -20,12 +21,14 @@
"@radix-ui/react-dropdown-menu": "^2.1.6",
"@radix-ui/react-label": "^2.1.2",
"@radix-ui/react-popover": "^1.1.6",
"@radix-ui/react-scroll-area": "^1.2.3",
"@radix-ui/react-select": "^2.1.6",
"@radix-ui/react-separator": "^1.1.2",
"@radix-ui/react-slot": "^1.1.2",
"@radix-ui/react-tabs": "^1.1.3",
"@radix-ui/react-tooltip": "^1.1.8",
"@tailwindcss/vite": "^4.0.15",
"@tanstack/react-form": "^1.2.1",
"@tanstack/react-query": "^5.69.0",
"@tanstack/react-router": "^1.114.27",
"@tanstack/react-table": "^8.21.2",
@@ -45,6 +48,7 @@
"react-dom": "^19.0.0",
"react-grid-layout": "^1.5.1",
"react-hook-form": "^7.54.2",
"react-resizable-panels": "^2.1.7",
"sonner": "^2.0.1",
"tailwind-merge": "^3.0.2",
"tailwindcss": "^4.0.15",

View File

@@ -1,12 +1,12 @@
import { LstCard } from "@/components/extendedUI/LstCard";
import { Skeleton } from "@/components/ui/skeleton";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { useSessionStore } from "@/lib/store/sessionStore";
import { useModuleStore } from "@/lib/store/useModuleStore";
@@ -21,105 +21,121 @@ import StopServer from "./StopServer";
import StartServer from "./StartServer";
export type Servers = {
server_id?: string;
sName?: string;
serverDNS?: string;
plantToken?: string;
idAddress: string;
lastUpdated: string;
isUpgrading: boolean;
server_id?: string;
sName?: string;
serverDNS?: string;
plantToken?: string;
idAddress: string;
lastUpdated: string;
isUpgrading: boolean;
};
export default function ServerPage() {
const { user, token } = useSessionStore();
const { modules } = useModuleStore();
const router = useRouter();
const { user, token } = useSessionStore();
const { modules } = useModuleStore();
const router = useRouter();
const { data, isError, error, isLoading } = useQuery(getServers(token ?? ""));
const { data, isError, error, isLoading } = useQuery(
getServers(token ?? "")
);
const adminModule = modules.filter((n) => n.name === "admin");
const userLevel =
user?.roles?.filter((r) => r.module_id === adminModule[0].module_id) || [];
const adminModule = modules.filter((n) => n.name === "admin");
const userLevel =
user?.roles?.filter((r) => r.module_id === adminModule[0].module_id) ||
[];
if (!adminModule[0]?.roles?.includes(userLevel[0]?.role)) {
router.navigate({ to: "/" });
}
if (!adminModule[0]?.roles?.includes(userLevel[0]?.role)) {
router.navigate({ to: "/" });
}
if (isError) {
return <div>{JSON.stringify(error)}</div>;
}
if (isError) {
return <div>{JSON.stringify(error)}</div>;
}
console.log(data);
return (
<LstCard className="m-2 flex place-content-center w-dvh">
<Table>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>Server</TableHead>
<TableHead>PlantToken</TableHead>
<TableHead>IP Address</TableHead>
<TableHead>Date Last updated</TableHead>
<TableHead>Update Server</TableHead>
</TableRow>
</TableHeader>
{isLoading ? (
<>
<TableBody>
{Array(10)
.fill(0)
.map((_, i) => (
<TableRow key={i}>
<TableCell className="font-medium">
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
</TableRow>
))}
</TableBody>
</>
) : (
<TableBody>
{data?.map((server: Servers) => {
const strippedDate = server.lastUpdated.replace("Z", ""); // Remove Z
const formattedDate = format(strippedDate, "MM/dd/yyyy hh:mm a");
return (
<TableRow key={server.server_id}>
<TableCell className="font-medium">{server.sName}</TableCell>
<TableCell className="font-medium">
{server.serverDNS}
</TableCell>
<TableCell className="font-medium">
{server.plantToken}
</TableCell>
<TableCell className="font-medium">
{server.idAddress}
</TableCell>
<TableCell className="font-medium">{formattedDate}</TableCell>
<TableCell className="font-medium">
{adminUrlCheck() && (
<div className="flex flex-row">
<UpdateServer server={server} token={token as string} />
<StartServer />
<StopServer />
<RestartServer />
</div>
)}
</TableCell>
</TableRow>
);
})}
</TableBody>
)}
</Table>
</LstCard>
);
//console.log(data);
return (
<LstCard className="m-2 flex place-content-center w-dvh">
<Table>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>Server</TableHead>
<TableHead>PlantToken</TableHead>
<TableHead>IP Address</TableHead>
<TableHead>Date Last updated</TableHead>
<TableHead>Update Server</TableHead>
</TableRow>
</TableHeader>
{isLoading ? (
<>
<TableBody>
{Array(10)
.fill(0)
.map((_, i) => (
<TableRow key={i}>
<TableCell className="font-medium">
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
</TableRow>
))}
</TableBody>
</>
) : (
<TableBody>
{data?.map((server: Servers) => {
const strippedDate = server.lastUpdated.replace(
"Z",
""
); // Remove Z
const formattedDate = format(
strippedDate,
"MM/dd/yyyy hh:mm a"
);
return (
<TableRow key={server.server_id}>
<TableCell className="font-medium">
{server.sName}
</TableCell>
<TableCell className="font-medium">
{server.serverDNS}
</TableCell>
<TableCell className="font-medium">
{server.plantToken}
</TableCell>
<TableCell className="font-medium">
{server.idAddress}
</TableCell>
<TableCell className="font-medium">
{formattedDate}
</TableCell>
<TableCell className="font-medium">
{adminUrlCheck() && (
<div className="flex flex-row">
<UpdateServer
server={server}
token={token as string}
/>
<StartServer />
<StopServer />
<RestartServer />
</div>
)}
</TableCell>
</TableRow>
);
})}
</TableBody>
)}
</Table>
</LstCard>
);
}

View File

@@ -0,0 +1,43 @@
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
import { getUsers } from "@/utils/querys/admin/users";
import { useQuery } from "@tanstack/react-query";
import UserCard from "./components/UserCard";
export default function UserPage() {
const { data, isError, error, isLoading } = useQuery(getUsers());
if (isLoading) return <div className="m-auto">Loading users...</div>;
if (isError)
return (
<div className="m-auto">
There was an error getting the users.... {JSON.stringify(error)}
</div>
);
return (
<div className="m-2 w-dvw">
<Accordion type="single" collapsible>
{data.map((u: any) => {
return (
<AccordionItem key={u.user_id} value={u.user_id}>
<AccordionTrigger>
<span>{u.username}</span>
</AccordionTrigger>
<AccordionContent>
<div>
<UserCard user={u} />
</div>
</AccordionContent>
</AccordionItem>
);
})}
</Accordion>
</div>
);
}

View File

@@ -0,0 +1,238 @@
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectLabel,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { DebugButton } from "@/utils/formStuff/debugButton";
import { userFormOptions } from "@/utils/formStuff/options/userformOptions";
import { generatePassword } from "@/utils/passwordGen";
import { getUsers } from "@/utils/querys/admin/users";
import { useForm } from "@tanstack/react-form";
import { useQuery } from "@tanstack/react-query";
import axios from "axios";
import { toast } from "sonner";
export default function UserCard(data: any) {
const token = localStorage.getItem("auth_token");
const { refetch } = useQuery(getUsers());
const form = useForm({
...userFormOptions(data.user),
onSubmit: async ({ value }) => {
// Do something with form data
const userData = { ...value, user_id: data.user.user_id };
try {
const res = await axios.patch(
"/api/auth/updateuser",
userData,
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);
if (res.data.success) {
toast.success(res.data.message);
refetch();
form.reset();
} else {
res.data.message;
}
} catch (error) {
console.log(error);
}
},
});
return (
<div>
<form
onSubmit={(e) => {
e.preventDefault();
e.stopPropagation();
}}
>
<form.Field
name="username"
validators={{
// We can choose between form-wide and field-specific validators
onChange: ({ value }) =>
value.length > 3
? undefined
: "Username must be longer than 3 letters",
}}
children={(field) => {
return (
<div className="m-2 min-w-48 max-w-96 p-2">
<Label htmlFor="username">Username</Label>
<Input
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
//type="number"
onChange={(e) =>
field.handleChange(e.target.value)
}
/>
{field.state.meta.errors.length ? (
<em>{field.state.meta.errors.join(",")}</em>
) : null}
</div>
);
}}
/>
<form.Field
name="email"
validators={{
// We can choose between form-wide and field-specific validators
onChange: ({ value }) =>
value.length > 3
? undefined
: "You must enter a correct ",
}}
children={(field) => {
return (
<div className="m-2 min-w-48 max-w-96 p-2">
<Label htmlFor="email">Email</Label>
<Input
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
//type="number"
onChange={(e) =>
field.handleChange(e.target.value)
}
/>
{field.state.meta.errors.length ? (
<em>{field.state.meta.errors.join(",")}</em>
) : null}
</div>
);
}}
/>
<form.Field
name="role"
//listeners={{onChange: ({value})=>{}}}
children={(field) => {
return (
<div className="m-2 min-w-48 max-w-96 p-2">
<Label htmlFor={field.name}>Select role</Label>
<Select
value={field.state.value}
onValueChange={field.handleChange}
>
<SelectTrigger className="w-[180px]">
<SelectValue
id={field.name}
placeholder="Select Role"
/>
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>Roles</SelectLabel>
<SelectItem value="viewer">
Viewer
</SelectItem>
<SelectItem value="operator">
Operator
</SelectItem>
<SelectItem value="manager">
Manager
</SelectItem>
<SelectItem value="admin">
Admin
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
);
}}
/>
<form.Field
name="password"
validators={{
onChangeAsyncDebounceMs: 500,
onChangeAsync: ({ value }) => {
if (
window.location.pathname.includes("/users") &&
value.length === 0
) {
return;
}
if (value.length < 4) {
return "Password must be at least 4 characters long.";
}
if (!/[A-Z]/.test(value)) {
return "Password must contain at least one uppercase letter.";
}
if (!/[a-z]/.test(value)) {
return "Password must contain at least one lower case letter.";
}
if (!/[0-9]/.test(value)) {
return "Password must contain at least one number.";
}
if (
!/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(
value
)
) {
return "Password must contain at least one special character.";
}
},
}}
children={(field) => {
return (
<div className="m-2 p-2">
<Label htmlFor="password">
Change Password
</Label>
<div className="mt-2 flex flex-row">
<Input
className="min-w-48 max-w-96"
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
//type="number"
onChange={(e) =>
field.handleChange(e.target.value)
}
/>
<Button
className="ml-2"
onClick={() =>
field.handleChange(
generatePassword(8)
)
}
>
Random password
</Button>
<DebugButton data={form.state.values} />
</div>
{field.state.meta.errors.length ? (
<em>{field.state.meta.errors.join(",")}</em>
) : null}
</div>
);
}}
/>
</form>
<div>
<Button onClick={form.handleSubmit}>Save</Button>
</div>
</div>
);
}

View File

@@ -1,4 +1,14 @@
import {Atom, Logs, Minus, Plus, Server, Settings, ShieldCheck, Users, Webhook} from "lucide-react";
import {
Atom,
Logs,
Minus,
Plus,
Server,
Settings,
ShieldCheck,
Users,
Webhook,
} from "lucide-react";
import {
SidebarGroup,
SidebarGroupContent,
@@ -10,7 +20,11 @@ import {
SidebarMenuSubButton,
SidebarMenuSubItem,
} from "../../ui/sidebar";
import {Collapsible, CollapsibleContent, CollapsibleTrigger} from "../../ui/collapsible";
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from "../../ui/collapsible";
const items = [
{
@@ -53,9 +67,9 @@ const data = {
},
{
title: "Users",
url: "#",
url: "/users",
icon: Users,
isActive: false,
isActive: true,
},
{
title: "UCD",
@@ -82,7 +96,11 @@ export function AdminSideBar() {
<SidebarGroupContent>
<SidebarMenu>
{data.navMain.map((item, index) => (
<Collapsible key={item.title} defaultOpen={index === 1} className="group/collapsible">
<Collapsible
key={item.title}
defaultOpen={index === 1}
className="group/collapsible"
>
<SidebarMenuItem>
<CollapsibleTrigger asChild>
<SidebarMenuButton>
@@ -96,15 +114,25 @@ export function AdminSideBar() {
<CollapsibleContent>
<SidebarMenuSub>
{item.items.map((item) => (
<SidebarMenuSubItem key={item.title}>
<SidebarMenuSubItem
key={item.title}
>
{item.isActive && (
<SidebarMenuSubButton asChild>
<SidebarMenuSubButton
asChild
>
<a
href={item.url}
target={item.newWindow ? "_blank" : "_self"}
target={
item.newWindow
? "_blank"
: "_self"
}
>
<item.icon />
<span>{item.title}</span>
<span>
{item.title}
</span>
</a>
</SidebarMenuSubButton>
)}

View File

@@ -0,0 +1,131 @@
import axios from "axios";
import { LstCard } from "../extendedUI/LstCard";
import { Button } from "../ui/button";
import { ScrollArea } from "../ui/scroll-area";
import { Skeleton } from "../ui/skeleton";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "../ui/table";
import { toast } from "sonner";
const currentPallets = [
{ key: "line", label: "Line" },
{ key: "runningNr", label: "Running #" },
{ key: "upd_date", label: "Date Scanned" },
{ key: "waitingfor", label: "Waiting For" },
{ key: "clear", label: "Clear" },
];
const currentTags = [
{ key: "line", label: "Line" },
{ key: "printerName", label: "Printer" },
{ key: "runningNr", label: "Running #" },
{ key: "upd_date", label: "Label date" },
{ key: "status", label: "Label Status" },
];
export default function WrapperManualTrigger() {
const cameraTrigger = async () => {
try {
const res = await axios.get("/ocme/api/v1/manualCameraTrigger");
if (res.data.success) {
toast.success(res.data.message);
return;
}
if (!res.data.success) {
toast.error(res.data.message);
}
} catch (error) {
console.log(error);
//stoast.success(error.data.message);
}
};
return (
<LstCard className="m-2 p-2">
<ScrollArea className="max-h-[200px]">
<span>Wrapper Pallet Info</span>
<Table>
<TableHeader>
<TableRow>
{currentPallets.map((l) => (
<TableHead key={l.key}>{l.label}</TableHead>
))}
</TableRow>
</TableHeader>
<TableBody>
{Array(3)
.fill(0)
.map((_, i) => (
<TableRow key={i}>
<TableCell className="font-medium">
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</ScrollArea>
<ScrollArea className="max-h-[200px]">
<Table>
<TableHeader>
<TableRow>
{currentTags.map((l) => (
<TableHead key={l.key}>{l.label}</TableHead>
))}
</TableRow>
</TableHeader>
<TableBody>
{Array(3)
.fill(0)
.map((_, i) => (
<TableRow key={i}>
<TableCell className="font-medium">
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</ScrollArea>
<div>
<hr />
<p className="text-center mb-3">Manual Triggers</p>
<div className="flex flex-row justify-between">
<Button onClick={cameraTrigger}>Camera</Button>
<Button>Rfid</Button>
</div>
</div>
</LstCard>
);
}

View File

@@ -1,14 +1,27 @@
import {toast} from "sonner";
import {LstCard} from "../extendedUI/LstCard";
import {Button} from "../ui/button";
import {Input} from "../ui/input";
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from "../ui/table";
import {Skeleton} from "../ui/skeleton";
import { toast } from "sonner";
import { LstCard } from "../extendedUI/LstCard";
import { Button } from "../ui/button";
import { Input } from "../ui/input";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "../ui/table";
import { Skeleton } from "../ui/skeleton";
//import CycleCountLog from "./CycleCountLog";
import {Select, SelectContent, SelectItem, SelectTrigger, SelectValue} from "../ui/select";
import {Controller, useForm} from "react-hook-form";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "../ui/select";
import { Controller, useForm } from "react-hook-form";
import axios from "axios";
import {useState} from "react";
import { useState } from "react";
export default function OcmeCycleCount() {
const token = localStorage.getItem("auth_token");
@@ -18,7 +31,7 @@ export default function OcmeCycleCount() {
register,
handleSubmit,
//watch,
formState: {errors},
formState: { errors },
reset,
control,
} = useForm();
@@ -29,7 +42,7 @@ export default function OcmeCycleCount() {
toast.success(`Cycle count started`);
try {
const res = await axios.post("/ocme/api/v1/cyclecount", data, {
headers: {Authorization: `Bearer ${token}`},
headers: { Authorization: `Bearer ${token}` },
});
toast.success(res.data.message);
setData(res.data.data);
@@ -45,20 +58,25 @@ export default function OcmeCycleCount() {
<div className="flex flex-row w-screen">
<div className="m-2 w-5/6">
<LstCard>
<p className="ml-2">Please enter the name or laneID you want to cycle count.</p>
<p className="ml-2">
Please enter the name or laneID you want to cycle count.
</p>
<div>
<form onSubmit={handleSubmit(onSubmit)}>
<div className="flex justify-between">
<div className="m-2 flex flex-row">
<Input
placeholder="enter lane: L064"
className={errors.lane ? "border-red-500" : ""}
className={
errors.lane ? "border-red-500" : ""
}
aria-invalid={!!errors.lane}
{...register("lane", {
required: true,
minLength: {
value: 3,
message: "The lane is too short!",
message:
"The lane is too short!",
},
})}
/>
@@ -68,25 +86,39 @@ export default function OcmeCycleCount() {
name="laneType"
defaultValue={""}
render={({
field: {onChange},
field: { onChange },
fieldState: {},
//formState,
}) => (
<Select onValueChange={onChange}>
<Select
onValueChange={onChange}
>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="Select name or id" />
</SelectTrigger>
<SelectContent>
<SelectItem value="name">Name</SelectItem>
<SelectItem value="laneId">Lane ID</SelectItem>
<SelectItem value="name">
Name
</SelectItem>
<SelectItem value="laneId">
Lane ID
</SelectItem>
</SelectContent>
</Select>
)}
/>
</div>
</div>
<Button className="m-2" type="submit" disabled={counting}>
{counting ? <span>Counting...</span> : <span>CycleCount</span>}
<Button
className="m-2"
type="submit"
disabled={counting}
>
{counting ? (
<span>Counting...</span>
) : (
<span>CycleCount</span>
)}
</Button>
</div>
</form>
@@ -108,41 +140,43 @@ export default function OcmeCycleCount() {
{data.length === 0 ? (
<TableBody>
{Array(10)
.fill(0)
.map((_, i) => (
<TableRow key={i}>
<TableCell className="font-medium">
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
</TableRow>
))}
.fill(0)
.map((_, i) => (
<TableRow key={i}>
<TableCell className="font-medium">
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
</TableRow>
))}
</TableBody>
) : (
<>
{data.map((i: any) => {
let classname = ``;
if (i.info === "Quality Check Required") {
if (
i.info === "Quality Check Required"
) {
classname = `bg-red-500`;
}
if (i.info === "Sent to Inv") {
@@ -150,24 +184,46 @@ export default function OcmeCycleCount() {
}
return (
<TableRow key={i.runningNumber}>
<TableCell className={`font-medium ${classname}`}>
<TableCell
className={`font-medium ${classname}`}
>
{i.alpla_laneID}
</TableCell>
<TableCell className={`font-medium ${classname}`}>
<TableCell
className={`font-medium ${classname}`}
>
{i.alpla_laneDescription}
</TableCell>
<TableCell className={`font-medium ${classname}`}>
<TableCell
className={`font-medium ${classname}`}
>
{i.Article}
</TableCell>
<TableCell className={`font-medium ${classname}`}>
<TableCell
className={`font-medium ${classname}`}
>
{i.alpla_laneDescription}
</TableCell>
<TableCell className={`font-medium ${classname}`}>
<TableCell
className={`font-medium ${classname}`}
>
{i.runningNumber}
</TableCell>
<TableCell className={`font-medium ${classname}`}>{i.ocme}</TableCell>
<TableCell className={`font-medium ${classname}`}>{i.stock}</TableCell>
<TableCell className={`font-medium ${classname}`}>{i.info}</TableCell>
<TableCell
className={`font-medium ${classname}`}
>
{i.ocme}
</TableCell>
<TableCell
className={`font-medium ${classname}`}
>
{i.stock}
</TableCell>
<TableCell
className={`font-medium ${classname}`}
>
{i.info}
</TableCell>
</TableRow>
);
})}

View File

@@ -1,23 +1,30 @@
import {LstCard} from "@/components/extendedUI/LstCard";
import { LstCard } from "@/components/extendedUI/LstCard";
import {Skeleton} from "@/components/ui/skeleton";
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table";
import { Skeleton } from "@/components/ui/skeleton";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
// import {useSessionStore} from "@/lib/store/sessionStore";
// import {useSettingStore} from "@/lib/store/useSettings";
import {useQuery} from "@tanstack/react-query";
import {getlabels} from "@/utils/querys/production/labels";
import {format} from "date-fns";
import { useQuery } from "@tanstack/react-query";
import { getlabels } from "@/utils/querys/production/labels";
import { format } from "date-fns";
const labelLogs = [
{key: "line", label: "Line"},
{key: "printerName", label: "Printer"},
{key: "runningNr", label: "Running #"},
{key: "upd_date", label: "Label date"},
{key: "status", label: "Label Status"},
{ key: "line", label: "Line" },
{ key: "printerName", label: "Printer" },
{ key: "runningNr", label: "Running #" },
{ key: "upd_date", label: "Label date" },
{ key: "status", label: "Label Status" },
//{key: "reprint", label: "Reprint"}, // removing the reprint button for now until repritning is working as intended
];
export default function LabelLog() {
const {data, isError, isLoading} = useQuery(getlabels("4"));
const { data, isError, isLoading } = useQuery(getlabels("4"));
//const {user} = useSessionStore();
//const {settings} = useSettingStore();
//const server = settings.filter((n) => n.name === "server")[0]?.value || "";
@@ -40,33 +47,33 @@ export default function LabelLog() {
<TableBody>
{Array(7)
.fill(0)
.map((_, i) => (
<TableRow key={i}>
<TableCell className="font-medium">
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
</TableRow>
))}
.fill(0)
.map((_, i) => (
<TableRow key={i}>
<TableCell className="font-medium">
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</LstCard>
</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>
@@ -82,39 +89,50 @@ export default function LabelLog() {
<>
<TableBody>
{Array(7)
.fill(0)
.map((_, i) => (
<TableRow key={i}>
<TableCell className="font-medium">
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
</TableRow>
))}
.fill(0)
.map((_, i) => (
<TableRow key={i}>
<TableCell className="font-medium">
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
</TableRow>
))}
</TableBody>
</>
) : (
<TableBody>
{data?.map((label: any) => (
{labelData.map((label: any) => (
<TableRow key={label.runningNr}>
<TableCell className="font-medium">{label.line}</TableCell>
<TableCell className="font-medium">{label.printerName}</TableCell>
<TableCell className="font-medium">{label.runningNr}</TableCell>
<TableCell className="font-medium">
{format(label.upd_date, "M/d/yyyy hh:mm")}
{label.line}
</TableCell>
<TableCell className="font-medium">
{label.printerName}
</TableCell>
<TableCell className="font-medium">
{label.runningNr}
</TableCell>
<TableCell className="font-medium">
{format(
label?.upd_date.replace("Z", ""),
"M/d/yyyy hh:mm"
)}
</TableCell>
<TableCell className="font-medium">
{label.status}
</TableCell>
<TableCell className="font-medium">{label.status}</TableCell>
</TableRow>
))}
</TableBody>

View File

@@ -1,14 +1,22 @@
import {LstCard} from "@/components/extendedUI/LstCard";
import { LstCard } from "@/components/extendedUI/LstCard";
import {Skeleton} from "@/components/ui/skeleton";
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table";
import {useSessionStore} from "@/lib/store/sessionStore";
import {useSettingStore} from "@/lib/store/useSettings";
import {LotType} from "@/types/lots";
import {getlots} from "@/utils/querys/production/lots";
import {useQuery} from "@tanstack/react-query";
import { Skeleton } from "@/components/ui/skeleton";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { useSessionStore } from "@/lib/store/sessionStore";
import { useSettingStore } from "@/lib/store/useSettings";
import { LotType } from "@/types/lots";
import { getlots } from "@/utils/querys/production/lots";
import { useQuery } from "@tanstack/react-query";
import ManualPrint from "./ManualPrinting/ManualPrint";
import ManualPrintForm from "./ManualPrinting/ManualPrintForm";
import { ScrollArea } from "@/components/ui/scroll-area";
let lotColumns = [
{
@@ -57,13 +65,11 @@ let lotColumns = [
// },
];
export default function Lots() {
const {data, isError, isLoading} = useQuery(getlots());
const {user} = useSessionStore();
const {settings} = useSettingStore();
const { data, isError, isLoading } = useQuery(getlots());
const { user } = useSessionStore();
const { settings } = useSettingStore();
const server = settings.filter((n) => n.name === "server")[0]?.value || "";
console.log(server);
const roles = ["admin", "manager", "operator"];
if (user && roles.includes(user.role)) {
@@ -83,140 +89,165 @@ export default function Lots() {
if (isError) {
return (
<div className="m-2 p-2 min-h-2/5">
<LstCard>
<p className="text-center">Current Assigned lots</p>
<Table>
<TableHeader>
<TableRow>
{lotColumns.map((l) => (
<TableHead key={l.key}>{l.label}</TableHead>
))}
</TableRow>
</TableHeader>
<TableBody>
{Array(10)
.fill(0)
.map((_, i) => (
<TableRow key={i}>
<TableCell className="font-medium">
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<ScrollArea className="max-h-1/2 rounded-md border p-4">
<LstCard>
<p className="text-center">Current Assigned lots</p>
<Table>
<TableHeader>
<TableRow>
{lotColumns.map((l) => (
<TableHead key={l.key}>
{l.label}
</TableHead>
))}
</TableRow>
))}
</TableBody>
</Table>
</LstCard>
</TableHeader>
<TableBody>
{Array(10)
.fill(0)
.map((_, i) => (
<TableRow key={i}>
<TableCell className="font-medium">
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</LstCard>
</ScrollArea>
</div>
);
}
return (
<LstCard className="m-2 p-2 min-h-2/5">
<p className="text-center">Current Assigned lots</p>
<Table>
<TableHeader>
<TableRow>
{lotColumns.map((l) => (
<TableHead key={l.key}>{l.label}</TableHead>
))}
</TableRow>
</TableHeader>
{isLoading ? (
<>
<ScrollArea className="h-[400px]">
<p className="text-center">Current Assigned lots</p>
<Table>
<TableHeader>
<TableRow>
{lotColumns.map((l) => (
<TableHead key={l.key}>{l.label}</TableHead>
))}
</TableRow>
</TableHeader>
{isLoading ? (
<>
<TableBody>
{Array(10)
.fill(0)
.map((_, i) => (
<TableRow key={i}>
<TableCell className="font-medium">
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
</TableRow>
))}
</TableBody>
</>
) : (
<TableBody>
{Array(10)
.fill(0)
.map((_, i) => (
<TableRow key={i}>
{data?.map((lot: LotType) => (
<TableRow key={lot.LabelOnlineID}>
<TableCell className="font-medium">
<Skeleton className="h-4" />
{lot.MachineLocation}
</TableCell>
<TableCell>
<Skeleton className="h-4" />
<TableCell className="font-medium">
{lot.AV}
</TableCell>
<TableCell>
<Skeleton className="h-4" />
<TableCell className="font-medium">
{lot.Alias}
</TableCell>
<TableCell>
<Skeleton className="h-4" />
<TableCell className="font-medium">
{lot.LOT}
</TableCell>
<TableCell>
<Skeleton className="h-4" />
<TableCell className="font-medium">
{lot.ProlinkLot}
</TableCell>
<TableCell>
<Skeleton className="h-4" />
<TableCell className="font-medium">
{lot.PlannedQTY}
</TableCell>
<TableCell>
<Skeleton className="h-4" />
<TableCell className="font-medium">
{lot.Produced}
</TableCell>
<TableCell>
<Skeleton className="h-4" />
<TableCell className="font-medium">
{lot.Remaining}
</TableCell>
<TableCell>
<Skeleton className="h-4" />
<TableCell className="font-medium">
{lot.overPrinting}
</TableCell>
{user && roles.includes(user.role) && (
<>
{server === "usday1vms006" ||
server === "localhost" ? (
<>
<TableCell className="flex justify-center">
<ManualPrintForm />
</TableCell>
</>
) : (
<TableCell className="flex justify-center">
<ManualPrint lot={lot} />
</TableCell>
)}
</>
)}
</TableRow>
))}
</TableBody>
</>
) : (
<TableBody>
{data?.map((lot: LotType) => (
<TableRow key={lot.LabelOnlineID}>
<TableCell className="font-medium">{lot.MachineLocation}</TableCell>
<TableCell className="font-medium">{lot.AV}</TableCell>
<TableCell className="font-medium">{lot.Alias}</TableCell>
<TableCell className="font-medium">{lot.LOT}</TableCell>
<TableCell className="font-medium">{lot.ProlinkLot}</TableCell>
<TableCell className="font-medium">{lot.PlannedQTY}</TableCell>
<TableCell className="font-medium">{lot.Produced}</TableCell>
<TableCell className="font-medium">{lot.Remaining}</TableCell>
<TableCell className="font-medium">{lot.overPrinting}</TableCell>
{user && roles.includes(user.role) && (
<>
{server === "usday1vms006" || server === "localhost" ? (
<>
<TableCell className="flex justify-center">
<ManualPrintForm lot={lot} />
</TableCell>
</>
) : (
<TableCell className="flex justify-center">
<ManualPrint lot={lot} />
</TableCell>
)}
</>
)}
</TableRow>
))}
</TableBody>
)}
</Table>
)}
</Table>
</ScrollArea>
</LstCard>
);
}

View File

@@ -1,4 +1,4 @@
import {Button} from "@/components/ui/button";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
@@ -8,8 +8,8 @@ import {
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import {Input} from "@/components/ui/input";
import {Label} from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
Select,
SelectContent,
@@ -19,81 +19,81 @@ import {
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import {Textarea} from "@/components/ui/textarea";
import {useSessionStore} from "@/lib/store/sessionStore";
import {useSettingStore} from "@/lib/store/useSettings";
import {LotType} from "@/types/lots";
import { Textarea } from "@/components/ui/textarea";
import { useSettingStore } from "@/lib/store/useSettings";
import axios from "axios";
import {Tag} from "lucide-react";
import {useState} from "react";
import {Controller, useForm} from "react-hook-form";
import {toast} from "sonner";
import {manualPrintLabels} from "./ManualPrintLabel";
import { Tag } from "lucide-react";
import { useState } from "react";
import { Controller, useForm } from "react-hook-form";
import { toast } from "sonner";
const printReason = [
{key: "printerIssue", label: "Printer Related"},
{key: "strapper", label: "Strapper Error"},
{key: "manualCheck", label: "20th pallet check"},
{key: "outOfSync", label: "Labeler Out of Sync"},
{ key: "printerIssue", label: "Printer Related" },
{ key: "missingRfidTag", label: "Missing or incorrect tag" },
{ key: "strapper", label: "Strapper Error" },
{ key: "manualCheck", label: "20th pallet check" },
{ key: "outOfSync", label: "Labeler Out of Sync" },
];
export default function ManualPrintForm({lot}: {lot: LotType}) {
const {user} = useSessionStore();
export default function ManualPrintForm() {
const token = localStorage.getItem("auth_token");
const {settings} = useSettingStore();
const { settings } = useSettingStore();
const [open, setOpen] = useState(false);
const server = settings.filter((n) => n.name === "server")[0]?.value;
// const serverPort = settings.filter((n) => n.name === "serverPort")[0]?.value;
// const serverUrl = `http://${server}:${serverPort}`;
// what is the dyco set to? rfid or dyco
const dyco = settings.filter((n) => n.name === "dycoPrint");
const {
register,
handleSubmit,
//watch,
formState: {errors},
formState: { errors },
reset,
control,
} = useForm();
const handlePrintLabel = async (lot: LotType) => {
//console.log(lot);
const labels: any = await manualPrintLabels(lot, user);
if (labels.success) {
toast.success(labels.message);
} else {
toast.error(labels.message);
}
};
const handleManualPrintLog = async (logData: any, lot: LotType) => {
const handleManualPrintLog = async (logData: any) => {
// toast.success(`A new label was sent to printer: ${lot.PrinterName} for line ${lot.MachineDescription} `);
const logdataUrl = `/api/ocp/manualLabelLog`;
const logdataUrl = `/api/ocp/manuallabellog`;
axios
.post(logdataUrl, logData, {headers: {Authorization: `Bearer ${token}`}})
.then((d) => {
//console.log(d);
toast.success(d.data.message);
handlePrintLabel(lot);
reset();
})
.catch((e) => {
if (e.response.status === 500) {
toast.error(`Internal Server error please try again.`);
return {sucess: false};
}
.post(logdataUrl, logData, {
headers: { Authorization: `Bearer ${token}` },
})
.then((d) => {
console.log(d);
if (d.data.success) {
toast.success(d.data.message);
} else {
toast.error(d.data.message);
}
reset();
setOpen(false);
})
.catch((e) => {
if (e.response.status === 500) {
toast.error(`Internal Server error please try again.`);
return { sucess: false };
}
if (e.response.status === 401) {
//console.log(e.response);
toast.error(`You are not authorized to do this.`);
return {sucess: false};
}
});
if (e.response.status === 401) {
//console.log(e.response);
toast.error(`You are not authorized to do this.`);
return { sucess: false };
}
});
};
const onSubmit = (data: any) => {
console.log(data);
//console.log(data);
handleManualPrintLog(data, lot);
handleManualPrintLog(data);
};
const closeForm = () => {
reset();
setOpen(false);
};
return (
<Dialog
@@ -117,12 +117,14 @@ export default function ManualPrintForm({lot}: {lot: LotType}) {
<DialogHeader>
<DialogTitle>Edit profile</DialogTitle>
<DialogDescription>
Make changes to your profile here. Click save when you're done.
Make changes to your profile here. Click save when
you're done.
</DialogDescription>
</DialogHeader>
<form onSubmit={handleSubmit(onSubmit)}>
<p>
To manually print a label you must complete all the required fields below.
To manually print a label you must complete all the
required fields below.
<br />
If you clicked this in error just click close
</p>
@@ -133,7 +135,7 @@ export default function ManualPrintForm({lot}: {lot: LotType}) {
name="printReason"
defaultValue={""}
render={({
field: {onChange},
field: { onChange },
fieldState: {},
//formState,
}) => (
@@ -143,35 +145,46 @@ export default function ManualPrintForm({lot}: {lot: LotType}) {
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>Print Reasons</SelectLabel>
{printReason.map((printReason: any) => (
<SelectItem value={printReason.key}>{printReason.label}</SelectItem>
))}
<SelectLabel>
Print Reasons
</SelectLabel>
{printReason.map(
(printReason: any) => (
<SelectItem
value={printReason.key}
>
{printReason.label}
</SelectItem>
)
)}
</SelectGroup>
</SelectContent>
</Select>
)}
/>
) : (
<div>
<div className="m-2">
<Label htmlFor="printRason" className="m-1">
Why are you manually printing?
</Label>
<Input
type="text"
className={errors.printReason ? "border-red-500" : ""}
className={
errors.printReason ? "border-red-500" : ""
}
aria-invalid={!!errors.printReason}
{...register("printReason", {
required: true,
minLength: {
value: 5,
message: "To short of a reason please try again!",
message:
"To short of a reason please try again!",
},
})}
/>
</div>
)}
<div>
<div className="m-2">
<Label htmlFor="line" className="m-1">
"What is the line number you are printing?"
</Label>
@@ -180,11 +193,11 @@ export default function ManualPrintForm({lot}: {lot: LotType}) {
type="number"
className={errors.line ? "border-red-500" : ""}
aria-invalid={!!errors.line}
{...register("line", {required: true})}
{...register("line", { required: true })}
/>
</div>
<div>
<div className="m-2">
<Label htmlFor="initials" className="m-1">
Enter intials
</Label>
@@ -192,23 +205,55 @@ export default function ManualPrintForm({lot}: {lot: LotType}) {
//variant="underlined"
//label="Enter intials"
{...register("initials", {required: true})}
{...register("initials", { required: true })}
/>
</div>
<hr />
{dyco[0].value === "0" && (
<div>
<p>Enter the missing tag number.</p>
<hr />
<Label htmlFor="rfidTag" className="m-1">
Enter the tag number only Example
ALPLA000002541. only enter 2541
</Label>
<Input
type="text"
className={
errors.printReason ? "border-red-500" : ""
}
aria-invalid={!!errors.printReason}
{...register("rfidTag", {
required: true,
minLength: {
value: 1,
message: "Tag number is to short!",
},
})}
/>
</div>
)}
<div className="m-2">
<Textarea
//label="Comments"
placeholder="add more info as needed."
{...register("additionalComments")}
/>
</div>
<Textarea
//label="Comments"
placeholder="add more info as needed."
{...register("additionalComments")}
/>
<DialogFooter>
<Button color="danger" variant="default" onClick={() => setOpen(!open)}>
Close
</Button>
<Button color="primary" type="submit">
Print
</Button>
<div className="mt-3">
<Button
color="danger"
variant="default"
onClick={closeForm}
>
Close
</Button>
<Button color="primary" type="submit">
Print
</Button>
</div>
</DialogFooter>
</form>
</DialogContent>

View File

@@ -1,15 +1,15 @@
import {LotType} from "@/types/lots";
import { LotType } from "@/types/lots";
import axios from "axios";
export const manualPrintLabels = async (lot: LotType, user: any) => {
//console.log(lot);
const labelUrl = `/ocp/manualPrintAndFollow`;
const labelUrl = `/api/ocp/manualprintandfollow`;
try {
const res = await axios.post(
labelUrl,
{line: lot.MachineLocation, printerName: lot.PrinterName},
{headers: {Authorization: `Basic ${user?.prod}`}}
{ line: lot.MachineLocation, printerName: lot.PrinterName },
{ headers: { Authorization: `Basic ${user?.prod}` } }
);
if (res.data.success) {
@@ -19,7 +19,7 @@ export const manualPrintLabels = async (lot: LotType, user: any) => {
};
} else {
return {
success: true,
success: false,
message: `Line ${lot.MachineDescription} encountered an error printing labels: ${res.data.message}`,
};
}

View File

@@ -1,5 +1,154 @@
import {LstCard} from "@/components/extendedUI/LstCard";
import { LstCard } from "@/components/extendedUI/LstCard";
import { Button } from "@/components/ui/button";
import { Skeleton } from "@/components/ui/skeleton";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { getOcpLogs } from "@/utils/querys/production/ocpLogs";
import { useQuery } from "@tanstack/react-query";
import axios from "axios";
import { format } from "date-fns";
import { Trash } from "lucide-react";
import { toast } from "sonner";
const labelLogs = [
{ key: "message", label: "Error Message" },
{ key: "created_at", label: "ErrorDat" },
{ key: "clear", label: "Clear" },
//{key: "reprint", label: "Reprint"}, // removing the reprint button for now until repritning is working as intended
];
export default function OcpLogs() {
return <LstCard className="m-2 p-2">Ocp Logs</LstCard>;
const { data, isError, isLoading } = useQuery(getOcpLogs("4"));
const clearLog = async (log: any) => {
try {
const res = await axios.patch(`/api/logger/logs/${log.log_id}`);
if (res.data.success) {
toast.success(`Log message: ${log.message}, was just cleared`);
} else {
console.log(res);
toast.error(`There was an error clearing the message.`);
}
} catch (error) {
toast.error(`There was an error trying to clearing the message.`);
}
};
const logData = data ? data : [];
if (isError) {
return (
<div className="m-2 p-2 min-h-2/5">
<LstCard>
<p className="text-center">Labels for the last 2 hours</p>
<Table>
<TableHeader>
<TableRow>
{labelLogs.map((l) => (
<TableHead key={l.key}>{l.label}</TableHead>
))}
</TableRow>
</TableHeader>
<TableBody>
{Array(7)
.fill(0)
.map((_, i) => (
<TableRow key={i}>
<TableCell className="font-medium">
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</LstCard>
</div>
);
}
return (
<LstCard className="m-2 p-2 min-h-2/5">
<p className="text-center">Labels for the last 2 hours</p>
<Table>
<TableHeader>
<TableRow>
{labelLogs.map((l) => (
<TableHead key={l.key}>{l.label}</TableHead>
))}
</TableRow>
</TableHeader>
{isLoading ? (
<>
<TableBody>
{Array(7)
.fill(0)
.map((_, i) => (
<TableRow key={i}>
<TableCell className="font-medium">
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
</TableRow>
))}
</TableBody>
</>
) : (
<TableBody>
{logData.map((label: any) => (
<TableRow key={label.log_id}>
<TableCell className="font-medium max-w-5/6">
<p className="text-balance">
{label.message}
</p>
</TableCell>
<TableCell className="font-medium">
{format(
label?.created_at.replace("Z", ""),
"M/d/yyyy hh:mm"
)}
</TableCell>
<TableCell className="font-medium">
<Button
size="icon"
onClick={() => clearLog(label)}
>
<Trash />
</Button>
</TableCell>
</TableRow>
))}
</TableBody>
)}
</Table>
</LstCard>
);
}

View File

@@ -1,28 +1,53 @@
import WrapperManualTrigger from "@/components/ocme/WrapperCard";
import LabelLog from "./LabelLog";
import Lots from "./Lots";
import OcpLogs from "./OcpLogs";
import PrinterStatus from "./PrinterStatus";
import { useSettingStore } from "@/lib/store/useSettings";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
export default function OCPPage() {
const { settings } = useSettingStore();
const server = settings.filter((n) => n.plantToken === "usday1");
return (
<div className="h-dvh w-full overflow-hidden">
<div className="h-screen w-full ">
<div className="flex flex-wrap gap-2">
<div className="flex flex-col w-4/5 h-dvh">
<div className="">
<Lots />
</div>
<div className="flex flex-row">
<div className="w-1/2">
<LabelLog />
</div>
<div className="w-1/2">
<OcpLogs />
</div>
<div className="w-5/6 h-1/2">
<Tabs defaultValue="ocplogs" className="w-full">
<TabsList className="grid w-full grid-cols-2">
<TabsTrigger value="ocplogs">
OcpLogs
</TabsTrigger>
<TabsTrigger value="labels">Labels</TabsTrigger>
</TabsList>
<TabsContent value="ocplogs">
<div className="w-full">
<OcpLogs />
</div>
</TabsContent>
<TabsContent value="labels">
<div className="w-full">
<LabelLog />
</div>
</TabsContent>
</Tabs>
</div>
</div>
<div className="w-1/6">
<PrinterStatus />
<div className="w-1/6 flex flex-col">
{server && (
<div>
<WrapperManualTrigger />
</div>
)}
<div>
<PrinterStatus />
</div>
</div>
</div>
</div>

View File

@@ -1,6 +1,14 @@
import {LstCard} from "@/components/extendedUI/LstCard";
import {Skeleton} from "@/components/ui/skeleton";
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table";
import { LstCard } from "@/components/extendedUI/LstCard";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Skeleton } from "@/components/ui/skeleton";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
let printerCols = [
{
@@ -19,34 +27,37 @@ let printerCols = [
export default function PrinterStatus() {
return (
<LstCard className="m-2 p-2">
<p className="text-center">Printer Status</p>
<Table>
<TableHeader>
<TableRow>
{printerCols.map((l) => (
<TableHead key={l.key}>{l.label}</TableHead>
))}
</TableRow>
</TableHeader>
<ScrollArea className="max-h-[300px]">
<p className="text-center">Printer Status</p>
<TableBody>
{Array(10)
.fill(0)
.map((_, i) => (
<TableRow key={i}>
<TableCell className="font-medium">
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<Table>
<TableHeader>
<TableRow>
{printerCols.map((l) => (
<TableHead key={l.key}>{l.label}</TableHead>
))}
</TableRow>
))}
</TableBody>
</Table>
</TableHeader>
<TableBody>
{Array(5)
.fill(0)
.map((_, i) => (
<TableRow key={i}>
<TableCell className="font-medium">
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</ScrollArea>
</LstCard>
);
}

View File

@@ -0,0 +1,64 @@
import * as React from "react"
import * as AccordionPrimitive from "@radix-ui/react-accordion"
import { ChevronDownIcon } from "lucide-react"
import { cn } from "@/lib/utils"
function Accordion({
...props
}: React.ComponentProps<typeof AccordionPrimitive.Root>) {
return <AccordionPrimitive.Root data-slot="accordion" {...props} />
}
function AccordionItem({
className,
...props
}: React.ComponentProps<typeof AccordionPrimitive.Item>) {
return (
<AccordionPrimitive.Item
data-slot="accordion-item"
className={cn("border-b last:border-b-0", className)}
{...props}
/>
)
}
function AccordionTrigger({
className,
children,
...props
}: React.ComponentProps<typeof AccordionPrimitive.Trigger>) {
return (
<AccordionPrimitive.Header className="flex">
<AccordionPrimitive.Trigger
data-slot="accordion-trigger"
className={cn(
"focus-visible:border-ring focus-visible:ring-ring/50 flex flex-1 items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180",
className
)}
{...props}
>
{children}
<ChevronDownIcon className="text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200" />
</AccordionPrimitive.Trigger>
</AccordionPrimitive.Header>
)
}
function AccordionContent({
className,
children,
...props
}: React.ComponentProps<typeof AccordionPrimitive.Content>) {
return (
<AccordionPrimitive.Content
data-slot="accordion-content"
className="data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm"
{...props}
>
<div className={cn("pt-0 pb-4", className)}>{children}</div>
</AccordionPrimitive.Content>
)
}
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }

View File

@@ -0,0 +1,45 @@
"use client";
import { GripVertical } from "lucide-react";
import * as ResizablePrimitive from "react-resizable-panels";
import { cn } from "@/lib/utils";
const ResizablePanelGroup = ({
className,
...props
}: React.ComponentProps<typeof ResizablePrimitive.PanelGroup>) => (
<ResizablePrimitive.PanelGroup
className={cn(
"flex h-full w-full data-[panel-group-direction=vertical]:flex-col",
className
)}
{...props}
/>
);
const ResizablePanel = ResizablePrimitive.Panel;
const ResizableHandle = ({
withHandle,
className,
...props
}: React.ComponentProps<typeof ResizablePrimitive.PanelResizeHandle> & {
withHandle?: boolean;
}) => (
<ResizablePrimitive.PanelResizeHandle
className={cn(
"relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90",
className
)}
{...props}
>
{withHandle && (
<div className="z-10 flex h-4 w-3 items-center justify-center rounded-sm border bg-border">
<GripVertical className="h-2.5 w-2.5" />
</div>
)}
</ResizablePrimitive.PanelResizeHandle>
);
export { ResizablePanelGroup, ResizablePanel, ResizableHandle };

View File

@@ -0,0 +1,56 @@
import * as React from "react"
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
import { cn } from "@/lib/utils"
function ScrollArea({
className,
children,
...props
}: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) {
return (
<ScrollAreaPrimitive.Root
data-slot="scroll-area"
className={cn("relative", className)}
{...props}
>
<ScrollAreaPrimitive.Viewport
data-slot="scroll-area-viewport"
className="ring-ring/10 dark:ring-ring/20 dark:outline-ring/40 outline-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] focus-visible:ring-4 focus-visible:outline-1"
>
{children}
</ScrollAreaPrimitive.Viewport>
<ScrollBar />
<ScrollAreaPrimitive.Corner />
</ScrollAreaPrimitive.Root>
)
}
function ScrollBar({
className,
orientation = "vertical",
...props
}: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>) {
return (
<ScrollAreaPrimitive.ScrollAreaScrollbar
data-slot="scroll-area-scrollbar"
orientation={orientation}
className={cn(
"flex touch-none p-px transition-colors select-none",
orientation === "vertical" &&
"h-full w-2.5 border-l border-l-transparent",
orientation === "horizontal" &&
"h-2.5 flex-col border-t border-t-transparent",
className
)}
{...props}
>
<ScrollAreaPrimitive.ScrollAreaThumb
data-slot="scroll-area-thumb"
className="bg-border relative flex-1 rounded-full"
/>
</ScrollAreaPrimitive.ScrollAreaScrollbar>
)
}
export { ScrollArea, ScrollBar }

View File

@@ -20,6 +20,7 @@ import { Route as IndexImport } from './routes/index'
import { Route as OcpIndexImport } from './routes/ocp/index'
import { Route as EomEomImport } from './routes/_eom/eom'
import { Route as AuthProfileImport } from './routes/_auth/profile'
import { Route as AdminUsersImport } from './routes/_admin/users'
import { Route as AdminSettingsImport } from './routes/_admin/settings'
import { Route as AdminServersImport } from './routes/_admin/servers'
import { Route as AdminModulesImport } from './routes/_admin/modules'
@@ -82,6 +83,12 @@ const AuthProfileRoute = AuthProfileImport.update({
getParentRoute: () => AuthRoute,
} as any)
const AdminUsersRoute = AdminUsersImport.update({
id: '/users',
path: '/users',
getParentRoute: () => AdminRoute,
} as any)
const AdminSettingsRoute = AdminSettingsImport.update({
id: '/settings',
path: '/settings',
@@ -200,6 +207,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof AdminSettingsImport
parentRoute: typeof AdminImport
}
'/_admin/users': {
id: '/_admin/users'
path: '/users'
fullPath: '/users'
preLoaderRoute: typeof AdminUsersImport
parentRoute: typeof AdminImport
}
'/_auth/profile': {
id: '/_auth/profile'
path: '/profile'
@@ -265,12 +279,14 @@ interface AdminRouteChildren {
AdminModulesRoute: typeof AdminModulesRoute
AdminServersRoute: typeof AdminServersRoute
AdminSettingsRoute: typeof AdminSettingsRoute
AdminUsersRoute: typeof AdminUsersRoute
}
const AdminRouteChildren: AdminRouteChildren = {
AdminModulesRoute: AdminModulesRoute,
AdminServersRoute: AdminServersRoute,
AdminSettingsRoute: AdminSettingsRoute,
AdminUsersRoute: AdminUsersRoute,
}
const AdminRouteWithChildren = AdminRoute._addFileChildren(AdminRouteChildren)
@@ -305,6 +321,7 @@ export interface FileRoutesByFullPath {
'/modules': typeof AdminModulesRoute
'/servers': typeof AdminServersRoute
'/settings': typeof AdminSettingsRoute
'/users': typeof AdminUsersRoute
'/profile': typeof AuthProfileRoute
'/eom': typeof EomEomRoute
'/ocp': typeof OcpIndexRoute
@@ -323,6 +340,7 @@ export interface FileRoutesByTo {
'/modules': typeof AdminModulesRoute
'/servers': typeof AdminServersRoute
'/settings': typeof AdminSettingsRoute
'/users': typeof AdminUsersRoute
'/profile': typeof AuthProfileRoute
'/eom': typeof EomEomRoute
'/ocp': typeof OcpIndexRoute
@@ -344,6 +362,7 @@ export interface FileRoutesById {
'/_admin/modules': typeof AdminModulesRoute
'/_admin/servers': typeof AdminServersRoute
'/_admin/settings': typeof AdminSettingsRoute
'/_admin/users': typeof AdminUsersRoute
'/_auth/profile': typeof AuthProfileRoute
'/_eom/eom': typeof EomEomRoute
'/ocp/': typeof OcpIndexRoute
@@ -364,6 +383,7 @@ export interface FileRouteTypes {
| '/modules'
| '/servers'
| '/settings'
| '/users'
| '/profile'
| '/eom'
| '/ocp'
@@ -381,6 +401,7 @@ export interface FileRouteTypes {
| '/modules'
| '/servers'
| '/settings'
| '/users'
| '/profile'
| '/eom'
| '/ocp'
@@ -400,6 +421,7 @@ export interface FileRouteTypes {
| '/_admin/modules'
| '/_admin/servers'
| '/_admin/settings'
| '/_admin/users'
| '/_auth/profile'
| '/_eom/eom'
| '/ocp/'
@@ -472,7 +494,8 @@ export const routeTree = rootRoute
"children": [
"/_admin/modules",
"/_admin/servers",
"/_admin/settings"
"/_admin/settings",
"/_admin/users"
]
},
"/_auth": {
@@ -506,6 +529,10 @@ export const routeTree = rootRoute
"filePath": "_admin/settings.tsx",
"parent": "/_admin"
},
"/_admin/users": {
"filePath": "_admin/users.tsx",
"parent": "/_admin"
},
"/_auth/profile": {
"filePath": "_auth/profile.tsx",
"parent": "/_auth"

View File

@@ -0,0 +1,10 @@
import UserPage from "@/components/admin/user/UserPage";
import { createFileRoute } from "@tanstack/react-router";
export const Route = createFileRoute("/_admin/users")({
component: RouteComponent,
});
function RouteComponent() {
return <UserPage />;
}

View File

@@ -0,0 +1,5 @@
import { Button } from "@/components/ui/button";
export const DebugButton = (data: any) => {
return <Button onClick={() => console.log(data.data)}>Debug</Button>;
};

View File

@@ -0,0 +1,14 @@
import { formOptions } from "@tanstack/react-form";
export const userFormOptions = (user: any) => {
return formOptions({
defaultValues: {
username: user.username,
password: "",
email: user.email,
role: user.role,
//hobbies: [],
},
// } as Person,
});
};

View File

@@ -0,0 +1,27 @@
export const generatePassword = (length: number) => {
const uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const lowercase = "abcdefghijklmnopqrstuvwxyz";
const numbers = "0123456789";
const symbols = "!@#$%&()_+-={}:,.<>?/"; // Safe symbol list
// Ensure the password contains at least one of each required type
let password: any = [
uppercase[Math.floor(Math.random() * uppercase.length)],
lowercase[Math.floor(Math.random() * lowercase.length)],
numbers[Math.floor(Math.random() * numbers.length)],
symbols[Math.floor(Math.random() * symbols.length)],
];
// Fill the rest of the password with random characters from all sets
const allCharacters = uppercase + lowercase;
for (let i = password.length; i < length; i++) {
password.push(
allCharacters[Math.floor(Math.random() * allCharacters.length)]
);
}
// Shuffle the password to avoid predictable patterns
password = password.sort(() => Math.random() - 0.5).join("");
return password;
};

View File

@@ -0,0 +1,26 @@
import { queryOptions } from "@tanstack/react-query";
import axios from "axios";
export function getUsers() {
const token = localStorage.getItem("auth_token");
return queryOptions({
queryKey: ["getUsers"],
queryFn: () => fetchUsers(token),
enabled: !!token, // Prevents query if token is null
staleTime: 1000,
//refetchInterval: 2 * 2000,
refetchOnWindowFocus: true,
});
}
const fetchUsers = async (token: string | null) => {
const { data } = await axios.get(`/api/auth/allusers`, {
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
});
// if we are not localhost ignore the devDir setting.
//const url: string = window.location.host.split(":")[0];
return data.data ?? [];
};

View File

@@ -1,4 +1,4 @@
import {queryOptions} from "@tanstack/react-query";
import { queryOptions } from "@tanstack/react-query";
import axios from "axios";
export function getlabels(hours: string) {
@@ -7,13 +7,13 @@ export function getlabels(hours: string) {
queryFn: () => fetchSettings(hours),
staleTime: 1000,
//refetchInterval: 2500,
refetchInterval: 2 * 2000,
refetchOnWindowFocus: true,
});
}
const fetchSettings = async (hours: string) => {
const {data} = await axios.get(`/api/v1/ocp/labels?hours=${hours}`);
const { data } = await axios.get(`/api/ocp/getlabels?hours=${hours}`);
// if we are not localhost ignore the devDir setting.
//const url: string = window.location.host.split(":")[0];
return data.data ?? [];

View File

@@ -1,4 +1,4 @@
import {queryOptions} from "@tanstack/react-query";
import { queryOptions } from "@tanstack/react-query";
import axios from "axios";
export function getlots() {
@@ -7,13 +7,13 @@ export function getlots() {
queryFn: () => fetchSettings(),
staleTime: 10 * 1000,
//refetchInterval: 10 * 1000,
refetchInterval: 10 * 1000,
refetchOnWindowFocus: true,
});
}
const fetchSettings = async () => {
const {data} = await axios.get("/api/v1/ocp/lots");
const { data } = await axios.get("/api/ocp/getlots");
// if we are not localhost ignore the devDir setting.
//const url: string = window.location.host.split(":")[0];
let lotData = data.data;

View File

@@ -0,0 +1,22 @@
import { queryOptions } from "@tanstack/react-query";
import axios from "axios";
export function getOcpLogs(hours: string) {
return queryOptions({
queryKey: ["ocpLogs"],
queryFn: () => fetchSettings(hours),
staleTime: 1000,
refetchInterval: 2 * 1000,
refetchOnWindowFocus: true,
});
}
const fetchSettings = async (hours: string) => {
const { data } = await axios.get(
`/api/logger/logs?service=ocp&service=rfid&level=error&level=warn&hours=${hours}`
);
// if we are not localhost ignore the devDir setting.
//const url: string = window.location.host.split(":")[0];
return data.data ?? [];
};

847
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "lstv2",
"version": "2.9.0",
"version": "2.10.0",
"type": "module",
"scripts": {
"dev": "concurrently -n \"server,frontend\" -c \"#007755,#2f6da3\" \"npm run dev:server\" \"cd frontend && npm run dev\"",
@@ -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,9 @@
"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\" && npm run zipServer",
"scriptBuild": "powershell -ExecutionPolicy Bypass -File server/scripts/build.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",
"prodinstall": "npm i --omit=dev && npm run db:migrate",
"checkupdates": "npx npm-check-updates"
@@ -32,7 +34,7 @@
}
},
"admConfig": {
"build": 50,
"build": 125,
"oldBuild": "backend-0.1.3.zip"
},
"devDependencies": {
@@ -42,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"
@@ -57,14 +58,18 @@
"@hono/node-server": "^1.14.0",
"@hono/zod-openapi": "^0.19.2",
"@scalar/hono-api-reference": "^0.7.2",
"@tanstack/react-form": "^1.2.1",
"@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 +80,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

@@ -1,12 +1,12 @@
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
import { serve } from "@hono/node-server";
import { OpenAPIHono } from "@hono/zod-openapi";
import { proxy } from "hono/proxy";
import { serveStatic } from "@hono/node-server/serve-static";
import { logger } from "hono/logger";
import { cors } from "hono/cors";
import { createLog } from "./services/logger/logger.js";
import { WebSocketServer } from "ws";
// custom routes
import scalar from "./services/general/route/scalar.js";
import system from "./services/server/systemServer.js";
@@ -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,66 +32,78 @@ 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"
? false
: true;
serverIntialized.length === 0 && process.env.NODE_ENV !== "development"
? false
: true;
createLog("info", "LST", "server", `Server is installed: ${installed}`);
const app = new OpenAPIHono({ strict: false });
// middle ware
app.use("*", logger());
if (process.env.NODE_ENV === "development") {
app.use("*", logger());
}
app.use(
"*",
cors({
origin: "*", // Allow all origins
allowHeaders: ["Content-Type", "Authorization", "X-Requested-With"],
allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"],
//exposeHeaders: ["Content-Length", "X-Kuma-Revision"],
credentials: true, // Allow credentials if needed
maxAge: 600,
})
"*",
cors({
origin: "*", // Allow all origins
allowHeaders: ["Content-Type", "Authorization", "X-Requested-With"],
allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"],
//exposeHeaders: ["Content-Length", "X-Kuma-Revision"],
credentials: true, // Allow credentials if needed
maxAge: 600,
})
);
// Middleware to normalize route case
app.use("*", async (c, next) => {
const lowercasedUrl = c.req.url.toLowerCase();
//console.log("Incoming Request:", c.req.url, c.req.method);
// If the URL is already lowercase, continue as usual
if (c.req.url === lowercasedUrl) {
return next();
}
// app.use("*", async (c, next) => {
// // const lowercasedUrl = c.req.url.toLowerCase();
// console.log("Incoming Request:", c.req.url, c.req.method);
// // // If the URL is already lowercase, continue as usual
// // if (c.req.url === lowercasedUrl) {
// await next();
// // }
// Otherwise, re-route internally
return c.redirect(lowercasedUrl, 308); // 308 preserves the HTTP method
});
// // // Otherwise, re-route internally
// // return c.redirect(lowercasedUrl, 308); // 308 preserves the HTTP method
// });
app.doc("/api/ref", {
openapi: "3.0.0",
info: {
version: "2.0.0",
title: "LST API",
},
openapi: "3.0.0",
info: {
version: "2.0.0",
title: "LST API",
},
});
const routes = [
scalar,
auth,
// apiHits,
system,
tcpServer,
sqlService,
logistics,
rfid,
printers,
loggerService,
ocpService,
scalar,
auth,
// apiHits,
system,
tcpServer,
sqlService,
logistics,
rfid,
printers,
loggerService,
ocpService,
notify,
] as const;
const appRoutes = routes.forEach((route) => {
app.route("/api/", route);
app.route("/api/", route);
});
app.route("/ocme/", ocme);
@@ -129,48 +144,59 @@ app.use("*", serveStatic({ path: "./frontend/dist/index.html" }));
// Handle app exit signals
process.on("SIGINT", async () => {
console.log("\nGracefully shutting down...");
//await closePool();
process.exit(0);
console.log("\nGracefully shutting down...");
//await closePool();
process.exit(0);
});
process.on("SIGTERM", async () => {
console.log("Received termination signal, closing database...");
//await closePool();
process.exit(0);
console.log("Received termination signal, closing database...");
//await closePool();
process.exit(0);
});
process.on("uncaughtException", async (err) => {
console.log("Uncaught Exception:", err);
//await closePool();
process.exit(1);
console.log("Uncaught Exception:", err);
//await closePool();
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 () => {
console.log("Process is about to exit...");
//await closePool();
process.exit(0);
console.log("Process is about to exit...");
//await closePool();
process.exit(0);
});
const port =
process.env.NODE_ENV === "development"
? process.env.VITE_SERVER_PORT
: process.env.PROD_PORT;
process.env.NODE_ENV === "development"
? process.env.VITE_SERVER_PORT
: process.env.PROD_PORT;
serve(
{
fetch: app.fetch,
port: Number(port),
hostname: "0.0.0.0",
},
(info) => {
createLog(
"info",
"LST",
"server",
`Server is running on http://${info.address}:${info.port}`
);
}
{
fetch: app.fetch,
port: Number(port),
hostname: "0.0.0.0",
},
(info) => {
createLog(
"info",
"LST",
"server",
`Server is running on http://${info.address}:${info.port}`
);
}
);
export type AppRoutes = typeof appRoutes;

View File

@@ -85,8 +85,23 @@ $plantFunness = {
$localPath = $location -replace '\$', ':'
$serverFile = "$($localPath)\$buildFile"
$serverPath = "$($localPath)"
$appPath = $extractedFolderPath
$nssmPath = $serverPath + "\nssm.exe"
$npmPath = "C:\Program Files\nodejs\npm.cmd" # Path to npm.cmd
Write-Host "In the plant we go!!!!!"
######################################################################################
# Removing the fist and frontend folder to make sure we keep them the same and clean.
######################################################################################
# Delete the directories after extraction
Write-Host "Deleting Dist and Frontend..."
Set-Location $serverPath
npm run removeOld # --omit=dev
Write-Host "Unzipping the folder..."
$extractedFolderPath = $serverPath
@@ -162,10 +177,6 @@ $plantFunness = {
# Service removoal and making sure we have the new version added
#################################################################
$appPath = $extractedFolderPath
$nssmPath = $serverPath + "\nssm.exe"
$npmPath = "C:\Program Files\nodejs\npm.cmd" # Path to npm.cmd
#################################################################
# Removing all the old services
#################################################################
@@ -415,10 +426,10 @@ try {
Start-Service -DisplayName $serviceLstV2
Start-Sleep -Seconds 1
Write-Host "$($server) finished updating"
if($token -eq "usday1"){
Write-Host "Starting $($serviceOcme)"
Start-Service -DisplayName $serviceOcme
}
# if($token -eq "usday1"){
# Write-Host "Starting $($serviceOcme)"
# Start-Service -DisplayName $serviceOcme
# }
}
Invoke-Command -ComputerName $server -ScriptBlock $plantFunness -ArgumentList $server, $token, $location, $buildZip, $buildLoc, $obslst, $obsBuild -Credential $credentials

View File

@@ -0,0 +1,22 @@
# Define the array of folders
$folders = @(
"AlplaBasis",
"AlplaBudget",
"AlplaINVOICE",
"AlplaLabel",
"AlplaOrder",
"AlplaPlanning",
"AlplaPurchase",
"AlplaStock",
"PDF24",
"Module shortcuts"
)
# Set permissions using icacls
$permissions = "Everyone:(OI)(CI)F"
# Loop through each folder and set permissions
foreach ($folder in $folders) {
$folderPath = "C:\Sources\AlplaPROD\$folder"
icacls $folderPath /grant $permissions /t /c /q
}

View File

@@ -1,21 +1,24 @@
import {spawn} from "child_process";
import {getAppInfo} from "../globalUtils/appInfo.js";
import {db} from "../../database/dbclient.js";
import {serverData} from "../../database/schema/serverData.js";
import {eq, sql} from "drizzle-orm";
import {createLog} from "../services/logger/logger.js";
import { spawn } from "child_process";
import { getAppInfo } from "../globalUtils/appInfo.js";
import { db } from "../../database/dbclient.js";
import { serverData } from "../../database/schema/serverData.js";
import { eq, sql } from "drizzle-orm";
import { createLog } from "../services/logger/logger.js";
type UpdateServerResponse = {
success: boolean;
message: string;
};
export const updateServer = async (devApp: string, server: string | null): Promise<UpdateServerResponse> => {
export const updateServer = async (
devApp: string,
server: string | null
): Promise<UpdateServerResponse> => {
const app = await getAppInfo(devApp);
const serverInfo = await db
.select()
.from(serverData)
.where(eq(serverData.plantToken, server?.toLowerCase() ?? ""));
.select()
.from(serverData)
.where(eq(serverData.plantToken, server?.toLowerCase() ?? ""));
if (serverInfo.length === 0) {
createLog(
@@ -26,7 +29,8 @@ export const updateServer = async (devApp: string, server: string | null): Promi
);
return {
success: false,
message: "Looks like you are missing the plant token or have entered an incorrect one please try again.",
message:
"Looks like you are missing the plant token or have entered an incorrect one please try again.",
};
}
@@ -77,9 +81,9 @@ export const updateServer = async (devApp: string, server: string | null): Promi
const process = spawn("powershell", args);
// change the server to upgradeing
await db
.update(serverData)
.set({isUpgrading: true})
.where(eq(serverData.plantToken, server?.toLowerCase() ?? ""));
.update(serverData)
.set({ isUpgrading: true })
.where(eq(serverData.plantToken, server?.toLowerCase() ?? ""));
//let stdout = "";
//let stderr = "";
@@ -108,9 +112,14 @@ export const updateServer = async (devApp: string, server: string | null): Promi
//update the last build.
try {
await db
.update(serverData)
.set({lastUpdated: sql`NOW()`, isUpgrading: false})
.where(eq(serverData.plantToken, server?.toLowerCase() ?? ""));
.update(serverData)
.set({ lastUpdated: sql`NOW()`, isUpgrading: false })
.where(
eq(
serverData.plantToken,
server?.toLowerCase() ?? ""
)
);
createLog(
"info",
"lst",
@@ -156,17 +165,35 @@ export const updateServer = async (devApp: string, server: string | null): Promi
export async function processAllServers(devApp: string) {
const servers = await db.select().from(serverData);
createLog("info", "lst", "serverUpdater", `Running the update on all servers`);
createLog(
"info",
"lst",
"serverUpdater",
`Running the update on all servers`
);
let count = 1;
for (const server of servers) {
try {
const updateToServer = await updateServer(devApp, server.plantToken);
createLog("info", "lst", "serverUpdater", `${server.sName} was updated.`);
const updateToServer = await updateServer(
devApp,
server.plantToken
);
createLog(
"info",
"lst",
"serverUpdater",
`${server.sName} was updated.`
);
count = count + 1;
//return {success: true, message: `${server.sName} was updated.`, data: updateToServer};
} catch (error: any) {
createLog("info", "lst", "serverUpdater", `Error updating ${server.sName}: ${error.message}`);
createLog(
"info",
"lst",
"serverUpdater",
`Error updating ${server.sName}: ${error.message}`
);
//return {success: false, message: `Error updating ${server.sName}: ${error.message}`};
}
}

View File

@@ -99,7 +99,7 @@ const updateBuildNumber = (appLock: string) => {
// Auto-commit changes
execSync("git add package.json");
execSync(
`git commit -m "build: bump build number to ${pkgJson.admConfig.build}"`
`git commit -m "chore(release): bump build number to ${pkgJson.admConfig.build}"`
);
} else {
createLog(

View File

@@ -5,64 +5,80 @@ import { tryCatch } from "../../../../globalUtils/tryCatch.js";
import type { User } from "../../../../types/users.js";
import { createPassword } from "../../utils/createPassword.js";
import { createLog } from "../../../logger/logger.js";
import { sendEmail } from "../../../notifications/controller/sendMail.js";
export const updateUserADM = async (userData: User) => {
/**
* The user model will need to be passed over so we can update per the request on the user.
* password, username, email.
*/
/**
* The user model will need to be passed over so we can update per the request on the user.
* password, username, email.
*/
createLog(
"info",
"apiAuthedRoute",
"auth",
`${userData.user_id} is being updated.`
);
// get the orignal user info
const { data: user, error: userError } = await tryCatch(
db.select().from(users).where(eq(users.user_id, userData.user_id!))
);
console.log(userData);
createLog(
"info",
"apiAuthedRoute",
"auth",
`${userData.user_id} is being updated.`
);
// get the orignal user info
const { data: user, error: userError } = await tryCatch(
db.select().from(users).where(eq(users.user_id, userData.user_id!))
);
if (userError) {
return {
success: false,
message: "There was an error getting the user",
userError,
if (userError) {
return {
success: false,
message: "There was an error getting the user",
userError,
};
}
if (user?.length === 0) {
return {
success: false,
message:
"The user you are looking for has either been deleted or dose not exist.",
};
}
const upd_user = user as User;
const password: string = userData.password
? await createPassword(userData.password!)
: upd_user.password!;
const data = {
username: userData.username ? userData.username : upd_user?.username,
password: password,
email: userData.email ? userData.email : upd_user.email,
role: userData.role ? userData.role : upd_user.role,
};
}
if (user?.length === 0) {
// term ? ilike(posts.title, term) : undefined
const { data: updData, error: updError } = await tryCatch(
db.update(users).set(data).where(eq(users.user_id, userData.user_id!))
);
if (updError) {
return {
success: false,
message: "There was an error getting the user",
updError,
};
}
if (userData?.password!.length > 0) {
// send this user an email so they have the randomized password.
await sendEmail({
email: user[0]?.email,
subject: "LST - Password reset.",
template: "passwordReset",
context: {
password: userData.password!,
username: user[0].username!,
},
});
}
return {
success: false,
message:
"The user you are looking for has either been deleted or dose not exist.",
success: true,
message: `${userData.username} has been updated.`,
updData,
};
}
const upd_user = user as User;
const password: string = userData.password
? await createPassword(userData.password!)
: upd_user.password!;
const data = {
username: userData.username ? userData.username : upd_user?.username,
password: password,
email: userData.email ? userData.email : upd_user.email,
};
// term ? ilike(posts.title, term) : undefined
const { data: updData, error: updError } = await tryCatch(
db.update(users).set(data).where(eq(users.user_id, userData.user_id!))
);
if (updError) {
return {
success: false,
message: "There was an error getting the user",
updError,
};
}
return {
success: true,
message: `${userData.username} has been updated.`,
updData,
};
};

View File

@@ -10,82 +10,76 @@ import { updateUserADM } from "../../controllers/userAdmin/updateUserAdm.js";
const app = new OpenAPIHono();
const responseSchema = z.object({
success: z.boolean().openapi({ example: true }),
message: z.string().optional().openapi({ example: "user access" }),
data: z.array(z.object({})).optional().openapi({ example: [] }),
success: z.boolean().openapi({ example: true }),
message: z.string().optional().openapi({ example: "user access" }),
data: z.array(z.object({})).optional().openapi({ example: [] }),
});
const UserAccess = z.object({
user_id: z.string().openapi({ example: "users UUID" }),
username: z
.string()
.regex(/^[a-zA-Z0-9_]{3,30}$/)
.optional()
.openapi({ example: "smith034" }),
email: z
.string()
.email()
.optional()
.openapi({ example: "smith@example.com" }),
password: z
.string()
.min(6, { message: "Passwords must be longer than 3 characters" })
.regex(/[A-Z]/, {
message: "Password must contain at least one uppercase letter",
})
.regex(/[\W_]/, {
message: "Password must contain at least one special character",
})
.optional()
.openapi({ example: "Password1!" }),
user_id: z.string().openapi({ example: "users UUID" }),
username: z
.string()
.regex(/^[a-zA-Z0-9_]{3,30}$/)
.optional()
.openapi({ example: "smith034" }),
email: z
.string()
.email()
.optional()
.openapi({ example: "smith@example.com" }),
password: z
.string()
.optional()
.openapi({ example: "Password1!" }),
});
app.openapi(
createRoute({
tags: ["Auth:admin"],
summary: "updates a specific user",
method: "post",
path: "/updateuser",
middleware: [
authMiddleware,
hasCorrectRole(["admin", "systemAdmin"], "admin"),
],
//description: "When logged in you will be able to grant new permissions",
request: {
body: {
content: {
"application/json": { schema: UserAccess },
createRoute({
tags: ["Auth:admin"],
summary: "updates a specific user",
method: "patch",
path: "/updateuser",
middleware: [
authMiddleware,
hasCorrectRole(["admin", "systemAdmin"], "admin"),
],
//description: "When logged in you will be able to grant new permissions",
request: {
body: {
content: {
"application/json": { schema: UserAccess },
},
},
},
},
},
responses: responses(),
}),
async (c) => {
//apiHit(c, { endpoint: "api/auth/setUserRoles" });
const userData = await c.req.json();
try {
const userUPD: any = await updateUserADM(userData);
//return apiReturn(c, true, access?.message, access?.data, 200);
return c.json(
{
success: userUPD.success,
message: userUPD.message,
data: userUPD.data,
},
200
);
} catch (error) {
console.log(error);
//return apiReturn(c, false, "Error in setting the user access", error, 400);
return c.json(
{
success: false,
message: "Error in setting the user access",
data: error,
},
400
);
responses: responses(),
}),
async (c) => {
//apiHit(c, { endpoint: "api/auth/setUserRoles" });
const userData = await c.req.json();
try {
const userUPD: any = await updateUserADM(userData);
//return apiReturn(c, true, access?.message, access?.data, 200);
return c.json(
{
success: userUPD.success,
message: userUPD.message,
data: userUPD.data,
},
200
);
} catch (error) {
console.log(error);
//return apiReturn(c, false, "Error in setting the user access", error, 400);
return c.json(
{
success: false,
message: "Error in setting the user access",
data: error,
},
400
);
}
}
}
);
export default app;

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

@@ -1,28 +1,41 @@
import {and, eq, inArray, lte, sql} from "drizzle-orm";
import {db} from "../../../../database/dbclient.js";
import {logs} from "../../../../database/schema/logs.js";
import {createLog} from "../logger.js";
import { and, eq, gte, inArray, lte, sql } from "drizzle-orm";
import { db } from "../../../../database/dbclient.js";
import { logs } from "../../../../database/schema/logs.js";
import { createLog } from "../logger.js";
export const getLogs = async (data: any) => {
try {
// clear all remaining logs ne to info.
const checked = data.checked && data.checked[0] === "true" ? true : false || false;
const checked =
data.checked && data.checked[0] === "true" ? true : false || false;
const logData = await db
.select()
.from(logs)
.where(
and(
lte(logs.created_at, sql.raw(`NOW() - INTERVAL '${data.hours} hours'`)),
inArray(logs.service, data.service),
inArray(logs.level, data.level),
eq(logs.checked, checked)
)
);
.select()
.from(logs)
.where(
and(
gte(
logs.created_at,
sql.raw(`NOW() - INTERVAL '${data.hours ?? "4"} hours'`)
),
inArray(logs.service, data.service),
inArray(logs.level, data.level),
eq(logs.checked, checked)
)
);
return {success: true, message: "logs returned", data: logData};
return { success: true, message: "logs returned", data: logData };
} catch (error) {
console.log(error);
createLog("error", "lst", "logger", `There was an error deleteing server logs. ${error}`);
return {success: false, message: "An error occured while trying to get the logs", error};
createLog(
"error",
"lst",
"logger",
`There was an error deleteing server logs. ${error}`
);
return {
success: false,
message: "An error occured while trying to get the logs",
error,
};
}
};

View File

@@ -1,6 +1,6 @@
import {pino, type LogFn, type Logger} from "pino";
import { pino, type LogFn, type Logger } from "pino";
export let logLevel = "info";
export let logLevel = process.env.LOGLEVEL || "info";
const transport = pino.transport({
targets: [
@@ -31,7 +31,7 @@ const log: Logger = pino(
// },
//customLevels: {death: 70},
// removes data from the logs that we dont want to be shown :D
redact: {paths: ["email", "password"], remove: true},
redact: { paths: ["email", "password"], remove: true },
},
transport
);
@@ -43,8 +43,11 @@ export const createLog = (
message: string
) => {
if (level in log) {
log[level]({username, service}, message);
log[level]({ username, service }, message);
} else {
log.warn({username, service}, `Invalid log level '${level}', falling back to warn: ${message}`);
log.warn(
{ username, service },
`Invalid log level '${level}', falling back to warn: ${message}`
);
}
};

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 { 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,36 @@
<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>
<p>
Dear {{username}},<br/><br/>
Your password was change. Please find your new temporary password below:<br/><br/>
Temporary Password: <em><b>{{password}}</b></em><br/><br/>
For security reasons, we strongly recommend changing your password as soon as possible.<br/><br/>
You can update it by logging into your account and navigating to the password settings section.<br/><br/>
Best regards,<br/><br/>
LST team<br/>
</p>
</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

@@ -3,9 +3,14 @@ import axios from "axios";
export const ocmeInv = async (data: any) => {
try {
const res = await axios.post(
"http://usday1vms010:3250/api/v1/getLaneData",
{lane: data.lane, laneType: data.laneType},
{headers: {"Content-Type": "application/json", Connection: "keep-alive"}}
"http://usday1vms010:3250/api/v1/getlanedata",
{ lane: data.lane, laneType: data.laneType },
{
headers: {
"Content-Type": "application/json",
Connection: "keep-alive",
},
}
);
// console.log(res.data.data);

View File

@@ -1,23 +1,37 @@
import {db} from "../../../../database/dbclient.js";
import {ocmeData} from "../../../../database/schema/ocme.js";
import {differenceInMinutes} from "date-fns";
import {createLog} from "../../logger/logger.js";
import {eq} from "drizzle-orm";
import { db } from "../../../../database/dbclient.js";
import { ocmeData } from "../../../../database/schema/ocme.js";
import { differenceInMinutes } from "date-fns";
import { createLog } from "../../logger/logger.js";
import { eq } from "drizzle-orm";
export const getInfo = async () => {
let ocmeInfo: any = [];
try {
ocmeInfo = await db.select().from(ocmeData).where(eq(ocmeData.pickedUp, false));
ocmeInfo = await db
.select()
.from(ocmeData)
.where(eq(ocmeData.pickedUp, false));
// add in the time difference
ocmeInfo = ocmeInfo.map((o: any) => {
const now = new Date(Date.now());
const diff = differenceInMinutes(now, o.add_Date!);
return {...o, waitingFor: diff};
//const strippedDate = o.add_Date.replace("Z", "");
const diff = differenceInMinutes(now, o.add_Date);
return { ...o, waitingFor: diff };
});
createLog("info", "ocme", "ocme", `There are ${ocmeInfo.length} pallet(s) to be picked up.`);
createLog(
"debug",
"ocme",
"ocme",
`There are ${ocmeInfo.length} pallet(s) to be picked up.`
);
} catch (error) {
createLog("error", "ocme", "ocme", "There was an error trying to retrive the ocmeInfo.");
createLog(
"error",
"ocme",
"ocme",
"There was an error trying to retrive the ocmeInfo."
);
throw Error("There was an error trying to retrive the.");
}

View File

@@ -1,43 +1,84 @@
import {db} from "../../../../database/dbclient.js";
import {ocmeData} from "../../../../database/schema/ocme.js";
import {createSSCC} from "../../../globalUtils/createSSCC.js";
import {createLog} from "../../logger/logger.js";
import {query} from "../../sqlServer/prodSqlServer.js";
import {labelData} from "../../sqlServer/querys/materialHelpers/labelInfo.js";
import { db } from "../../../../database/dbclient.js";
import { ocmeData } from "../../../../database/schema/ocme.js";
import { createSSCC } from "../../../globalUtils/createSSCC.js";
import { createLog } from "../../logger/logger.js";
import { query } from "../../sqlServer/prodSqlServer.js";
import { labelData } from "../../sqlServer/querys/materialHelpers/labelInfo.js";
export const postLabelData = async (data: any) => {
// if we have sscc we will do everything here and ignore the rn even it its sent over
if (data.sscc && !data.runningNr) {
data.runningNr = data.sscc.slice(10, -1);
console.log(data);
let newData = data;
if (Array.isArray(data)) {
newData = {
sscc: data[1],
areaFrom: data[0],
completed: true,
};
}
if (!data.sscc && !data.runningNr) {
// data.runningNr = data.sscc.slice(10, -1);
return {success: false, message: "Missing data please try again", data: []};
if (newData.sscc && !newData.runningNr) {
newData.runningNr = newData.sscc.slice(10, -1);
}
if (!newData.sscc && !newData.runningNr) {
return {
success: false,
message: "Missing data please try again",
data: [],
};
}
let label;
const filterQuery = labelData.replaceAll("[rn]", data.runningNr);
const filterQuery = labelData.replaceAll("[rn]", newData.runningNr);
try {
label = await query(filterQuery, "Label data");
} catch (error) {
createLog("error", "ocme", "ocme", "There was an error getting the labelData");
createLog(
"error",
"ocme",
"ocme",
"There was an error getting the labelData"
);
}
if (label.length === 0) {
return {
success: false,
message: "The label you scanned dose not exist in stock.",
};
}
const newPost = {
sscc: data.sscc ? data.sscc : await createSSCC(data.runningNr),
runningNr: data.runningNr,
completed: data.completed,
lineNum: label[0].machineLocation,
areaFrom: data.areaFrom,
sscc: newData.sscc ? newData.sscc : await createSSCC(newData.runningNr),
runningNr: newData.runningNr,
completed: newData.completed ? newData.completed : true,
lineNum: label[0]?.machineLocation,
areaFrom: newData.areaFrom,
pickedUp: false,
};
try {
const enterNewData = await db.insert(ocmeData).values(newPost).returning({sscc: ocmeData.sscc});
return {success: true, message: "Data was posted to ocme info", data: enterNewData};
const enterNewData = await db
.insert(ocmeData)
.values(newPost)
.onConflictDoUpdate({ target: ocmeData.runningNr, set: newPost })
.returning({
sscc: ocmeData.sscc,
runningNr: ocmeData.runningNr,
areaFrom: ocmeData.areaFrom,
lineNum: ocmeData.lineNum,
completed: ocmeData.completed,
pickedUp: ocmeData.pickedUp,
});
//console.log(enterNewData);
return {
success: true,
message: "Data was posted to ocme info",
data: enterNewData,
};
} catch (error) {
console.log(error);
return {success: false, message: "Data was posted to ocme info", data: newPost};
//console.log(error);
return {
success: false,
message: "Was not posted",
data: [error],
};
}
};

View File

@@ -0,0 +1,56 @@
import net from "net";
import { db } from "../../../../database/dbclient.js";
import { settings } from "../../../../database/schema/settings.js";
import { eq } from "drizzle-orm";
import { createLog } from "../../logger/logger.js";
export const triggerScanner = async () => {
const camera = new net.Socket();
let setting = await db
.select()
.from(settings)
.where(eq(settings.name, "zebraScanners"));
if (setting.length === 0) {
return {
success: false,
message: "Looks like the setting is missing.",
};
}
const scannerData = JSON.parse(setting[0]?.value);
let data = scannerData.filter((n: any) => n.name === "wrapper1");
if (data.length === 0) {
return {
success: false,
message: "Looks like the scanner is missing.",
};
}
let port = data[0]?.port;
createLog(
"info",
"wrapperScanner",
"ocme",
`End of line Camera was triggered`
);
return new Promise((resolve, reject) => {
camera.connect(port, data[0].ip, async () => {
createLog("info", "wrapperScanner", "ocme", `Triggered`);
camera.write("TRIGGER", "utf8");
camera.end();
resolve({ success: true, message: "Camera was triggered." });
});
camera.on("error", (error) => {
createLog("error", "wrapperScanner", "ocme", `${error}`);
resolve({
success: false,
message: `There was an error triggering the camera: ${JSON.stringify(
error
)}`,
});
});
resolve({ success: true, message: "Camera was triggered." });
});
};

View File

@@ -1,4 +1,4 @@
import {OpenAPIHono} from "@hono/zod-openapi";
import { OpenAPIHono } from "@hono/zod-openapi";
// routes
import getInfo from "./route/getInfo.js";
@@ -7,35 +7,52 @@ import pickedup from "./route/pickedUp.js";
import postsscc from "./route/postSSCC.js";
import getShipments from "./route/getShipmentPallets.js";
import cycleCount from "./route/cycleCount.js";
import {serve} from "@hono/node-server";
import {createLog} from "../logger/logger.js";
import {db} from "../../../database/dbclient.js";
import {settings} from "../../../database/schema/settings.js";
import { serve } from "@hono/node-server";
import { createLog } from "../logger/logger.js";
import { db } from "../../../database/dbclient.js";
import { settings } from "../../../database/schema/settings.js";
import manualTrigger from "./route/triggerCamera.js";
const app = new OpenAPIHono();
const port = process.env.OCME_PORT;
const routes = [getInfo, postRunningNr, postsscc, pickedup, getShipments, cycleCount] as const;
const routes = [
getInfo,
postRunningNr,
postsscc,
pickedup,
getShipments,
cycleCount,
manualTrigger,
] as const;
const setting = await db.select().from(settings);
const isActive = setting.filter((n) => n.name === "ocmeService");
const appRoutes = routes.forEach((route) => {
app.route("/api/v1", route);
app.route("/api/v1", route);
});
app.all("/api/v1/*", (c) => {
return c.json({success: false, message: "you have encounted an ocme route that dose not exist."});
return c.json({
success: false,
message: "you have encounted an ocme route that dose not exist.",
});
});
if (port && isActive[0]?.value === "1") {
serve(
{
fetch: app.fetch,
port: Number(port),
hostname: "0.0.0.0",
},
(info) => {
createLog("info", "LST", "server", `Ocme section is listening on http://${info.address}:${info.port}`);
}
);
serve(
{
fetch: app.fetch,
port: Number(port),
hostname: "0.0.0.0",
},
(info) => {
createLog(
"info",
"LST",
"server",
`Ocme section is listening on http://${info.address}:${info.port}`
);
}
);
}
export default app;

View File

@@ -1,60 +1,71 @@
import {createRoute, OpenAPIHono, z} from "@hono/zod-openapi";
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import {apiHit} from "../../../globalUtils/apiHits.js";
import {responses} from "../../../globalUtils/routeDefs/responses.js";
import {authMiddleware} from "../../auth/middleware/authMiddleware.js";
import {cycleCount} from "../controller/cycleCount.js";
import type {User} from "../../../types/users.js";
import {verify} from "hono/jwt";
import { apiHit } from "../../../globalUtils/apiHits.js";
import { responses } from "../../../globalUtils/routeDefs/responses.js";
import { authMiddleware } from "../../auth/middleware/authMiddleware.js";
import { cycleCount } from "../controller/cycleCount.js";
import type { User } from "../../../types/users.js";
import { verify } from "hono/jwt";
const app = new OpenAPIHono({strict: false});
const app = new OpenAPIHono({ strict: false });
const AddSetting = z.object({
lane: z.string().openapi({example: "L064"}),
lane: z.string().openapi({ example: "L064" }),
});
app.openapi(
createRoute({
tags: ["ocme"],
summary: "Cycle counts a lane based on the lane Alias",
method: "post",
path: "/cyclecount",
middleware: authMiddleware,
request: {
body: {
content: {
"application/json": {schema: AddSetting},
},
},
createRoute({
tags: ["ocme"],
summary: "Cycle counts a lane based on the lane Alias",
method: "post",
path: "/cycleCount",
middleware: authMiddleware,
request: {
body: {
content: {
"application/json": { schema: AddSetting },
},
responses: responses(),
}),
async (c) => {
apiHit(c, {endpoint: "api/auth/register"});
// make sure we have a vaid user being accessed thats really logged in
const body = await c.req.json();
},
},
responses: responses(),
}),
async (c) => {
apiHit(c, { endpoint: "api/auth/register" });
// make sure we have a vaid user being accessed thats really logged in
const body = await c.req.json();
const authHeader = c.req.header("Authorization");
const authHeader = c.req.header("Authorization");
const token = authHeader?.split("Bearer ")[1] || "";
let user: User;
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) {
return c.json({message: "Unauthorized"}, 401);
}
try {
const cycleData = await cycleCount(body, user);
return c.json({success: true, message: `${body.lane} was just cycle counted.`, data: cycleData}, 200);
} catch (error) {
return c.json(
{success: false, message: `There was an error cycle counting ${body.lane}`, data: error},
400
);
}
try {
const payload = await verify(token, process.env.JWT_SECRET!);
user = payload.user as User;
} catch (error) {
return c.json({ message: "Unauthorized" }, 401);
}
try {
const cycleData = await cycleCount(body, user);
return c.json(
{
success: true,
message: `${body.lane} was just cycle counted.`,
data: cycleData,
},
200
);
} catch (error) {
return c.json(
{
success: false,
message: `There was an error cycle counting ${body.lane}`,
data: error,
},
400
);
}
}
);
export default app;

View File

@@ -1,80 +1,36 @@
import {createRoute, OpenAPIHono, z} from "@hono/zod-openapi";
import {getInfo} from "../controller/getInfo.js";
import {apiHit} from "../../../globalUtils/apiHits.js";
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { getInfo } from "../controller/getInfo.js";
import { apiHit } from "../../../globalUtils/apiHits.js";
import { responses } from "../../../globalUtils/routeDefs/responses.js";
const app = new OpenAPIHono({strict: false});
const AddSetting = z.object({
name: z.string().openapi({example: "server"}),
value: z.string().openapi({example: "localhost"}),
description: z.string().openapi({example: "The server we are going to connect to"}),
roles: z.string().openapi({example: "admin"}),
module: z.string().openapi({example: "production"}),
});
const app = new OpenAPIHono({ strict: false });
app.openapi(
createRoute({
tags: ["ocme"],
summary: "Get all current info",
method: "get",
path: "/getinfo",
request: {
body: {
content: {
"application/json": {schema: AddSetting},
},
},
},
responses: {
200: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({example: true}),
message: z.string().openapi({example: "Starter"}),
data: z.array(z.object({})).optional().openapi({example: []}),
}),
},
},
description: "Response message",
},
400: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({example: false}),
message: z.string().optional().openapi({example: "Internal Server error"}),
data: z.array(z.object({})).optional().openapi({example: []}),
}),
},
},
description: "Internal Server Error",
},
// 401: {
// content: {
// "application/json": {
// schema: z.object({message: z.string().optional().openapi({example: "Unauthenticated"})}),
// },
// },
// description: "Unauthorized",
// },
// 500: {
// content: {
// "application/json": {
// schema: z.object({message: z.string().optional().openapi({example: "Internal Server error"})}),
// },
// },
// description: "Internal Server Error",
// },
},
path: "/getInfo",
responses: responses(),
}),
async (c) => {
// make sure we have a vaid user being accessed thats really logged in
apiHit(c, {endpoint: "api/auth/register"});
apiHit(c, { endpoint: "api/auth/register" });
try {
return c.json({success: true, message: "Ocme Info", data: await getInfo()}, 200);
return c.json(
{ success: true, message: "Ocme Info", data: await getInfo() },
200
);
} catch (error) {
return c.json({success: false, message: "There was an error getting ocmeInfo data", data: error}, 400);
return c.json(
{
success: false,
message: "There was an error getting ocmeInfo data",
data: error,
},
400
);
}
}
);

View File

@@ -1,94 +1,114 @@
import {createRoute, OpenAPIHono, z} from "@hono/zod-openapi";
import {apiHit} from "../../../globalUtils/apiHits.js";
import {getShipmentPallets} from "../controller/getShipmentPallets.js";
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { apiHit } from "../../../globalUtils/apiHits.js";
import { getShipmentPallets } from "../controller/getShipmentPallets.js";
const app = new OpenAPIHono();
const ShipmentID = z.object({
shipmentID: z.string().optional().openapi({example: "14558"}),
shipmentID: z.string().optional().openapi({ example: "14558" }),
});
app.openapi(
createRoute({
tags: ["ocme"],
summary: "Post New running number to be picked up.",
method: "post",
path: "/getshipmentpallets",
request: {
body: {
content: {
"application/json": {schema: ShipmentID},
},
},
createRoute({
tags: ["ocme"],
summary: "Post New running number to be picked up.",
method: "post",
path: "/GetShipmentPallets",
request: {
body: {
content: {
"application/json": { schema: ShipmentID },
},
responses: {
200: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({example: true}),
message: z.string().openapi({example: "Starter"}),
// data: z
// .array(z.object({sscc: z.string().optional()}))
// .optional()
// .openapi({example: []}),
}),
},
},
description: "Response message",
},
400: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({example: false}),
message: z.string().optional().openapi({example: "Internal Server error"}),
data: z.array(z.object({})).optional().openapi({example: []}),
}),
},
},
description: "Internal Server Error",
},
// 401: {
// content: {
// "application/json": {
// schema: z.object({message: z.string().optional().openapi({example: "Unauthenticated"})}),
// },
// },
// description: "Unauthorized",
// },
// 500: {
// content: {
// "application/json": {
// schema: z.object({message: z.string().optional().openapi({example: "Internal Server error"})}),
// },
// },
// description: "Internal Server Error",
// },
},
},
responses: {
200: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({ example: true }),
message: z.string().openapi({ example: "Starter" }),
// data: z
// .array(z.object({sscc: z.string().optional()}))
// .optional()
// .openapi({example: []}),
}),
},
},
}),
async (c) => {
// make sure we have a vaid user being accessed thats really logged in
try {
const data = await c.req.json();
apiHit(c, {endpoint: "api/ocme/getshipmentpallets", lastBody: data});
description: "Response message",
},
400: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({ example: false }),
message: z
.string()
.optional()
.openapi({ example: "Internal Server error" }),
data: z.array(z.object({})).optional().openapi({ example: [] }),
}),
},
},
description: "Internal Server Error",
},
// 401: {
// content: {
// "application/json": {
// schema: z.object({message: z.string().optional().openapi({example: "Unauthenticated"})}),
// },
// },
// description: "Unauthorized",
// },
// 500: {
// content: {
// "application/json": {
// schema: z.object({message: z.string().optional().openapi({example: "Internal Server error"})}),
// },
// },
// description: "Internal Server Error",
// },
},
}),
async (c) => {
// make sure we have a vaid user being accessed thats really logged in
try {
const data = await c.req.json();
apiHit(c, { endpoint: "api/ocme/getshipmentpallets", lastBody: data });
if (!data.shipmentID) {
return c.json(
{success: false, message: "You are missing the shipment id please try again.", data: []},
400
);
}
console.log;
const shiptmentData = await getShipmentPallets(data.shipmentID);
if (!data.shipmentID) {
return c.json(
{
success: false,
message: "You are missing the shipment id please try again.",
data: [],
},
400
);
}
return c.json(
{success: shiptmentData.success, message: shiptmentData.message, data: shiptmentData.data ?? []},
200
);
} catch (error) {
return c.json({success: false, message: "There was an error getting the shipment data.", data: error}, 400);
}
const shiptmentData = await getShipmentPallets(data.shipmentID);
return c.json(
{
success: shiptmentData.success,
message: shiptmentData.message,
data: shiptmentData.data ?? [],
},
200
);
} catch (error) {
return c.json(
{
success: false,
message: "There was an error getting the shipment data.",
data: error,
},
400
);
}
}
);
export default app;

View File

@@ -1,89 +1,114 @@
import {createRoute, OpenAPIHono, z} from "@hono/zod-openapi";
import {postLabelData} from "../controller/postRunningNr.js";
import {apiHit} from "../../../globalUtils/apiHits.js";
import {pickedup} from "../controller/pickedup.js";
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { postLabelData } from "../controller/postRunningNr.js";
import { apiHit } from "../../../globalUtils/apiHits.js";
import { pickedup } from "../controller/pickedup.js";
const app = new OpenAPIHono();
const PostRunningNr = z.object({
sscc: z.string().optional().openapi({example: "00090103830005710997"}),
runningNr: z.string().optional().openapi({example: "localhost"}),
areaFrom: z.string().optional().openapi({example: "The server we are going to connect to"}),
completed: z.boolean().optional().openapi({example: true}),
all: z.boolean().optional().openapi({example: false}),
sscc: z.string().optional().openapi({ example: "00090103830005710997" }),
runningNr: z.string().optional().openapi({ example: "localhost" }),
areaFrom: z
.string()
.optional()
.openapi({ example: "The server we are going to connect to" }),
completed: z.boolean().optional().openapi({ example: true }),
all: z.boolean().optional().openapi({ example: false }),
});
app.openapi(
createRoute({
tags: ["ocme"],
summary: "Picks up a pallet in the system.",
method: "patch",
description:
"removes the pallet(s) from showing as needed to be picked up, we clear everything related to the pallet number to reduce the risk of a mix, passing `all` will just clear everything that is pending.",
path: "/pickedup",
request: {
body: {
content: {
"application/json": {schema: PostRunningNr},
},
},
createRoute({
tags: ["ocme"],
summary: "Picks up a pallet in the system.",
method: "patch",
description:
"removes the pallet(s) from showing as needed to be picked up, we clear everything related to the pallet number to reduce the risk of a mix, passing `all` will just clear everything that is pending.",
path: "/pickedUp",
request: {
body: {
content: {
"application/json": { schema: PostRunningNr },
},
responses: {
200: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({example: true}),
message: z.string().openapi({example: "Starter"}),
// data: z
// .array(z.object({sscc: z.string().optional()}))
// .optional()
// .openapi({example: []}),
}),
},
},
description: "Response message",
},
400: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({example: false}),
message: z.string().optional().openapi({example: "Internal Server error"}),
data: z.array(z.object({})).optional().openapi({example: []}),
}),
},
},
description: "Internal Server Error",
},
// 401: {
// content: {
// "application/json": {
// schema: z.object({message: z.string().optional().openapi({example: "Unauthenticated"})}),
// },
// },
// description: "Unauthorized",
// },
500: {
content: {
"application/json": {
schema: z.object({message: z.string().optional().openapi({example: "Internal Server error"})}),
},
},
description: "Internal Server Error",
},
},
},
responses: {
200: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({ example: true }),
message: z.string().openapi({ example: "Starter" }),
// data: z
// .array(z.object({sscc: z.string().optional()}))
// .optional()
// .openapi({example: []}),
}),
},
},
}),
async (c) => {
// make sure we have a vaid user being accessed thats really logged in
try {
const data = await c.req.json();
apiHit(c, {endpoint: "api/ocme/pickedup", lastBody: data});
const postPallet = await pickedup(data);
return c.json({success: postPallet.success, message: postPallet.message, data: postPallet.data}, 200);
} catch (error) {
return c.json({success: false, message: "There was an error getting ocmeInfo data", data: error}, 400);
}
description: "Response message",
},
400: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({ example: false }),
message: z
.string()
.optional()
.openapi({ example: "Internal Server error" }),
data: z.array(z.object({})).optional().openapi({ example: [] }),
}),
},
},
description: "Internal Server Error",
},
// 401: {
// content: {
// "application/json": {
// schema: z.object({message: z.string().optional().openapi({example: "Unauthenticated"})}),
// },
// },
// description: "Unauthorized",
// },
500: {
content: {
"application/json": {
schema: z.object({
message: z
.string()
.optional()
.openapi({ example: "Internal Server error" }),
}),
},
},
description: "Internal Server Error",
},
},
}),
async (c) => {
// make sure we have a vaid user being accessed thats really logged in
try {
const data = await c.req.json();
apiHit(c, { endpoint: "api/ocme/pickedup", lastBody: data });
const postPallet = await pickedup(data);
return c.json(
{
success: postPallet.success,
message: postPallet.message,
data: postPallet.data,
},
200
);
} catch (error) {
return c.json(
{
success: false,
message: "There was an error getting ocmeInfo data",
data: error,
},
400
);
}
}
);
export default app;

View File

@@ -1,86 +1,106 @@
import {createRoute, OpenAPIHono, z} from "@hono/zod-openapi";
import {getInfo} from "../controller/getInfo.js";
import {postLabelData} from "../controller/postRunningNr.js";
import {apiHit} from "../../../globalUtils/apiHits.js";
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { getInfo } from "../controller/getInfo.js";
import { postLabelData } from "../controller/postRunningNr.js";
import { apiHit } from "../../../globalUtils/apiHits.js";
const app = new OpenAPIHono();
const PostRunningNr = z.object({
sscc: z.string().optional().openapi({example: "00090103830005710997"}),
runningNr: z.string().optional().openapi({example: "localhost"}),
areaFrom: z.string().optional().openapi({example: "The server we are going to connect to"}),
completed: z.boolean().optional().openapi({example: true}),
sscc: z.string().optional().openapi({ example: "00090103830005710997" }),
runningNr: z.string().optional().openapi({ example: "localhost" }),
areaFrom: z
.string()
.optional()
.openapi({ example: "The server we are going to connect to" }),
completed: z.boolean().optional().openapi({ example: true }),
});
app.openapi(
createRoute({
tags: ["ocme"],
summary: "Post New running number to be picked up.",
method: "post",
path: "/postrunningnumber",
request: {
body: {
content: {
"application/json": {schema: PostRunningNr},
},
},
createRoute({
tags: ["ocme"],
summary: "Post New running number to be picked up.",
method: "post",
path: "/postRunningNumber",
request: {
body: {
content: {
"application/json": { schema: PostRunningNr },
},
responses: {
200: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({example: true}),
message: z.string().openapi({example: "Starter"}),
// data: z
// .array(z.object({sscc: z.string().optional()}))
// .optional()
// .openapi({example: []}),
}),
},
},
description: "Response message",
},
400: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({example: false}),
message: z.string().optional().openapi({example: "Internal Server error"}),
data: z.array(z.object({})).optional().openapi({example: []}),
}),
},
},
description: "Internal Server Error",
},
// 401: {
// content: {
// "application/json": {
// schema: z.object({message: z.string().optional().openapi({example: "Unauthenticated"})}),
// },
// },
// description: "Unauthorized",
// },
// 500: {
// content: {
// "application/json": {
// schema: z.object({message: z.string().optional().openapi({example: "Internal Server error"})}),
// },
// },
// description: "Internal Server Error",
// },
},
},
responses: {
200: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({ example: true }),
message: z.string().openapi({ example: "Starter" }),
// data: z
// .array(z.object({sscc: z.string().optional()}))
// .optional()
// .openapi({example: []}),
}),
},
},
}),
async (c) => {
// make sure we have a vaid user being accessed thats really logged in
try {
const data = await c.req.json();
apiHit(c, {endpoint: "api/ocme/postRunningNumber", lastBody: data});
const postPallet = await postLabelData(data);
return c.json({success: postPallet.success, message: postPallet.message, data: postPallet.data ?? []}, 200);
} catch (error) {
return c.json({success: false, message: "There was an error getting ocmeInfo data", data: error}, 400);
}
description: "Response message",
},
400: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({ example: false }),
message: z
.string()
.optional()
.openapi({ example: "Internal Server error" }),
data: z.array(z.object({})).optional().openapi({ example: [] }),
}),
},
},
description: "Internal Server Error",
},
// 401: {
// content: {
// "application/json": {
// schema: z.object({message: z.string().optional().openapi({example: "Unauthenticated"})}),
// },
// },
// description: "Unauthorized",
// },
// 500: {
// content: {
// "application/json": {
// schema: z.object({message: z.string().optional().openapi({example: "Internal Server error"})}),
// },
// },
// description: "Internal Server Error",
// },
},
}),
async (c) => {
// make sure we have a vaid user being accessed thats really logged in
try {
const data = await c.req.json();
apiHit(c, { endpoint: "api/ocme/postRunningNumber", lastBody: data });
const postPallet = await postLabelData(data);
return c.json(
{
success: postPallet.success,
message: postPallet.message,
data: postPallet.data ?? [],
},
200
);
} catch (error) {
return c.json(
{
success: false,
message: "There was an error getting ocmeInfo data",
data: error,
},
400
);
}
}
);
export default app;

View File

@@ -1,86 +1,106 @@
import {createRoute, OpenAPIHono, z} from "@hono/zod-openapi";
import {getInfo} from "../controller/getInfo.js";
import {postLabelData} from "../controller/postRunningNr.js";
import {apiHit} from "../../../globalUtils/apiHits.js";
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { getInfo } from "../controller/getInfo.js";
import { postLabelData } from "../controller/postRunningNr.js";
import { apiHit } from "../../../globalUtils/apiHits.js";
const app = new OpenAPIHono();
const PostRunningNr = z.object({
sscc: z.string().optional().openapi({example: "00090103830005710997"}),
runningNr: z.string().optional().openapi({example: "localhost"}),
areaFrom: z.string().optional().openapi({example: "The server we are going to connect to"}),
completed: z.boolean().optional().openapi({example: true}),
sscc: z.string().optional().openapi({ example: "00090103830005710997" }),
runningNr: z.string().optional().openapi({ example: "localhost" }),
areaFrom: z
.string()
.optional()
.openapi({ example: "The server we are going to connect to" }),
completed: z.boolean().optional().openapi({ example: true }),
});
app.openapi(
createRoute({
tags: ["ocme"],
summary: "Post New running number to be picked up.",
method: "post",
path: "/postsscc",
request: {
body: {
content: {
"application/json": {schema: PostRunningNr},
},
},
createRoute({
tags: ["ocme"],
summary: "Post New running number to be picked up.",
method: "post",
path: "/postSSCC",
request: {
body: {
content: {
"application/json": { schema: PostRunningNr },
},
responses: {
200: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({example: true}),
message: z.string().openapi({example: "Starter"}),
// data: z
// .array(z.object({sscc: z.string().optional()}))
// .optional()
// .openapi({example: []}),
}),
},
},
description: "Response message",
},
400: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({example: false}),
message: z.string().optional().openapi({example: "Internal Server error"}),
data: z.array(z.object({})).optional().openapi({example: []}),
}),
},
},
description: "Internal Server Error",
},
// 401: {
// content: {
// "application/json": {
// schema: z.object({message: z.string().optional().openapi({example: "Unauthenticated"})}),
// },
// },
// description: "Unauthorized",
// },
// 500: {
// content: {
// "application/json": {
// schema: z.object({message: z.string().optional().openapi({example: "Internal Server error"})}),
// },
// },
// description: "Internal Server Error",
// },
},
},
responses: {
200: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({ example: true }),
message: z.string().openapi({ example: "Starter" }),
// data: z
// .array(z.object({sscc: z.string().optional()}))
// .optional()
// .openapi({example: []}),
}),
},
},
}),
async (c) => {
// make sure we have a vaid user being accessed thats really logged in
try {
const data = await c.req.json();
apiHit(c, {endpoint: "api/ocme/postRunningNumber", lastBody: data});
const postPallet = await postLabelData(data);
return c.json({success: postPallet.success, message: postPallet.message, data: postPallet.data ?? []}, 200);
} catch (error) {
return c.json({success: false, message: "There was an error getting ocmeInfo data", data: error}, 400);
}
description: "Response message",
},
400: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({ example: false }),
message: z
.string()
.optional()
.openapi({ example: "Internal Server error" }),
data: z.array(z.object({})).optional().openapi({ example: [] }),
}),
},
},
description: "Internal Server Error",
},
// 401: {
// content: {
// "application/json": {
// schema: z.object({message: z.string().optional().openapi({example: "Unauthenticated"})}),
// },
// },
// description: "Unauthorized",
// },
// 500: {
// content: {
// "application/json": {
// schema: z.object({message: z.string().optional().openapi({example: "Internal Server error"})}),
// },
// },
// description: "Internal Server Error",
// },
},
}),
async (c) => {
// make sure we have a vaid user being accessed thats really logged in
try {
const data = await c.req.json();
apiHit(c, { endpoint: "api/ocme/postRunningNumber", lastBody: data });
const postPallet = await postLabelData(data);
return c.json(
{
success: postPallet.success,
message: postPallet.message,
data: postPallet.data ?? [],
},
200
);
} catch (error) {
return c.json(
{
success: false,
message: "There was an error getting ocmeInfo data",
data: error,
},
400
);
}
}
);
export default app;

View File

@@ -0,0 +1,28 @@
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { getInfo } from "../controller/getInfo.js";
import { apiHit } from "../../../globalUtils/apiHits.js";
import { responses } from "../../../globalUtils/routeDefs/responses.js";
import { triggerScanner } from "../controller/triggerCamera.js";
const app = new OpenAPIHono({ strict: false });
app.openapi(
createRoute({
tags: ["ocme"],
summary: "Triggers the camera at the end of the dyco.",
method: "get",
path: "/manualCameraTrigger",
responses: responses(),
}),
async (c) => {
// make sure we have a vaid user being accessed thats really logged in
apiHit(c, { endpoint: "api/auth/register" });
const manualTrigger: any = await triggerScanner();
console.log(manualTrigger);
return c.json({
success: manualTrigger.success,
message: manualTrigger.message,
});
}
);
export default app;

View File

@@ -0,0 +1,94 @@
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.1/Manufacturing/ProductionControlling/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.status != 200) {
createLog(
"error",
"labeling",
"ocp",
`${data.printer[0].name}, Error:${res.data}`
);
//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 {
const booked = await db
.update(prodlabels)
.set({
status: "Booked in",
upd_date: sql`NOW()`,
})
.where(
eq(prodlabels.runningNr, parseInt(data.SSCC.slice(10, -1)))
)
.returning({ runningNr: prodlabels.runningNr });
createLog(
"info",
"labeling",
"ocp",
`${booked[0].runningNr} , was just booked in.`
);
return {
success: true,
message: `${parseInt(
data.SSCC.slice(10, -1)
)}, was just booked in`,
};
} catch (error) {
createLog(
"error",
"labeling",
"ocp",
`Error creating new runningNumber in the DB.`
);
}
} catch (error) {
createLog(
"error",
"labeling",
"ocp",
`${data.printer[0].name}, "Error: ${error}`
);
return {
success: false,
message: "There was an error booking in the label.",
data: error,
};
}
};

View File

@@ -0,0 +1,168 @@
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 {
const insertLabel = 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",
})
.returning({ runningNr: prodlabels.runningNr });
createLog(
"info",
"labeling",
"ocp",
`${insertLabel[0]?.runningNr} was just inserted into the db.`
);
} 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

@@ -0,0 +1,33 @@
import { desc, gte, lte, sql } from "drizzle-orm";
import { db } from "../../../../../database/dbclient.js";
import { prodlabels } from "../../../../../database/schema/prodLabels.js";
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
export const getLabels = async (hours: string) => {
const { data: labelInfo, error: labelError } = await tryCatch(
db
.select()
.from(prodlabels)
.where(
gte(
prodlabels.upd_date,
sql.raw(`NOW() - INTERVAL '${hours} hours'`)
)
)
.orderBy(desc(prodlabels.upd_date))
);
if (labelError) {
return {
success: false,
message: "There was an error getting the labels",
data: [labelError],
};
}
return {
success: true,
message: "Current labels order by upd_Date.",
count: labelInfo.length,
data: labelInfo,
};
};

View File

@@ -0,0 +1,243 @@
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[0]?.HumanReadableId
);
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 {
success: false,
message: `Main material is not prepaired for lot ${filteredLot[0].lot}`,
};
}
// 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 {
success: false,
message: `Prolink does not match for ${filteredLot[0].MachineDescription}`,
};
}
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,52 @@
import { db } from "../../../../../database/dbclient.js";
import { manualPrinting } from "../../../../../database/schema/ocpManualPrint.js";
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
import { manualTag } from "../../../rfid/controller/tags/manualTag.js";
import { labelingProcess } from "./labelProcess.js";
export const manualPrint = async (manualPrint: any) => {
/**
* add the reason we did a manual print.
*/
const manualPrintData = {
line: manualPrint.line,
printReason: manualPrint.printReason,
initials: manualPrint.initials,
additionalComments: manualPrint?.additionalComments,
add_user: "lst",
};
const { data, error } = await tryCatch(
db.insert(manualPrinting).values(manualPrintData).returning({
line: manualPrinting.line,
printReason: manualPrinting.printReason,
initials: manualPrinting.initials,
additionalComments: manualPrinting?.additionalComments,
add_user: manualPrinting.add_user,
})
);
if (error) {
return {
success: false,
message: "There was an error posting the manualPrintData",
data: error,
};
}
let label = await labelingProcess({ line: manualPrint.line });
if (manualPrint.rfidTag) {
manualTag(
manualPrint.rfidTag,
"wrapper1",
parseInt(label.data.SSCC.slice(10, -1))
);
}
return {
success: true,
message: "Log Entered label will be coming soon.",
data,
};
};

View File

@@ -0,0 +1,23 @@
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
import { query } from "../../../sqlServer/prodSqlServer.js";
import { lotQuery } from "../../../sqlServer/querys/ocp/lots.js";
export const getLots = async () => {
const { data: lotInfo, error: lotError } = await tryCatch(
query(lotQuery, "Alplalabel online lots")
);
if (lotError) {
return {
success: false,
message: "There was an error getting the lots",
data: lotError,
};
}
return {
success: true,
message: "Current active lots that are technically released.",
data: lotInfo,
};
};

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 { query } from "../../../sqlServer/prodSqlServer.js";
import { prolinkQuery } from "../../../sqlServer/querys/ocp/prolinkCheck.js";
// check the if the lot matches
export const prolinkCheck = async (lot: any) => {
const { data, error: settingError } = await tryCatch(
db.select().from(settings)
);
if (settingError) {
createLog(
"error",
"ocp",
"ocp",
`There was an error getting the settings.`
);
return;
}
const settingData: any = data;
const plantToken = settingData.filter(
(s: any) => s.name === "plantToken"
)[0].value;
const prolinkCheck = settingData.filter(
(s: any) => s.name === "prolinkCheck"
)[0].value;
// if we want to ignore prolink check it will be disabled and then just return a pass as true
if (prolinkCheck === "0") {
createLog(
"info",
"ocp",
"ocp",
`Prolink Check is disabled skipping check.`
);
return true;
}
// run the query
try {
const prolink = await query(prolinkQuery, "Prolink Checks");
// filter out the lot
const filterdLot = prolink.filter(
(p: any) => p.AlplaLabelOnline === lot
);
//console.log(filterdLot);
if (filterdLot[0].LotCheck === "Good") {
return true;
} else {
return false;
}
} catch (err) {
createLog(
"error",
"ocp",
"ocp",
`Error from running the Prolink Check query: ${err}`
);
return false;
}
};

View File

@@ -1,20 +0,0 @@
import {db} from "../../../../database/dbclient.js";
import {manualPrinting} from "../../../../database/schema/ocpManualPrint.js";
export const manualPrint = async (data: any) => {
/**
* add the reason we did a manual print.
*/
const manualPrintData = {
line: data.line,
printReason: data.printReason,
initials: data.initials,
additionalComments: data?.additionalComments,
add_user: "lst",
};
try {
const manualPrint = await db.insert(manualPrinting).values(manualPrintData);
} catch (error) {}
};

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

@@ -0,0 +1,21 @@
import { db } from "../../../../../database/dbclient.js";
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
import { printers } from "../../../../../database/schema/printers.js";
export const getPrinters = async () => {
const currentTime = new Date(Date.now());
const { data: printerData, error: printerError } = await tryCatch(
db.select().from(printers)
);
if (printerError) {
return {
success: false,
message: "there was an error getting the printers",
data: printerError,
};
}
return { success: true, message: "Printers", data: printerData };
};

View File

@@ -0,0 +1,84 @@
import { printers } from "../../../../../database/schema/printers.js";
import axios from "axios";
import { sql } from "drizzle-orm";
import { prodEndpointCreation } from "../../../../globalUtils/createUrl.js";
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
import { lstAuth } from "../../../../index.js";
import { db } from "../../../../../database/dbclient.js";
import { createLog } from "../../../logger/logger.js";
export const updatePrinters = async () => {
const currentTime = new Date(Date.now());
// get the printers from prod
let url = await prodEndpointCreation(
"/public/v1.0/Administration/Printers"
);
const { data: prodPrinters, error: prodError } = await tryCatch(
axios.get(url, {
headers: {
Authorization: `Basic ${lstAuth}`,
"Content-Type": "application/json",
},
})
);
if (prodError) {
console.log(prodError);
return {
success: false,
message: "there was an error getting the printers.",
data: prodError,
};
}
// do the printer update into our db
const prodPrinterInfo = prodPrinters.data;
for (let i = 0; i < prodPrinterInfo.length; i++) {
const printerStuff: any = {
humanReadableId: prodPrinterInfo[i].humanReadableId,
name: prodPrinterInfo[i].name,
ipAddress: prodPrinterInfo[i].ipAddress,
port: prodPrinterInfo[i].port,
remark: prodPrinterInfo[i].remark,
};
const { data, error } = await tryCatch(
db
.insert(printers)
.values(printerStuff)
.onConflictDoUpdate({
target: printers.humanReadableId,
set: {
//humanReadableId: prodPrinterInfo[i].humanReadableId,
name: prodPrinterInfo[i].name,
ipAddress: prodPrinterInfo[i].ipAddress,
port: prodPrinterInfo[i].port,
remark: prodPrinterInfo[i].remark,
upd_date: sql`NOW()`,
},
})
);
if (error) {
createLog(
"error",
"lst",
"ocp",
`${
prodPrinterInfo[i].name
} encoutered and error adding/updating ${JSON.stringify(error)}`
);
}
createLog(
"debug",
"lst",
"ocp",
`${prodPrinterInfo[i].name} were just added/updated.`
);
}
return { success: true, message: "Printers were just added or 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,103 @@
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";
import { strapperFaults } from "./plcTags/strapperFault.js";
let PLC = new Controller();
let isDycoRunning = false;
// PLC address
let plcAddress = "10.44.5.4";
let isReading = false;
// 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;
plcCycle = setInterval(async () => {
if (isReading) {
createLog(
"debug",
"dyco",
"ocp",
"Skipping cycle: previous read still in progress."
);
return;
}
isReading = true; // Set flag
try {
await PLC.readTag(labelerTag);
await PLC.readTag(palletSend);
await PLC.readTag(strapperError);
// strapper check
strapperFaults(strapperError);
// send the labeler tag data over
labelerTagRead(labelerTag);
// send the end of line check over.
palletSendTag(palletSend);
} catch (error: any) {
createLog(
"error",
"dyco",
"ocp",
`Error reading PLC tag: ${error.message}`
);
} finally {
isReading = false; // Reset flag
}
}, plcInterval);
});
} catch (error) {
createLog(
"error",
"dyco",
"ocp",
`There was an error in the dyco: ${error}`
);
await PLC.disconnect();
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,108 @@
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";
import { stapperFaulted, strapperFaults } from "./strapperFault.js";
export let cameraPalletCheck = 20;
export let currentPalletCheck = 0;
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;
/**
* add logic in to see if this is the first time we run this so we return an error to validate we are in sync.
*/
createLog(
"info",
"dyco",
"ocp",
`Current pallet at the wrapper is: ${numericString}`
);
if (dycoPrint[0].value === "1") {
createLog("info", "dyco", "ocp", "Dyco will be printing the label");
// if (!dycoControlCheck) {
// createLog(
// "error",
// "dyco",
// "ocp",
// `Dyco was switch to be the printer guys. please validate the line is in sync, Current line is ${numericString}`
// );
// dycoControlCheck = true;
// return;
// }
// check the stapper error logic.
if (stapperFaulted) {
createLog("error", "dyco", "ocp", `Strapper is faulted.`);
return;
}
// check if we need to manual check due to 20 pallets.
if (currentPalletCheck <= cameraPalletCheck) {
currentPalletCheck = currentPalletCheck + 1;
labelingProcess({ line: numericString });
} else {
currentPalletCheck = 0;
createLog(
"error",
"dyco",
"ocp",
`You have reached 20 pallets since the last check please validate the labeler is still in sync.`
);
}
}
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.
setTimeout(async () => {
await readTags("wrapper1");
}, 2 * 1000);
}
}
};
/**
* 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,74 @@
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";
// strapper related issues
export let strapperActive = true;
export let stapperFaulted = false;
export let strapperFaultCount = 3; // move to db so we can control it outside the app
let alreadyAlerted = false;
export const strapperFaults = async (tagData: any) => {
const { data, error } = await tryCatch(db.select().from(settings));
if (error) {
return { success: false, message: "Failed to get settings." };
}
const strapperCheckSetting = data.filter((n) => n.name === "strapperCheck");
if (strapperCheckSetting[0]?.value === "1") {
if (stapperFaulted && strapperFaultCount > 0) {
createLog(
"warn",
"dyco",
"ocp",
`There was a strapper error, remaining pallets to check ${strapperFaultCount}.`
);
alreadyAlerted = true;
strapperFaultCount = strapperFaultCount - 1;
return {
success: false,
message: `There was a strapper error, remaining pallets to check ${strapperFaultCount}.`,
};
} else {
createLog(
"debug",
"dyco",
"ocp",
`Strapper check is active but not faulted, remaining pallets to check ${strapperFaultCount}.`
);
// reset everything
stapperFaulted = false;
strapperFaultCount = 3; // move to db as well
return {
success: true,
message: `Strapper check is active but not faulted, remaining pallets to check ${strapperFaultCount}.`,
};
}
}
if (strapperActive) {
// monitor strapper
//console.log(`Strapper fault is ${strapperError.value}`);
if (tagData.value && strapperFaultCount > 0) {
// strapper faulted we want to start the trigger to force the check
if (!stapperFaulted) {
createLog(
"error",
"dyco",
"ocp",
`Strapper errored triggering manual checks will be required for the next ${strapperFaultCount}`
);
}
stapperFaulted = true;
alreadyAlerted = true;
// change move fault count to db....
strapperFaultCount = 3;
}
}
};

Some files were not shown because too many files have changed in this diff Show More