Compare commits
87 Commits
a96b85bc53
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| dcfa56bdb9 | |||
| ea92422bb1 | |||
| 2111a5fdc9 | |||
| 6edd20585f | |||
| a9759795c4 | |||
| 32f26a1725 | |||
| 60533beed5 | |||
| 24ced97b6d | |||
| dc1d342799 | |||
| 44d0cb63cf | |||
| ace73fa919 | |||
| 316af4233f | |||
| 36a805c652 | |||
| 460bc3d24a | |||
| ec201fcfb5 | |||
| 914ad46c43 | |||
| b96c546ed3 | |||
| 29b3be41a1 | |||
| 16edf58025 | |||
| 775627f215 | |||
| 4e70fae69b | |||
| 24dd109a21 | |||
| 38b57a00cc | |||
| f8070db95f | |||
| 10e9dc430c | |||
| 6b669ccd9c | |||
| d9a10d98a1 | |||
| e64dc7c013 | |||
| d63138d746 | |||
| 84a28f2d01 | |||
| 9be6614972 | |||
| 9d0db71f6a | |||
| 3cc55436f3 | |||
| 124fde07e0 | |||
| b15d0d7322 | |||
| 0680f332fb | |||
| 46bf310dce | |||
| 0dda6ae744 | |||
| 1b59cdd3a4 | |||
| 56934216f7 | |||
| e8a2ef8b85 | |||
| 6cbffa4ac5 | |||
| 09f16f4e62 | |||
| 461acb2b16 | |||
| 0d05c66a2b | |||
| 096cc18477 | |||
| f3333ce020 | |||
| 8e3d2b3d95 | |||
| 501709546d | |||
| 2b5e77993b | |||
| 6efaffbb17 | |||
| 90ddbca2e7 | |||
| 7a9ea16f48 | |||
| 420826de9b | |||
| dc2d3718fa | |||
| 5013228384 | |||
| 4459742cf0 | |||
| 070c3ee975 | |||
| 8ac92888ad | |||
| 567579ef35 | |||
| 8d90f27514 | |||
| 722b23a321 | |||
| ba48c5307f | |||
| 30d2ec0477 | |||
| d3c6444491 | |||
| 12345c0b64 | |||
| 6833dfc992 | |||
| ac27a286c0 | |||
| a3dba6cc9d | |||
| 320dd47aea | |||
| 712a6eebdf | |||
| f226c5644c | |||
| d605225e48 | |||
| 8e7f1eb098 | |||
| 59c6fd0117 | |||
| 2607fd3026 | |||
| bdb4bfc53d | |||
| c1816c07ff | |||
| 7311372ba8 | |||
| cd53460bec | |||
| 7e15e5d7bc | |||
| 3193e07e47 | |||
| 40bc19aa6f | |||
| 90920e8fba | |||
| f8cf0851a8 | |||
| efdab5bafc | |||
| 700346d809 |
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@@ -49,12 +49,15 @@
|
|||||||
"go.formatTool": "goimports",
|
"go.formatTool": "goimports",
|
||||||
"cSpell.words": [
|
"cSpell.words": [
|
||||||
"acitve",
|
"acitve",
|
||||||
|
"actaully",
|
||||||
"alpla",
|
"alpla",
|
||||||
"alplamart",
|
"alplamart",
|
||||||
"alplaprod",
|
"alplaprod",
|
||||||
|
"autoconsume",
|
||||||
"intiallally",
|
"intiallally",
|
||||||
"ppoo",
|
"ppoo",
|
||||||
"prodlabels"
|
"prodlabels",
|
||||||
|
"rfid"
|
||||||
],
|
],
|
||||||
"gitea.token": "8456def90e1c651a761a8711763d6ef225d6b2db",
|
"gitea.token": "8456def90e1c651a761a8711763d6ef225d6b2db",
|
||||||
"gitea.instanceURL": "https://git.tuffraid.net",
|
"gitea.instanceURL": "https://git.tuffraid.net",
|
||||||
|
|||||||
133
CHANGELOG.md
133
CHANGELOG.md
@@ -1,5 +1,138 @@
|
|||||||
# All Changes to LST can be found below.
|
# All Changes to LST can be found below.
|
||||||
|
|
||||||
|
## [1.9.0](https://git.tuffraid.net/cowch/lst/compare/v1.8.0...v1.9.0) (2025-12-03)
|
||||||
|
|
||||||
|
|
||||||
|
### 📝 Chore
|
||||||
|
|
||||||
|
* **module updates:** just updated all the modules ([bdb4bfc](https://git.tuffraid.net/cowch/lst/commits/bdb4bfc53d24f37f0e7098ea828cf418d58d5224))
|
||||||
|
|
||||||
|
|
||||||
|
### 🌟 Enhancements
|
||||||
|
|
||||||
|
* **datamart:** active article moved over to the new version ([8e7f1eb](https://git.tuffraid.net/cowch/lst/commits/8e7f1eb09811fcf3ea49b95b0ba9a8f55b9c4184))
|
||||||
|
* **dm:** added article description into the historical data ([7311372](https://git.tuffraid.net/cowch/lst/commits/7311372ba8eb901b51972ca216152bcfc2b009af))
|
||||||
|
* **swagger:** added in the start of swagger where all the common and useable endpoints will be ([2607fd3](https://git.tuffraid.net/cowch/lst/commits/2607fd3026ed0b5777a5598aa3498ffc67baa012))
|
||||||
|
|
||||||
|
|
||||||
|
### 🛠️ Code Refactor
|
||||||
|
|
||||||
|
* **contorller:** only install npm production modules dont install everything ([c1816c0](https://git.tuffraid.net/cowch/lst/commits/c1816c07ff5ac939b0997d314a9da624a4a66b7a))
|
||||||
|
* **helpercommands:** removed the remove as reusabele ([a3dba6c](https://git.tuffraid.net/cowch/lst/commits/a3dba6cc9db147ff4765fef648867e50878a6ac8))
|
||||||
|
* **quality:** added a check to monior [#7](https://git.tuffraid.net/cowch/lst/issues/7) as well ([6833dfc](https://git.tuffraid.net/cowch/lst/commits/6833dfc9929741203083b01726b83a6c8d61d308))
|
||||||
|
* **sql:** some changes to help with sql connection on random disconnect ([320dd47](https://git.tuffraid.net/cowch/lst/commits/320dd47aea017b4ff219b07e363ef87ec8523b82))
|
||||||
|
* **swagger:** corrected the name displaced ([d605225](https://git.tuffraid.net/cowch/lst/commits/d605225e48bca66f915ce0db448aa61933891986))
|
||||||
|
|
||||||
|
|
||||||
|
### 🐛 Bug fixes
|
||||||
|
|
||||||
|
* **commands:** corrections to allow external labels to be consumed and transfered ([12345c0](https://git.tuffraid.net/cowch/lst/commits/12345c0b6442c3abd309f660bb43216def9abb89))
|
||||||
|
* **dm:** type in customer article number ([f226c56](https://git.tuffraid.net/cowch/lst/commits/f226c5644cc2b93b9d967962bd6f82b3e506c8c0))
|
||||||
|
* **labeling:** added in a catch to avoid rouge lots ([59c6fd0](https://git.tuffraid.net/cowch/lst/commits/59c6fd011728dff50bfa3233d6095c396d0b1999))
|
||||||
|
* **lot transfer:** changes to make it so the reprint and return do not happen instantly ([ac27a28](https://git.tuffraid.net/cowch/lst/commits/ac27a286c07733333703d8421cfa525691363e54))
|
||||||
|
* **lstv2:** added in a close function to stop crashing the server ([712a6ee](https://git.tuffraid.net/cowch/lst/commits/712a6eebdfef0ce2b99155d23422ddc7e5e0daad))
|
||||||
|
|
||||||
|
## [1.8.0](https://git.tuffraid.net/cowch/lst/compare/v1.7.0...v1.8.0) (2025-11-25)
|
||||||
|
|
||||||
|
|
||||||
|
### 📝 Chore
|
||||||
|
|
||||||
|
* **misc:** api doc dates and db changes ([52089ec](https://git.tuffraid.net/cowch/lst/commits/52089ecdf06d9e5983afb6a24953d066a0456949))
|
||||||
|
|
||||||
|
|
||||||
|
### 📈 Project changes
|
||||||
|
|
||||||
|
* **settings:** changes to vs code as it was being way to slow ([5277ddf](https://git.tuffraid.net/cowch/lst/commits/5277ddfc51632651059e35b799ddf2a63d70cb70))
|
||||||
|
|
||||||
|
|
||||||
|
### 📝 Testing Code
|
||||||
|
|
||||||
|
* **android app:** this is the start to the android app ([7b630d5](https://git.tuffraid.net/cowch/lst/commits/7b630d5c0b1175f06c866b1238754e455d3a27c9))
|
||||||
|
* **controller:** added in server port that might night be needed but oh well ([efdab5b](https://git.tuffraid.net/cowch/lst/commits/efdab5bafca2a46d73de7ab1d776d283d5294aa3))
|
||||||
|
* **materials per day:** work on getting this running better ([a30eebf](https://git.tuffraid.net/cowch/lst/commits/a30eebf5d34c77c6c7118faf01776651f8888547))
|
||||||
|
* **mobile:** more testing on ota ([75c0659](https://git.tuffraid.net/cowch/lst/commits/75c0659658cbbb7e983df5538538d6429a325379))
|
||||||
|
* **mobile:** stallion intergration starts ([20fc286](https://git.tuffraid.net/cowch/lst/commits/20fc2860690f59851ca1e0251df84854c9d2ba01))
|
||||||
|
* **mobile:** testing for ota updated on android scanner ([314ab04](https://git.tuffraid.net/cowch/lst/commits/314ab049bb650120489259e920e52fd530f0ce41))
|
||||||
|
* **ti intergration:** added the place holder for intergration of comments for customer ([f8cf085](https://git.tuffraid.net/cowch/lst/commits/f8cf0851a86a6923a8941774efe17f93cb92e984))
|
||||||
|
|
||||||
|
|
||||||
|
### 🛠️ Code Refactor
|
||||||
|
|
||||||
|
* **all server stats:** added a 5 second time out if it dose not reach it just stops ([2133b94](https://git.tuffraid.net/cowch/lst/commits/2133b94a1dd84e16bb5a4b8fe215739a4b355223))
|
||||||
|
* **app:** refactored how we have the pkg.json so we can reduce on size of the app ([90920e8](https://git.tuffraid.net/cowch/lst/commits/90920e8fba4757297e0e42e86f80d5f14434a48e))
|
||||||
|
* **base modules:** removed the log spam ([6d27a7a](https://git.tuffraid.net/cowch/lst/commits/6d27a7aa6395a094d8763ba3fde0bdb81a7e3082))
|
||||||
|
* **cards:** trying to make the cards fit the odd shaped screens better ([33cbb17](https://git.tuffraid.net/cowch/lst/commits/33cbb17a0ede136a9be96e47ba0a7a66468b1ebc))
|
||||||
|
* **forklifts:** more refactoring to improve during production ([8c0f67c](https://git.tuffraid.net/cowch/lst/commits/8c0f67ca351778405279f7e225ee8dae654033f9))
|
||||||
|
* **inv with rn:** now includes batch number for tetra ([1084ced](https://git.tuffraid.net/cowch/lst/commits/1084cede04d43ec2b2c22c43c6e701bad4701981))
|
||||||
|
* **leases:** removed main server until i have a better way to sync them ([6ce4d84](https://git.tuffraid.net/cowch/lst/commits/6ce4d84fd00fa446ccb7d1bbad28680f045fae52))
|
||||||
|
* **ocp page:** using the name of the url now vs the settings ([d406a92](https://git.tuffraid.net/cowch/lst/commits/d406a92f3d5d6a8902164e9182717912debae804))
|
||||||
|
* **ocp:** work around for zechetti 2 until we can monitor more closing ([700346d](https://git.tuffraid.net/cowch/lst/commits/700346d80972e464d0a9ba62bba4dc0ed949cdee))
|
||||||
|
* **quality:** added some new options plus cancel button ([242ff62](https://git.tuffraid.net/cowch/lst/commits/242ff6277a1f407fbed2951d30dd6cf1ee32dd60))
|
||||||
|
* **quality:** more changes to the system to perfect it ([7b28f4e](https://git.tuffraid.net/cowch/lst/commits/7b28f4e9ef32a4fc90a0b4b16953b6cead096cac))
|
||||||
|
* **serverlist:** refactored to also show uptime and other info about the server ([e1e659f](https://git.tuffraid.net/cowch/lst/commits/e1e659f9b14f22474f919350f07b02b45141aa63))
|
||||||
|
* **types:** moved the item type to the sidebar to keep it more clean ([5023d4d](https://git.tuffraid.net/cowch/lst/commits/5023d4d129737cf6e0609592e5606a20a0f3728b))
|
||||||
|
* **wrapper:** removed the logs so its not spamming the server ([b8a9aa5](https://git.tuffraid.net/cowch/lst/commits/b8a9aa5132c7606fcccae8f058a77a11a8ed552a))
|
||||||
|
|
||||||
|
|
||||||
|
### 🐛 Bug fixes
|
||||||
|
|
||||||
|
* **comments:** added new role to put comments in ([1283a63](https://git.tuffraid.net/cowch/lst/commits/1283a63b5fd71fb44f7ec7789f670f8af7eafbb8))
|
||||||
|
* **correction:** the name needed to be correct to have a proper tempalte ([b1c56ee](https://git.tuffraid.net/cowch/lst/commits/b1c56ee4bb32c0dbf86e0164614fb3f1ecaf262d))
|
||||||
|
* **dm:** correction to passing the username over for the importing of the file ([a7a9aa2](https://git.tuffraid.net/cowch/lst/commits/a7a9aa2874ddd1391b56983db51cfabd8e789213))
|
||||||
|
* **dm:** fixes to validate auth before submiting incase someone stays on the page to long ([fef0303](https://git.tuffraid.net/cowch/lst/commits/fef0303cd6fdc9cc8cf9f9f4ad674a8b725691f3))
|
||||||
|
* **file name wrong:** fixed the name of the file for getCompanies ([8996da7](https://git.tuffraid.net/cowch/lst/commits/8996da7eb46a8b5bdfe44ee74a676e701d64fdbf))
|
||||||
|
* **forecast table:** correction to the customer article number ([ebe5c0b](https://git.tuffraid.net/cowch/lst/commits/ebe5c0bd5a883b1cbe87f7f9932fd803e80e7fae))
|
||||||
|
* **historical date:** added so we can have all dates ([9d793d2](https://git.tuffraid.net/cowch/lst/commits/9d793d22051c585ed224bfaf16e2a9b60bb02635))
|
||||||
|
* **historical inv:** corrected the way the date can come over to allow for yyyy-mm-dd or with / ([7c40f02](https://git.tuffraid.net/cowch/lst/commits/7c40f028c88d7fd78ac8ab75c172d808783fc641)), closes [#1](https://git.tuffraid.net/cowch/lst/issues/1)
|
||||||
|
* **historicalinv:** removed the second running one that caused duplicates ([a6cc17c](https://git.tuffraid.net/cowch/lst/commits/a6cc17ccb12b0d99ffdb1d371c5daf3bbb91f7ba))
|
||||||
|
* **label ratio:** correction to the endpoint ([50b7c9c](https://git.tuffraid.net/cowch/lst/commits/50b7c9cac5cd6923b08a8705fc8cb41530ec5b02))
|
||||||
|
* **manual print:** fixed so the print disables ([d3e8e94](https://git.tuffraid.net/cowch/lst/commits/d3e8e941103dc0118066e8790e7c27e5f035a6c5))
|
||||||
|
* **nav:** added missing add card button ([8fca201](https://git.tuffraid.net/cowch/lst/commits/8fca201e0463aba7ecace61f8dfb737e2acf4140))
|
||||||
|
* **ocp:** made corrections to the ocp page in dayton ([92af726](https://git.tuffraid.net/cowch/lst/commits/92af7262f60514501b903f5307d34e9154cc9034))
|
||||||
|
* **plc zeccetti:** changes to improve the timing on the zecetti more to be done ([247010d](https://git.tuffraid.net/cowch/lst/commits/247010d48f10ebb02a1b98c5df101134e8dab250))
|
||||||
|
* **preprint:** added the correct to string for the preprint stuff ([360c016](https://git.tuffraid.net/cowch/lst/commits/360c0163f1d3135d9c1c3788ac53dc8e0757c441))
|
||||||
|
* **prodendpoint:** if we have a real error just report it dont actually crash ([3193e07](https://git.tuffraid.net/cowch/lst/commits/3193e07e4707d055517b15f77ac117fefe07de12))
|
||||||
|
* **quality request:** bug fixes ([6f632ec](https://git.tuffraid.net/cowch/lst/commits/6f632ecd6831456c6e3c9973bc0ce7feb229aeec))
|
||||||
|
* **quality:** corrected url and perms for quality link ([eb6b9ce](https://git.tuffraid.net/cowch/lst/commits/eb6b9ce388c5dea35f95a9403765e7d330b664f9))
|
||||||
|
* **quality:** request was missing the forced selection ([96c3e4c](https://git.tuffraid.net/cowch/lst/commits/96c3e4c24adbdc59d11f7ea43888e1c47d061f90))
|
||||||
|
* **register:** added the ability to put in _ for user name ([aba1668](https://git.tuffraid.net/cowch/lst/commits/aba1668d2cab63a031657fb7c9f2bfb9777fa72a))
|
||||||
|
* **servers:** changed the server name to be unique ([a7bde5e](https://git.tuffraid.net/cowch/lst/commits/a7bde5e4eb41c597f94302dd2d119f7048c18a6f))
|
||||||
|
* **silo adjustments:** added supervisor to see the actual page so it matches the sidbard ([9aa0b31](https://git.tuffraid.net/cowch/lst/commits/9aa0b31278e5f8201acd21774f19ba69709a654d))
|
||||||
|
* **silo commits:** added in email that was now missing due to new authj ([25a958d](https://git.tuffraid.net/cowch/lst/commits/25a958d592d189f896ae0b5f7608d80a6ee2b1e7))
|
||||||
|
* **uom:** correction to how we do the uom check so we dont just look for the space ([ca866bf](https://git.tuffraid.net/cowch/lst/commits/ca866bf8c63e0576e890367d24a47c7ab46cc864))
|
||||||
|
|
||||||
|
|
||||||
|
### 🌟 Enhancements
|
||||||
|
|
||||||
|
* **added in swagger:** added the base for swagger to implement fully later ([9d9ca63](https://git.tuffraid.net/cowch/lst/commits/9d9ca63d7c9ab3e3ea168cf2add9c7baf2b9ed15))
|
||||||
|
* **articles:** moved articles over to the main server ([2a6eafa](https://git.tuffraid.net/cowch/lst/commits/2a6eafa19a97f0be01f63c68b63b4abfc4de1409))
|
||||||
|
* **barcode gen:** added the missing link ([b4064e8](https://git.tuffraid.net/cowch/lst/commits/b4064e87691937ad9f99441767b556a167b91055))
|
||||||
|
* **db manual fixes:** added a way to fix manual db changes as needed ([0b02984](https://git.tuffraid.net/cowch/lst/commits/0b0298423ed75eed6d112a04dda998b8a23b20ea))
|
||||||
|
* **dm:** new endpoint to get the forecast data ([a96b85b](https://git.tuffraid.net/cowch/lst/commits/a96b85bc536809d223dd7a29150d1a4d632e80da))
|
||||||
|
* **forecast data:** added in a historical forecast data set ([c2ae445](https://git.tuffraid.net/cowch/lst/commits/c2ae445ea4d26b047a2ee5d16041ed230f7b2061))
|
||||||
|
* **forklifts:** added backend forklift stuff and frontend companies ([50cde2d](https://git.tuffraid.net/cowch/lst/commits/50cde2d8d2aa24796db1f1c0126ef8c373614d5d))
|
||||||
|
* **forklifts:** added the ability to add new forklifts in ([7b6c9bd](https://git.tuffraid.net/cowch/lst/commits/7b6c9bdfbf2cf9d97c8e23d8ebd6523e32284963))
|
||||||
|
* **forklifts:** added the crud ([577584e](https://git.tuffraid.net/cowch/lst/commits/577584ef4dd10ee7f57ab0ad0d6261adddaf8966))
|
||||||
|
* **form stuff:** added in a searchable dropdown and added to new forklifts ([b23bb0d](https://git.tuffraid.net/cowch/lst/commits/b23bb0db31f78f46ffc556577cadb62e0bfa3b83))
|
||||||
|
* **invoice form:** added new invoice form ([65304f6](https://git.tuffraid.net/cowch/lst/commits/65304f61ceb3ad4655757aa5c291ac4ed77db048))
|
||||||
|
* **invoices:** added invoice + linking to forklift ([2e05f6e](https://git.tuffraid.net/cowch/lst/commits/2e05f6eeee052a92095098c73ace0bd331c43b22))
|
||||||
|
* **leases:** added in leases and move table to reuseable component ([bd7bea8](https://git.tuffraid.net/cowch/lst/commits/bd7bea8db697f5b025b8d93f86677a9a69cdf2b4))
|
||||||
|
* **listeners:** added in a new feature to auto add new listeners ([f9cfada](https://git.tuffraid.net/cowch/lst/commits/f9cfada8409b3a88323dafa80730c5565c067da8))
|
||||||
|
* **materials per day:** more work on materials per day ([564f0b5](https://git.tuffraid.net/cowch/lst/commits/564f0b5addd109018a806edd6a1fed4399ea63aa))
|
||||||
|
* **migration:** settings migration from old app all is now in the new app ([40bc19a](https://git.tuffraid.net/cowch/lst/commits/40bc19aa6f952a7a60b5ee8281fa159ca114161f))
|
||||||
|
* **missing inv:** adding a way to check for missing data in case it dose pull on the correct days ([d17edb1](https://git.tuffraid.net/cowch/lst/commits/d17edb1f9c830a2c17d28bd9180d264607d66fa2))
|
||||||
|
* **mobile:** ota updates added ([b6030de](https://git.tuffraid.net/cowch/lst/commits/b6030de4f44e73ce8bb9152886d384b9d7f2edff))
|
||||||
|
* **notify:** material per day for the next 90 days ([c509c7f](https://git.tuffraid.net/cowch/lst/commits/c509c7fe286a43ab0ffbf86635631477237632b5))
|
||||||
|
* **quality:** added in comments ([566754b](https://git.tuffraid.net/cowch/lst/commits/566754bf2ecfc390bc927b48aadb2fa934353769))
|
||||||
|
* **quality:** added location moved to to the table ([9572b71](https://git.tuffraid.net/cowch/lst/commits/9572b7159235c18617ff46058c94dfd9cfab8abc))
|
||||||
|
* **quality:** priority ranking added ([c777395](https://git.tuffraid.net/cowch/lst/commits/c777395b0350f60bd457c3164ed1ae478249df3a))
|
||||||
|
* **scroll view:** added in a scroll view to for quality so it dose not go over the end of the page ([b0ac326](https://git.tuffraid.net/cowch/lst/commits/b0ac326752331ab01ad981fa7b1022e82beab143))
|
||||||
|
* **servers:** added a link to the server by clicking on the name and the gp code ([00ef72d](https://git.tuffraid.net/cowch/lst/commits/00ef72de90e43c12bd3fecdc08dfa1e3a4f881fb))
|
||||||
|
* **settings:** added in dyco printing settings ([2ed6bf4](https://git.tuffraid.net/cowch/lst/commits/2ed6bf4d1f32f9a92712ccb36d4a4146ca112e85))
|
||||||
|
* **settings:** final migration of settings and edits added ([7e15e5d](https://git.tuffraid.net/cowch/lst/commits/7e15e5d7bcdf58f31bd96564be1f213d01d37cda))
|
||||||
|
* **start of server:** added the start of server data ([d60c08a](https://git.tuffraid.net/cowch/lst/commits/d60c08a281cd63f2183381a1a19c5e196b41fbc5))
|
||||||
|
* **templates:** added bug repot template ([79f4121](https://git.tuffraid.net/cowch/lst/commits/79f4121311df733f5dc59b32a6b32c1b4a32f97b))
|
||||||
|
|
||||||
## [1.7.0](https://git.tuffraid.net/cowch/lst/compare/v1.6.0...v1.7.0) (2025-10-30)
|
## [1.7.0](https://git.tuffraid.net/cowch/lst/compare/v1.6.0...v1.7.0) (2025-10-30)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
meta {
|
||||||
|
name: Error logging
|
||||||
|
type: http
|
||||||
|
seq: 4
|
||||||
|
}
|
||||||
|
|
||||||
|
get {
|
||||||
|
url: {{urlv2}}/api/notify/toomanyerrors
|
||||||
|
body: none
|
||||||
|
auth: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
settings {
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
meta {
|
||||||
|
name: ti Intergration
|
||||||
|
type: http
|
||||||
|
seq: 3
|
||||||
|
}
|
||||||
|
|
||||||
|
get {
|
||||||
|
url: {{urlv2}}/api/notify/tiTrigger
|
||||||
|
body: none
|
||||||
|
auth: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
settings {
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
}
|
||||||
22
LogisticsSupportTool_API_DOCS/LstV2/Warehouse/sscc.bru
Normal file
22
LogisticsSupportTool_API_DOCS/LstV2/Warehouse/sscc.bru
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
meta {
|
||||||
|
name: sscc
|
||||||
|
type: http
|
||||||
|
seq: 4
|
||||||
|
}
|
||||||
|
|
||||||
|
post {
|
||||||
|
url: {{url}}/lst/old/api/logistics/getsscc
|
||||||
|
body: json
|
||||||
|
auth: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
body:json {
|
||||||
|
{
|
||||||
|
"runningNr": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
settings {
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
meta {
|
||||||
|
name: PSI - Forecast data
|
||||||
|
type: http
|
||||||
|
seq: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
get {
|
||||||
|
url: {{url}}/lst/old/api/datamart/psiforecastdata?customer=8
|
||||||
|
body: none
|
||||||
|
auth: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
params:query {
|
||||||
|
customer: 8
|
||||||
|
}
|
||||||
|
|
||||||
|
settings {
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
meta {
|
||||||
|
name: PSI -planning data
|
||||||
|
type: http
|
||||||
|
seq: 2
|
||||||
|
}
|
||||||
|
|
||||||
|
get {
|
||||||
|
url: {{url}}/lst/old/api/datamart/psiplanningdata?avs=118,120&startDate=12/1/2025&endDate=12/31/2026
|
||||||
|
body: none
|
||||||
|
auth: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
params:query {
|
||||||
|
avs: 118,120
|
||||||
|
startDate: 12/1/2025
|
||||||
|
endDate: 12/31/2026
|
||||||
|
}
|
||||||
|
|
||||||
|
settings {
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
}
|
||||||
8
LogisticsSupportTool_API_DOCS/LstV2/datamart/folder.bru
Normal file
8
LogisticsSupportTool_API_DOCS/LstV2/datamart/folder.bru
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
meta {
|
||||||
|
name: datamart
|
||||||
|
seq: 8
|
||||||
|
}
|
||||||
|
|
||||||
|
auth {
|
||||||
|
mode: inherit
|
||||||
|
}
|
||||||
26
LogisticsSupportTool_API_DOCS/LstV2/ocp/Logs.bru
Normal file
26
LogisticsSupportTool_API_DOCS/LstV2/ocp/Logs.bru
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
meta {
|
||||||
|
name: Logs
|
||||||
|
type: http
|
||||||
|
seq: 2
|
||||||
|
}
|
||||||
|
|
||||||
|
get {
|
||||||
|
url: {{url}}/lst/old/api/logger/logs?service=ocp&service=rfid&service=dyco&level=error&level=info&level=warn&hours=12
|
||||||
|
body: none
|
||||||
|
auth: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
params:query {
|
||||||
|
service: ocp
|
||||||
|
service: rfid
|
||||||
|
service: dyco
|
||||||
|
level: error
|
||||||
|
level: info
|
||||||
|
level: warn
|
||||||
|
hours: 12
|
||||||
|
}
|
||||||
|
|
||||||
|
settings {
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
meta {
|
||||||
|
name: Consume
|
||||||
|
type: http
|
||||||
|
seq: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
post {
|
||||||
|
url: {{url}}/lst/old/api/logistics/consume
|
||||||
|
body: json
|
||||||
|
auth: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
body:json {
|
||||||
|
{
|
||||||
|
"lotNum":283559,
|
||||||
|
"runningNr":19302907
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
settings {
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
meta {
|
||||||
|
name: Consume
|
||||||
|
seq: 5
|
||||||
|
}
|
||||||
|
|
||||||
|
auth {
|
||||||
|
mode: inherit
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
meta {
|
||||||
|
name: SSCC
|
||||||
|
type: http
|
||||||
|
seq: 2
|
||||||
|
}
|
||||||
|
|
||||||
|
get {
|
||||||
|
url: {{url}}/lst/api/logistics/getsscc
|
||||||
|
body: none
|
||||||
|
auth: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
settings {
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
}
|
||||||
20
LogisticsSupportTool_API_DOCS/app/system/Update Setting.bru
Normal file
20
LogisticsSupportTool_API_DOCS/app/system/Update Setting.bru
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
meta {
|
||||||
|
name: Update Setting
|
||||||
|
type: http
|
||||||
|
seq: 4
|
||||||
|
}
|
||||||
|
|
||||||
|
post {
|
||||||
|
url: {{url}}/lst/api/system/settings/:token
|
||||||
|
body: none
|
||||||
|
auth: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
params:path {
|
||||||
|
token: test3
|
||||||
|
}
|
||||||
|
|
||||||
|
settings {
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"version": "1",
|
"version": "1",
|
||||||
"name": "LogisticsSupportTool_API_DOCS",
|
"name": "lstv2",
|
||||||
"type": "collection",
|
"type": "collection",
|
||||||
"ignore": [
|
"ignore": [
|
||||||
"node_modules",
|
"node_modules",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
vars {
|
vars {
|
||||||
url: http://localhost:4200
|
url: http://localhost:5500
|
||||||
session_cookie:
|
session_cookie:
|
||||||
urlv2: http://usmcd1vms036:3000
|
urlv2: http://usbow1vms006:3000
|
||||||
jwtV2:
|
jwtV2:
|
||||||
userID:
|
userID:
|
||||||
}
|
}
|
||||||
|
|||||||
24
LogisticsSupportTool_API_DOCS/logistics/bookout.bru
Normal file
24
LogisticsSupportTool_API_DOCS/logistics/bookout.bru
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
meta {
|
||||||
|
name: bookout
|
||||||
|
type: http
|
||||||
|
seq: 2
|
||||||
|
}
|
||||||
|
|
||||||
|
post {
|
||||||
|
url: {{url}}/lst/old/api/logistics/bookout
|
||||||
|
body: json
|
||||||
|
auth: none
|
||||||
|
}
|
||||||
|
|
||||||
|
body:json {
|
||||||
|
{
|
||||||
|
|
||||||
|
"runningNr": "1865027",
|
||||||
|
"reason": "packer printed premature"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
settings {
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
}
|
||||||
8
LogisticsSupportTool_API_DOCS/logistics/folder.bru
Normal file
8
LogisticsSupportTool_API_DOCS/logistics/folder.bru
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
meta {
|
||||||
|
name: logistics
|
||||||
|
seq: 7
|
||||||
|
}
|
||||||
|
|
||||||
|
auth {
|
||||||
|
mode: inherit
|
||||||
|
}
|
||||||
24
LogisticsSupportTool_API_DOCS/logistics/relocate.bru
Normal file
24
LogisticsSupportTool_API_DOCS/logistics/relocate.bru
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
meta {
|
||||||
|
name: relocate
|
||||||
|
type: http
|
||||||
|
seq: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
post {
|
||||||
|
url: {{url}}/lst/old/api/logistics/relocate
|
||||||
|
body: json
|
||||||
|
auth: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
body:json {
|
||||||
|
{
|
||||||
|
|
||||||
|
"runningNr": "56121541",
|
||||||
|
"laneID": "30006"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
settings {
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
}
|
||||||
24
LogisticsSupportTool_API_DOCS/logistics/removeAsWaste.bru
Normal file
24
LogisticsSupportTool_API_DOCS/logistics/removeAsWaste.bru
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
meta {
|
||||||
|
name: removeAsWaste
|
||||||
|
type: http
|
||||||
|
seq: 3
|
||||||
|
}
|
||||||
|
|
||||||
|
post {
|
||||||
|
url: {{url}}/lst/old/api/logistics/removeasreusable
|
||||||
|
body: json
|
||||||
|
auth: none
|
||||||
|
}
|
||||||
|
|
||||||
|
body:json {
|
||||||
|
{
|
||||||
|
|
||||||
|
"runningNr": "1865018",
|
||||||
|
"reason": "validating stockout"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
settings {
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
}
|
||||||
8
LogisticsSupportTool_API_DOCS/v3endpoints/folder.bru
Normal file
8
LogisticsSupportTool_API_DOCS/v3endpoints/folder.bru
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
meta {
|
||||||
|
name: v3endpoints
|
||||||
|
seq: 5
|
||||||
|
}
|
||||||
|
|
||||||
|
auth {
|
||||||
|
mode: inherit
|
||||||
|
}
|
||||||
16
LogisticsSupportTool_API_DOCS/v3endpoints/tester.bru
Normal file
16
LogisticsSupportTool_API_DOCS/v3endpoints/tester.bru
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
meta {
|
||||||
|
name: tester
|
||||||
|
type: http
|
||||||
|
seq: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
post {
|
||||||
|
url: http://localhost:3000/lst/api/system/prodsql/start
|
||||||
|
body: none
|
||||||
|
auth: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
settings {
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
}
|
||||||
33
app/main.ts
33
app/main.ts
@@ -3,16 +3,14 @@ process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
|||||||
import { toNodeHandler } from "better-auth/node";
|
import { toNodeHandler } from "better-auth/node";
|
||||||
import cors from "cors";
|
import cors from "cors";
|
||||||
import express from "express";
|
import express from "express";
|
||||||
import fs from "fs";
|
|
||||||
import { createServer } from "http";
|
import { createServer } from "http";
|
||||||
import { createProxyMiddleware, fixRequestBody } from "http-proxy-middleware";
|
import { createProxyMiddleware } from "http-proxy-middleware";
|
||||||
import morgan from "morgan";
|
import morgan from "morgan";
|
||||||
import os from "os";
|
import os from "os";
|
||||||
import { dirname, join } from "path";
|
import { dirname, join } from "path";
|
||||||
import swaggerJsdoc from "swagger-jsdoc";
|
import swaggerJsdoc from "swagger-jsdoc";
|
||||||
import swaggerUi from "swagger-ui-express";
|
import swaggerUi from "swagger-ui-express";
|
||||||
import { fileURLToPath } from "url";
|
import { fileURLToPath } from "url";
|
||||||
import { userMigrate } from "./src/internal/auth/controller/userMigrate.js";
|
|
||||||
import { schedulerManager } from "./src/internal/logistics/controller/schedulerManager.js";
|
import { schedulerManager } from "./src/internal/logistics/controller/schedulerManager.js";
|
||||||
import { setupMobileRoutes } from "./src/internal/mobile/route.js";
|
import { setupMobileRoutes } from "./src/internal/mobile/route.js";
|
||||||
import { printers } from "./src/internal/ocp/printers/printers.js";
|
import { printers } from "./src/internal/ocp/printers/printers.js";
|
||||||
@@ -23,7 +21,6 @@ import {
|
|||||||
addListeners,
|
addListeners,
|
||||||
manualFixes,
|
manualFixes,
|
||||||
} from "./src/internal/system/utlis/addListeners.js";
|
} from "./src/internal/system/utlis/addListeners.js";
|
||||||
import { swaggerOptions } from "./src/pkg/apiDocs/swaggerOptions.js";
|
|
||||||
import { auth } from "./src/pkg/auth/auth.js";
|
import { auth } from "./src/pkg/auth/auth.js";
|
||||||
import { db } from "./src/pkg/db/db.js";
|
import { db } from "./src/pkg/db/db.js";
|
||||||
import { settings } from "./src/pkg/db/schema/settings.js";
|
import { settings } from "./src/pkg/db/schema/settings.js";
|
||||||
@@ -36,6 +33,9 @@ import { sendNotify } from "./src/pkg/utils/notify.js";
|
|||||||
import { returnFunc } from "./src/pkg/utils/return.js";
|
import { returnFunc } from "./src/pkg/utils/return.js";
|
||||||
import { tryCatch } from "./src/pkg/utils/tryCatch.js";
|
import { tryCatch } from "./src/pkg/utils/tryCatch.js";
|
||||||
import { setupIoServer } from "./src/ws/server.js";
|
import { setupIoServer } from "./src/ws/server.js";
|
||||||
|
import { swaggerConfig, swaggerUiOptions } from "./src/internal/swagger/config.js";
|
||||||
|
import { setupSwagger } from "./src/internal/swagger/swagger.js";
|
||||||
|
|
||||||
|
|
||||||
const main = async () => {
|
const main = async () => {
|
||||||
const env = validateEnv(process.env);
|
const env = validateEnv(process.env);
|
||||||
@@ -77,7 +77,8 @@ const main = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// connect to the prod sql
|
// connect to the prod sql
|
||||||
await initializeProdPool();
|
console.log("Connecting to the sql server");
|
||||||
|
|
||||||
|
|
||||||
// express app
|
// express app
|
||||||
const app = express();
|
const app = express();
|
||||||
@@ -177,13 +178,14 @@ const main = async () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// docs and routes
|
// docs and routes
|
||||||
const openapiSpec: any = swaggerJsdoc(swaggerOptions);
|
// const openapiSpec: any = swaggerJsdoc(swaggerConfig);
|
||||||
app.use(
|
// app.use(
|
||||||
basePath + "/api/docs",
|
// basePath + "/api/docs",
|
||||||
swaggerUi.serve,
|
// swaggerUi.serve,
|
||||||
swaggerUi.setup(openapiSpec),
|
// swaggerUi.setup(openapiSpec, swaggerUiOptions),
|
||||||
);
|
// );
|
||||||
|
initializeProdPool();
|
||||||
|
setupSwagger(app, basePath)
|
||||||
app.use(basePath + "/d", express.static(join(__dirname, "../lstDocs/build")));
|
app.use(basePath + "/d", express.static(join(__dirname, "../lstDocs/build")));
|
||||||
app.use(
|
app.use(
|
||||||
basePath + "/app",
|
basePath + "/app",
|
||||||
@@ -218,11 +220,16 @@ const main = async () => {
|
|||||||
v1Listener();
|
v1Listener();
|
||||||
addListeners();
|
addListeners();
|
||||||
//userMigrate();
|
//userMigrate();
|
||||||
|
|
||||||
// some temp fixes
|
// some temp fixes
|
||||||
|
// above 235 remove these
|
||||||
manualFixes();
|
manualFixes();
|
||||||
|
//settingsMigrate();
|
||||||
}, 5 * 1000);
|
}, 5 * 1000);
|
||||||
|
|
||||||
|
// setTimeout(() => {
|
||||||
|
// startHonoServer();
|
||||||
|
// }, 8 * 1000);
|
||||||
|
|
||||||
// start the server up
|
// start the server up
|
||||||
server.listen(PORT, "0.0.0.0", () =>
|
server.listen(PORT, "0.0.0.0", () =>
|
||||||
log.info(
|
log.info(
|
||||||
|
|||||||
@@ -24,6 +24,13 @@ router.post("/", async (req: Request, res: Response) => {
|
|||||||
.from(user)
|
.from(user)
|
||||||
.where(eq(user.username, validated.username));
|
.where(eq(user.username, validated.username));
|
||||||
|
|
||||||
|
if(userLogin.length === 0 ){
|
||||||
|
return res.status(200).json({
|
||||||
|
success: false,
|
||||||
|
message: `It appears you do not have a user yet please head over to the register page and create a user then try again.`,
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
!userLogin[0].lastLogin ||
|
!userLogin[0].lastLogin ||
|
||||||
differenceInDays(userLogin[0].lastLogin, new Date(Date.now())) > 120
|
differenceInDays(userLogin[0].lastLogin, new Date(Date.now())) > 120
|
||||||
|
|||||||
89
app/src/internal/datamart/routes/getActiveAv.ts
Normal file
89
app/src/internal/datamart/routes/getActiveAv.ts
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
import { Router, type Request, type Response } from "express";
|
||||||
|
import { prodQuery } from "../../../pkg/prodSql/prodQuery.js";
|
||||||
|
import { tryCatch } from "../../../pkg/utils/tryCatch.js";
|
||||||
|
import { db } from "../../../pkg/db/db.js";
|
||||||
|
import { settings } from "../../../pkg/db/schema/settings.js";
|
||||||
|
import { eq } from "drizzle-orm";
|
||||||
|
import { activeArticle } from "../../../pkg/prodSql/querys/datamart/article.js";
|
||||||
|
|
||||||
|
type Articles = {
|
||||||
|
article: string
|
||||||
|
description: string
|
||||||
|
articleType: string
|
||||||
|
pricePoint:string
|
||||||
|
salesPrice:string
|
||||||
|
typeOfMaterial:string
|
||||||
|
articleIdType:string
|
||||||
|
articleWeight:string
|
||||||
|
idAddress:string
|
||||||
|
addressDescription:string
|
||||||
|
addressType:string
|
||||||
|
profitCenter:String
|
||||||
|
fg: string
|
||||||
|
num_of_cycles:string
|
||||||
|
costsCenterId:string
|
||||||
|
costCenterDescription:string
|
||||||
|
customerArticleNumber:string
|
||||||
|
customerArticleDescription:String
|
||||||
|
cycleTime:string
|
||||||
|
salesAgreement:string
|
||||||
|
productFamily:string
|
||||||
|
uom:string
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const router = Router();
|
||||||
|
|
||||||
|
// GET /health
|
||||||
|
router.get("/", async (req: Request, res: Response) => {
|
||||||
|
|
||||||
|
const includePlantToken = req.params.includePlantToken
|
||||||
|
|
||||||
|
let articles:Articles[] = [];
|
||||||
|
try {
|
||||||
|
const res = await prodQuery(activeArticle, "Get active articles");
|
||||||
|
articles = res?.data;
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message:"Error getting articles",
|
||||||
|
error: error
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (includePlantToken) {
|
||||||
|
const { data, error } = await tryCatch(db.select().from(settings).where(eq(settings.name, "plantToken")))
|
||||||
|
if (error) {
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message:"Error getting settings",
|
||||||
|
error: error
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// return articles.map((n) => {
|
||||||
|
// return {
|
||||||
|
// success: true,
|
||||||
|
// message: "Active articles including plant token",
|
||||||
|
// data:{ plantToken: data[0].value, ...n }};
|
||||||
|
// });
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: "Active articles including plant token",
|
||||||
|
data: articles.map((n) => {
|
||||||
|
return { plantToken: data[0].value, ...n }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: "Active articles including plant token",
|
||||||
|
data:articles};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router;
|
||||||
10
app/src/internal/datamart/routes/routes.ts
Normal file
10
app/src/internal/datamart/routes/routes.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import type { Express, Request, Response } from "express";
|
||||||
|
|
||||||
|
//datamart Routes
|
||||||
|
import getActiveAv from './getActiveAv.js'
|
||||||
|
export const setupDataMartRoutes = (app: Express, basePath: string) => {
|
||||||
|
const route = basePath + "/api/datamart"
|
||||||
|
app.use(route + '/activeArticle', getActiveAv);
|
||||||
|
//app.use(basePath + "/api/user/me", requireAuth(), me);
|
||||||
|
|
||||||
|
};
|
||||||
@@ -12,7 +12,6 @@ import { db } from "../../../../pkg/db/db.js";
|
|||||||
import {
|
import {
|
||||||
type ForecastData,
|
type ForecastData,
|
||||||
forecastData,
|
forecastData,
|
||||||
forecastDataSchema,
|
|
||||||
} from "../../../../pkg/db/schema/forecastEDIData.js";
|
} from "../../../../pkg/db/schema/forecastEDIData.js";
|
||||||
import { prodQuery } from "../../../../pkg/prodSql/prodQuery.js";
|
import { prodQuery } from "../../../../pkg/prodSql/prodQuery.js";
|
||||||
import { activeArticle } from "../../../../pkg/prodSql/querys/datamart/article.js";
|
import { activeArticle } from "../../../../pkg/prodSql/querys/datamart/article.js";
|
||||||
@@ -36,19 +35,21 @@ export const forecastEdiData = async (data: ForecastData[]) => {
|
|||||||
for (let i = 0; i < data.length; i++) {
|
for (let i = 0; i < data.length; i++) {
|
||||||
const activeAV = article?.data.filter(
|
const activeAV = article?.data.filter(
|
||||||
(c: any) =>
|
(c: any) =>
|
||||||
c?.CustomerArticleNumber === data[i].customerArticleNo?.toString(),
|
c?.customerArticleNumber === data[i].customerArticleNo?.toString(),
|
||||||
);
|
);
|
||||||
const newData = data[i];
|
const newData = data[i];
|
||||||
//console.log(activeAV[0].IdArtikelvarianten);
|
//console.log(activeAV[0].IdArtikelvarianten);
|
||||||
|
|
||||||
forecaseEDIDATA.push({
|
forecaseEDIDATA.push({
|
||||||
...newData,
|
...newData,
|
||||||
article: activeAV[0].IdArtikelvarianten,
|
article: activeAV.length > 0 ? activeAV[0].article : 0,
|
||||||
|
description:
|
||||||
|
activeAV.length > 0 ? activeAV[0].description : "No Av Created",
|
||||||
requirementDate: new Date(newData.requirementDate),
|
requirementDate: new Date(newData.requirementDate),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(forecaseEDIDATA[0]);
|
//console.log(forecaseEDIDATA[0]);
|
||||||
const { data: f, error: ef } = await tryCatch(
|
const { data: f, error: ef } = await tryCatch(
|
||||||
db.insert(forecastData).values(forecaseEDIDATA),
|
db.insert(forecastData).values(forecaseEDIDATA),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { setupForkliftRoutes } from "../forklifts/routes/routes.js";
|
|||||||
import { setupLogisticsRoutes } from "../logistics/routes.js";
|
import { setupLogisticsRoutes } from "../logistics/routes.js";
|
||||||
import { setupSystemRoutes } from "../system/routes.js";
|
import { setupSystemRoutes } from "../system/routes.js";
|
||||||
import { setupMobileRoutes } from "../mobile/route.js";
|
import { setupMobileRoutes } from "../mobile/route.js";
|
||||||
|
import { setupDataMartRoutes } from "../datamart/routes/routes.js";
|
||||||
|
|
||||||
export const setupRoutes = (app: Express, basePath: string) => {
|
export const setupRoutes = (app: Express, basePath: string) => {
|
||||||
// all routes
|
// all routes
|
||||||
@@ -14,6 +15,7 @@ export const setupRoutes = (app: Express, basePath: string) => {
|
|||||||
setupLogisticsRoutes(app, basePath);
|
setupLogisticsRoutes(app, basePath);
|
||||||
setupForkliftRoutes(app, basePath);
|
setupForkliftRoutes(app, basePath);
|
||||||
setupMobileRoutes(app, basePath);
|
setupMobileRoutes(app, basePath);
|
||||||
|
setupDataMartRoutes(app, basePath)
|
||||||
|
|
||||||
// always try to go to the app weather we are in dev or in production.
|
// always try to go to the app weather we are in dev or in production.
|
||||||
app.get(basePath + "/", (req: Request, res: Response) => {
|
app.get(basePath + "/", (req: Request, res: Response) => {
|
||||||
|
|||||||
59
app/src/internal/swagger/config.ts
Normal file
59
app/src/internal/swagger/config.ts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
export const swaggerUiOptions = {
|
||||||
|
explorer: true,
|
||||||
|
customCss: ".swagger-ui .topbar { display: none }",
|
||||||
|
customSiteTitle: "LST API Documentation",
|
||||||
|
swaggerOptions: {
|
||||||
|
persistAuthorization: true,
|
||||||
|
displayRequestDuration: true,
|
||||||
|
filter: true,
|
||||||
|
syntaxHighlight: {
|
||||||
|
activate: true,
|
||||||
|
theme: "monokai",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const swaggerConfig = {
|
||||||
|
definition: {
|
||||||
|
openapi: "3.0.0",
|
||||||
|
info: {
|
||||||
|
title: "Logistics Support Tool",
|
||||||
|
version: "1.8.0",
|
||||||
|
description: "Complete API documentation for lst",
|
||||||
|
contact: {
|
||||||
|
name: "API Support",
|
||||||
|
email: "blake.matthes@alpla.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
servers: [
|
||||||
|
{
|
||||||
|
url: "http://localhost:4200",
|
||||||
|
description: "Development server",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: "https://api.yourapp.com",
|
||||||
|
description: "Production server",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
components: {
|
||||||
|
securitySchemes: {
|
||||||
|
bearerAuth: {
|
||||||
|
type: "http",
|
||||||
|
scheme: "bearer",
|
||||||
|
bearerFormat: "JWT",
|
||||||
|
},
|
||||||
|
apiKey: {
|
||||||
|
type: "apiKey",
|
||||||
|
in: "header",
|
||||||
|
name: "X-API-Key",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
apis: [], // We'll populate this dynamically
|
||||||
|
};
|
||||||
129
app/src/internal/swagger/endpoints/auth/login.ts
Normal file
129
app/src/internal/swagger/endpoints/auth/login.ts
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
const loginEndpoint = {
|
||||||
|
'/lst/api/user/login': {
|
||||||
|
post: {
|
||||||
|
tags: ['Authentication'],
|
||||||
|
summary: 'Login to get a token',
|
||||||
|
description: 'User enters username and password, gets back a JWT token and session data',
|
||||||
|
|
||||||
|
// What the user sends you
|
||||||
|
requestBody: {
|
||||||
|
required: true,
|
||||||
|
content: {
|
||||||
|
'application/json': {
|
||||||
|
schema: {
|
||||||
|
type: 'object',
|
||||||
|
required: ['username', 'password'],
|
||||||
|
properties: {
|
||||||
|
username: {
|
||||||
|
type: 'string',
|
||||||
|
example: 'smith01'
|
||||||
|
},
|
||||||
|
password: {
|
||||||
|
type: 'string',
|
||||||
|
example: 'MyPassword123'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// What you send back to the user
|
||||||
|
responses: {
|
||||||
|
// SUCCESS - Login worked
|
||||||
|
200: {
|
||||||
|
description: 'Login successful',
|
||||||
|
content: {
|
||||||
|
'application/json': {
|
||||||
|
schema: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
success: {
|
||||||
|
type: 'boolean',
|
||||||
|
example: true
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
type: 'string',
|
||||||
|
example: 'Login successful'
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
token: {
|
||||||
|
type: 'string',
|
||||||
|
example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: 'string',
|
||||||
|
example: '12345'
|
||||||
|
},
|
||||||
|
email: {
|
||||||
|
type: 'string',
|
||||||
|
example: 'user@example.com'
|
||||||
|
},
|
||||||
|
username: {
|
||||||
|
type: 'string',
|
||||||
|
example: 'johndoe'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// ERROR - Wrong password or email
|
||||||
|
401: {
|
||||||
|
description: 'Wrong email or password',
|
||||||
|
content: {
|
||||||
|
'application/json': {
|
||||||
|
schema: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
success: {
|
||||||
|
type: 'boolean',
|
||||||
|
example: false
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
type: 'string',
|
||||||
|
example: 'Invalid credentials'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// ERROR - Missing fields
|
||||||
|
400: {
|
||||||
|
description: 'Missing email or password',
|
||||||
|
content: {
|
||||||
|
'application/json': {
|
||||||
|
schema: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
success: {
|
||||||
|
type: 'boolean',
|
||||||
|
example: false
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
type: 'string',
|
||||||
|
example: 'Email and password are required'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default loginEndpoint;
|
||||||
0
app/src/internal/swagger/schemas/auth.schema.ts
Normal file
0
app/src/internal/swagger/schemas/auth.schema.ts
Normal file
0
app/src/internal/swagger/schemas/common.schema.ts
Normal file
0
app/src/internal/swagger/schemas/common.schema.ts
Normal file
31
app/src/internal/swagger/swagger.ts
Normal file
31
app/src/internal/swagger/swagger.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import swaggerJsdoc from 'swagger-jsdoc';
|
||||||
|
import swaggerUi from 'swagger-ui-express';
|
||||||
|
import { swaggerConfig, swaggerUiOptions } from './config.js';
|
||||||
|
import { type Express } from 'express';
|
||||||
|
|
||||||
|
import loginEndpoint from './endpoints/auth/login.js';
|
||||||
|
|
||||||
|
const allPaths = {
|
||||||
|
...loginEndpoint,
|
||||||
|
// When you add more endpoints, add them here:
|
||||||
|
// ...registerEndpoint,
|
||||||
|
// ...logoutEndpoint,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const swaggerSpec = {
|
||||||
|
...swaggerConfig.definition,
|
||||||
|
paths: allPaths
|
||||||
|
};
|
||||||
|
|
||||||
|
const specs = swaggerJsdoc({
|
||||||
|
...swaggerConfig,
|
||||||
|
definition: swaggerSpec
|
||||||
|
});
|
||||||
|
|
||||||
|
export function setupSwagger(app: Express, basePath: string): void {
|
||||||
|
// Swagger UI at /api-docs
|
||||||
|
app.use(basePath + "/api/docs", swaggerUi.serve, swaggerUi.setup(specs, swaggerUiOptions));
|
||||||
|
|
||||||
|
//console.log('📚 Swagger docs at http://localhost:3000/api-docs');
|
||||||
|
}
|
||||||
@@ -5,66 +5,31 @@ import { Router } from "express";
|
|||||||
import https from "https";
|
import https from "https";
|
||||||
import { db } from "../../../../pkg/db/db.js";
|
import { db } from "../../../../pkg/db/db.js";
|
||||||
import { serverData } from "../../../../pkg/db/schema/servers.js";
|
import { serverData } from "../../../../pkg/db/schema/servers.js";
|
||||||
|
import { settings } from "../../../../pkg/db/schema/settings.js";
|
||||||
import { createLogger } from "../../../../pkg/logger/logger.js";
|
import { createLogger } from "../../../../pkg/logger/logger.js";
|
||||||
import { tryCatch } from "../../../../pkg/utils/tryCatch.js";
|
import { tryCatch } from "../../../../pkg/utils/tryCatch.js";
|
||||||
|
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
router.patch("/:token", async (req: Request, res: Response) => {
|
router.patch("/:id", async (req: Request, res: Response) => {
|
||||||
const log = createLogger({ module: "admin", subModule: "update server" });
|
const log = createLogger({ module: "admin", subModule: "update setting" });
|
||||||
|
|
||||||
// when a server is updated and is posted from localhost or 127.0.0.1 we also want to post it to the test server so we can see it from there, we want to insert with update on conflict.
|
// when a server is updated and is posted from localhost or 127.0.0.1 we also want to post it to the test server so we can see it from there, we want to insert with update on conflict.
|
||||||
const token = req.params.token;
|
const id = req.params.id;
|
||||||
const updates: Record<string, any> = {};
|
const updates: Record<string, any> = {};
|
||||||
|
|
||||||
if (req.body?.name !== undefined) {
|
if (req.body?.name !== undefined) {
|
||||||
updates.name = req.body.name;
|
updates.name = req.body.name;
|
||||||
}
|
}
|
||||||
if (req.body?.serverDNS !== undefined) {
|
if (req.body?.value !== undefined) {
|
||||||
updates.serverDNS = req.body.serverDNS;
|
updates.value = req.body.value;
|
||||||
}
|
}
|
||||||
if (req.body?.ipAddress !== undefined) {
|
if (req.body?.description !== undefined) {
|
||||||
updates.ipAddress = req.body.ipAddress;
|
updates.description = req.body.description;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.body?.greatPlainsPlantCode !== undefined) {
|
if (req.body?.moduleName !== undefined) {
|
||||||
updates.greatPlainsPlantCode = req.body.greatPlainsPlantCode;
|
updates.moduleName = req.body.moduleName;
|
||||||
}
|
|
||||||
|
|
||||||
if (req.body?.lstServerPort !== undefined) {
|
|
||||||
updates.lstServerPort = req.body.lstServerPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (req.body?.serverLoc !== undefined) {
|
|
||||||
updates.serverLoc = req.body.serverLoc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (req.body?.streetAddress !== undefined) {
|
|
||||||
updates.streetAddress = req.body.streetAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (req.body?.cityState !== undefined) {
|
|
||||||
updates.cityState = req.body.cityState;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (req.body?.zipcode !== undefined) {
|
|
||||||
updates.zipcode = req.body.zipcode;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (req.body?.contactEmail !== undefined) {
|
|
||||||
updates.contactEmail = req.body.contactEmail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (req.body?.contactPhone !== undefined) {
|
|
||||||
updates.contactPhone = req.body.contactPhone;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (req.body?.customerTiAcc !== undefined) {
|
|
||||||
updates.customerTiAcc = req.body.customerTiAcc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (req.body?.active !== undefined) {
|
|
||||||
updates.active = req.body.active;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updates.upd_user = req.user!.username || "lst_user";
|
updates.upd_user = req.user!.username || "lst_user";
|
||||||
@@ -73,65 +38,12 @@ router.patch("/:token", async (req: Request, res: Response) => {
|
|||||||
try {
|
try {
|
||||||
if (Object.keys(updates).length > 0) {
|
if (Object.keys(updates).length > 0) {
|
||||||
await db
|
await db
|
||||||
.update(serverData)
|
.update(settings)
|
||||||
.set(updates)
|
.set(updates)
|
||||||
.where(eq(serverData.plantToken, token));
|
.where(eq(settings.settings_id, id));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.hostname === "localhost" && process.env.MAIN_SERVER) {
|
res.status(200).json({ message: `Setting was just updated` });
|
||||||
log.info({}, "Running in dev server about to add in a new server");
|
|
||||||
const axiosInstance = axios.create({
|
|
||||||
httpsAgent: new https.Agent({ rejectUnauthorized: false }),
|
|
||||||
baseURL: process.env.MAIN_SERVER,
|
|
||||||
withCredentials: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
const loginRes = (await axiosInstance.post(
|
|
||||||
`${process.env.MAIN_SERVER}/lst/api/auth/sign-in/username`,
|
|
||||||
{
|
|
||||||
username: process.env.MAIN_SERVER_USERNAME,
|
|
||||||
password: process.env.MAIN_SERVER_PASSWORD,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
headers: { "Content-Type": "application/json" },
|
|
||||||
},
|
|
||||||
)) as any;
|
|
||||||
|
|
||||||
const setCookie = loginRes?.headers["set-cookie"][0];
|
|
||||||
|
|
||||||
//console.log(setCookie.split(";")[0].replace("__Secure-", ""));
|
|
||||||
|
|
||||||
if (!setCookie) {
|
|
||||||
throw new Error("Did not receive a Set-Cookie header from login");
|
|
||||||
}
|
|
||||||
|
|
||||||
const { data, error } = await tryCatch(
|
|
||||||
axios.patch(
|
|
||||||
`${process.env.MAIN_SERVER}/lst/api/admin/server/${token}`,
|
|
||||||
updates,
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
Cookie: setCookie.split(";")[0],
|
|
||||||
},
|
|
||||||
withCredentials: true,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
console.log(error);
|
|
||||||
log.error(
|
|
||||||
{ stack: error },
|
|
||||||
"There was an error adding the server to Main Server",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
log.info(
|
|
||||||
{ stack: data?.data },
|
|
||||||
"A new Server was just added to the server.",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
res.status(200).json({ message: `${token} Server was just updated` });
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
res.status(400).json({ message: "Error Server updated", error });
|
res.status(400).json({ message: "Error Server updated", error });
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ router.get("/", async (req, res) => {
|
|||||||
memoryUsage: `Heap: ${(used.heapUsed / 1024 / 1024).toFixed(2)} MB / RSS: ${(
|
memoryUsage: `Heap: ${(used.heapUsed / 1024 / 1024).toFixed(2)} MB / RSS: ${(
|
||||||
used.rss / 1024 / 1024
|
used.rss / 1024 / 1024
|
||||||
).toFixed(2)} MB`,
|
).toFixed(2)} MB`,
|
||||||
|
eomFGPkgSheetVersion: 1, // this is the excel file version when we have a change to the macro we want to grab this
|
||||||
|
masterMacroFile: 1, // this is the excel file version when we have a change to the macro we want to grab this
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
import { Client } from "pg";
|
import { Client } from "pg";
|
||||||
|
import { db } from "../../../pkg/db/db.js";
|
||||||
|
import { type NewSetting, settings } from "../../../pkg/db/schema/settings.js";
|
||||||
import { createLogger } from "../../../pkg/logger/logger.js";
|
import { createLogger } from "../../../pkg/logger/logger.js";
|
||||||
|
import { tryCatch } from "../../../pkg/utils/tryCatch.js";
|
||||||
|
|
||||||
export const addListeners = async () => {
|
export const addListeners = async () => {
|
||||||
const log = createLogger({ module: "utils", subModule: "listeners" });
|
const log = createLogger({ module: "utils", subModule: "listeners" });
|
||||||
@@ -60,9 +63,8 @@ export const addListeners = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// all the migration stuff that will need to be moved later build 230 and above will need to remove
|
||||||
export const manualFixes = async () => {
|
export const manualFixes = async () => {
|
||||||
const fixQuery = `ALTER TABLE "serverData" ADD CONSTRAINT "serverData_name_unique" UNIQUE("name");`;
|
|
||||||
|
|
||||||
const log = createLogger({ module: "utils", subModule: "manual fixes" });
|
const log = createLogger({ module: "utils", subModule: "manual fixes" });
|
||||||
const client = new Client({
|
const client = new Client({
|
||||||
connectionString: `postgresql://${process.env.DATABASE_USER}:${process.env.DATABASE_PASSWORD}@${process.env.DATABASE_HOST}:${process.env.DATABASE_PORT}/${process.env.DATABASE_DB}`,
|
connectionString: `postgresql://${process.env.DATABASE_USER}:${process.env.DATABASE_PASSWORD}@${process.env.DATABASE_HOST}:${process.env.DATABASE_PORT}/${process.env.DATABASE_DB}`,
|
||||||
@@ -70,10 +72,59 @@ export const manualFixes = async () => {
|
|||||||
|
|
||||||
await client.connect();
|
await client.connect();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The fix to correct the constraint on the server data
|
||||||
|
*/
|
||||||
|
// const fixQuery = `ALTER TABLE "serverData" ADD CONSTRAINT "serverData_name_unique" UNIQUE("name");`;
|
||||||
|
// try {
|
||||||
|
// log.info({}, "Running the manual fix");
|
||||||
|
// await client.query(fixQuery);
|
||||||
|
// } catch (e) {
|
||||||
|
// log.info({ error: e }, "Fix was not completed");
|
||||||
|
// }
|
||||||
|
};
|
||||||
|
|
||||||
|
export const settingsMigrate = async () => {
|
||||||
|
const log = createLogger({ module: "utils", subModule: "v1Migration" });
|
||||||
|
const client = new Client({
|
||||||
|
connectionString: process.env.DATABASE_URL_V1,
|
||||||
|
});
|
||||||
|
|
||||||
|
await client.connect();
|
||||||
|
|
||||||
|
let settingsV1: NewSetting[] = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
log.info({}, "Running the manual fix");
|
log.info({}, "Running the manual fix");
|
||||||
await client.query(fixQuery);
|
const s = await client.query("SELECT * FROM settings");
|
||||||
|
|
||||||
|
settingsV1 = s.rows.map((i) => {
|
||||||
|
return {
|
||||||
|
name: i.name,
|
||||||
|
value: i.value,
|
||||||
|
description: i.description,
|
||||||
|
moduleName: i.moduleName,
|
||||||
|
};
|
||||||
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.info({ error: e }, "Fix was not completed");
|
log.error({ error: e }, "There was an error getting the settings.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data, error } = await tryCatch(
|
||||||
|
db
|
||||||
|
.insert(settings)
|
||||||
|
.values(settingsV1)
|
||||||
|
.onConflictDoNothing()
|
||||||
|
.returning({ name: settings.name }),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
log.error({ error }, "There was an error adding new settings");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
log.info({ newSettingsAdded: data }, "New settings added");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// migrations after 230 go below here so we can keep this inline.
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
export const swaggerOptions = {
|
|
||||||
definition: {
|
|
||||||
openapi: "3.0.0",
|
|
||||||
info: {
|
|
||||||
title: "Logistics Support Tool",
|
|
||||||
version: "1.0.0",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// globs where swagger-jsdoc should look for annotations:
|
|
||||||
apis: ["../../src/**/*.ts"],
|
|
||||||
};
|
|
||||||
@@ -18,6 +18,7 @@ export const forecastData = pgTable("forecast_Data", {
|
|||||||
quantity: real("quantity"),
|
quantity: real("quantity"),
|
||||||
requirementDate: timestamp("requirement_date").notNull(),
|
requirementDate: timestamp("requirement_date").notNull(),
|
||||||
article: integer("article"),
|
article: integer("article"),
|
||||||
|
description: text("description"),
|
||||||
createdAt: timestamp("created_at").defaultNow(),
|
createdAt: timestamp("created_at").defaultNow(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
import { returnFunc } from "../utils/return.js";
|
|
||||||
import { connected, pool } from "./prodSqlConnect.js";
|
|
||||||
import { validateEnv } from "../utils/envValidator.js";
|
import { validateEnv } from "../utils/envValidator.js";
|
||||||
|
import { returnFunc } from "../utils/return.js";
|
||||||
|
import {
|
||||||
|
closePool,
|
||||||
|
connected,
|
||||||
|
pool,
|
||||||
|
reconnecting,
|
||||||
|
reconnectToSql,
|
||||||
|
} from "./prodSqlConnect.js";
|
||||||
|
|
||||||
const env = validateEnv(process.env);
|
const env = validateEnv(process.env);
|
||||||
/**
|
/**
|
||||||
@@ -11,48 +17,65 @@ const env = validateEnv(process.env);
|
|||||||
* You must use test1 always as it will be changed via query
|
* You must use test1 always as it will be changed via query
|
||||||
*/
|
*/
|
||||||
export async function prodQuery(queryToRun: string, name: string) {
|
export async function prodQuery(queryToRun: string, name: string) {
|
||||||
if (!connected) {
|
if (!connected) {
|
||||||
return returnFunc({
|
reconnectToSql();
|
||||||
success: false,
|
|
||||||
module: "prodSql",
|
|
||||||
subModule: "query",
|
|
||||||
level: "error",
|
|
||||||
message: `The sql ${env.PROD_PLANT_TOKEN} is not connected`,
|
|
||||||
notify: false,
|
|
||||||
data: [],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const query = queryToRun.replaceAll("test1", env.PROD_PLANT_TOKEN);
|
|
||||||
try {
|
|
||||||
const result = await pool.request().query(query);
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
message: `Query results for: ${name}`,
|
|
||||||
data: result.recordset,
|
|
||||||
};
|
|
||||||
} catch (error: any) {
|
|
||||||
console.log(error);
|
|
||||||
if (error.code === "ETIMEOUT") {
|
|
||||||
return returnFunc({
|
|
||||||
success: false,
|
|
||||||
module: "prodSql",
|
|
||||||
subModule: "query",
|
|
||||||
level: "error",
|
|
||||||
message: `${name} did not run due to a timeout.`,
|
|
||||||
notify: false,
|
|
||||||
data: [error],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error.code === "EREQUEST") {
|
if (reconnecting) {
|
||||||
return returnFunc({
|
return returnFunc({
|
||||||
success: false,
|
success: false,
|
||||||
module: "prodSql",
|
module: "prodSql",
|
||||||
subModule: "query",
|
subModule: "query",
|
||||||
level: "error",
|
level: "error",
|
||||||
message: `${name} encountered an error ${error.originalError.info.message}`,
|
message: `The sql ${env.PROD_PLANT_TOKEN} is trying to reconnect already`,
|
||||||
data: [],
|
notify: false,
|
||||||
});
|
data: [],
|
||||||
}
|
});
|
||||||
}
|
} else {
|
||||||
|
return returnFunc({
|
||||||
|
success: false,
|
||||||
|
module: "prodSql",
|
||||||
|
subModule: "query",
|
||||||
|
level: "error",
|
||||||
|
message: `The sql ${env.PROD_PLANT_TOKEN} is not connected`,
|
||||||
|
notify: false,
|
||||||
|
data: [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const query = queryToRun.replaceAll("test1", env.PROD_PLANT_TOKEN);
|
||||||
|
try {
|
||||||
|
const result = await pool.request().query(query);
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: `Query results for: ${name}`,
|
||||||
|
data: result.recordset,
|
||||||
|
};
|
||||||
|
} catch (error: any) {
|
||||||
|
console.log(error);
|
||||||
|
if (error.code === "ETIMEOUT") {
|
||||||
|
closePool();
|
||||||
|
return returnFunc({
|
||||||
|
success: false,
|
||||||
|
module: "prodSql",
|
||||||
|
subModule: "query",
|
||||||
|
level: "error",
|
||||||
|
message: `${name} did not run due to a timeout.`,
|
||||||
|
notify: false,
|
||||||
|
data: [error],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error.code === "EREQUEST") {
|
||||||
|
closePool();
|
||||||
|
return returnFunc({
|
||||||
|
success: false,
|
||||||
|
module: "prodSql",
|
||||||
|
subModule: "query",
|
||||||
|
level: "error",
|
||||||
|
message: `${name} encountered an error ${error.originalError.info.message}`,
|
||||||
|
data: [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,136 +1,134 @@
|
|||||||
import sql from "mssql";
|
import sql from "mssql";
|
||||||
import { checkHostnamePort } from "../utils/checkHostNamePort.js";
|
|
||||||
import { sqlConfig } from "./prodSqlConfig.js";
|
|
||||||
import { createLogger } from "../logger/logger.js";
|
import { createLogger } from "../logger/logger.js";
|
||||||
import { returnFunc } from "../utils/return.js";
|
import { checkHostnamePort } from "../utils/checkHostNamePort.js";
|
||||||
import { validateEnv } from "../utils/envValidator.js";
|
import { validateEnv } from "../utils/envValidator.js";
|
||||||
|
import { returnFunc } from "../utils/return.js";
|
||||||
|
import { sqlConfig } from "./prodSqlConfig.js";
|
||||||
|
|
||||||
const env = validateEnv(process.env);
|
const env = validateEnv(process.env);
|
||||||
|
|
||||||
export let pool: any;
|
export let pool: any;
|
||||||
export let connected: boolean = false;
|
export let connected: boolean = false;
|
||||||
let reconnecting = false;
|
export let reconnecting = false;
|
||||||
|
|
||||||
export const initializeProdPool = async () => {
|
export const initializeProdPool = async () => {
|
||||||
const log = createLogger({ module: "prodSql" });
|
const log = createLogger({ module: "prodSql" });
|
||||||
|
|
||||||
const serverUp = await checkHostnamePort(`${env.PROD_SERVER}:1433`);
|
const serverUp = await checkHostnamePort(`${env.PROD_SERVER}:1433`);
|
||||||
|
|
||||||
if (!serverUp) {
|
if (!serverUp) {
|
||||||
reconnectToSql();
|
reconnectToSql();
|
||||||
return returnFunc({
|
return returnFunc({
|
||||||
success: false,
|
success: false,
|
||||||
module: "prodSql",
|
module: "prodSql",
|
||||||
level: "fatal",
|
level: "fatal",
|
||||||
message: `The sql ${env.PROD_SERVER} is not reachable`,
|
message: `The sql ${env.PROD_SERVER} is not reachable`,
|
||||||
data: [],
|
data: [],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// if you were restarting from the endpoint you get this lovely error
|
// if you were restarting from the endpoint you get this lovely error
|
||||||
if (connected) {
|
if (connected) {
|
||||||
return returnFunc({
|
return returnFunc({
|
||||||
success: false,
|
success: false,
|
||||||
module: "prodSql",
|
module: "prodSql",
|
||||||
level: "error",
|
level: "error",
|
||||||
message: `There is already a connection to ${env.PROD_PLANT_TOKEN}`,
|
message: `There is already a connection to ${env.PROD_PLANT_TOKEN}`,
|
||||||
data: [],
|
data: [],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
pool = await sql.connect(sqlConfig);
|
pool = await sql.connect(sqlConfig);
|
||||||
|
|
||||||
log.info(
|
log.info(
|
||||||
`Connected to ${sqlConfig?.server}, using DB: ${sqlConfig?.database}`
|
`Connected to ${sqlConfig?.server}, using DB: ${sqlConfig?.database}`,
|
||||||
);
|
);
|
||||||
connected = true;
|
connected = true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.fatal(
|
log.fatal(
|
||||||
`${JSON.stringify(
|
`${JSON.stringify(error)}, "There was an error connecting to the pool."`,
|
||||||
error
|
);
|
||||||
)}, "There was an error connecting to the pool."`
|
reconnectToSql();
|
||||||
);
|
// throw new Error("There was an error closing the sql connection");
|
||||||
reconnectToSql();
|
}
|
||||||
// throw new Error("There was an error closing the sql connection");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const reconnectToSql = async () => {
|
export const reconnectToSql = async () => {
|
||||||
const log = createLogger({ module: "prodSql" });
|
const log = createLogger({ module: "prodSql" });
|
||||||
if (reconnecting) return;
|
if (reconnecting) return;
|
||||||
reconnecting = true;
|
reconnecting = true;
|
||||||
|
|
||||||
let delay = 2000; // start at 2s
|
let delay = 2000; // start at 2s
|
||||||
let attempts = 0;
|
let attempts = 0;
|
||||||
const maxAttempts = 10; // or limit by time, e.g. 2 min total
|
const maxAttempts = 10; // or limit by time, e.g. 2 min total
|
||||||
|
|
||||||
while (!connected && attempts < maxAttempts) {
|
while (!connected && attempts < maxAttempts) {
|
||||||
attempts++;
|
attempts++;
|
||||||
log.info(
|
log.info(
|
||||||
`Reconnect attempt ${attempts}/${maxAttempts} in ${
|
`Reconnect attempt ${attempts}/${maxAttempts} in ${delay / 1000}s...`,
|
||||||
delay / 1000
|
);
|
||||||
}s...`
|
|
||||||
);
|
|
||||||
|
|
||||||
await new Promise((res) => setTimeout(res, delay));
|
await new Promise((res) => setTimeout(res, delay));
|
||||||
|
|
||||||
const serverUp = await checkHostnamePort(`${env.PROD_SERVER}:1433`);
|
const serverUp = await checkHostnamePort(`${env.PROD_SERVER}:1433`);
|
||||||
|
|
||||||
if (!serverUp) {
|
if (!serverUp) {
|
||||||
delay = Math.min(delay * 2, 30000); // exponential backoff up to 30s
|
delay = Math.min(delay * 2, 30000); // exponential backoff up to 30s
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
pool = sql.connect(sqlConfig);
|
pool = sql.connect(sqlConfig);
|
||||||
|
|
||||||
log.info(
|
log.info(
|
||||||
`Connected to ${sqlConfig?.server}, and looking at ${sqlConfig?.database}`
|
`Connected to ${sqlConfig?.server}, and looking at ${sqlConfig?.database}`,
|
||||||
);
|
);
|
||||||
reconnecting = false;
|
reconnecting = false;
|
||||||
connected = true;
|
connected = true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.fatal(
|
log.fatal(
|
||||||
`${JSON.stringify(
|
`${JSON.stringify(
|
||||||
error
|
error,
|
||||||
)}, "There was an error connecting to the pool."`
|
)}, "There was an error connecting to the pool."`,
|
||||||
);
|
);
|
||||||
delay = Math.min(delay * 2, 30000); // exponential backoff up to 30s
|
delay = Math.min(delay * 2, 30000); // exponential backoff up to 30s
|
||||||
// throw new Error("There was an error closing the sql connection");
|
// throw new Error("There was an error closing the sql connection");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!connected) {
|
if (!connected) {
|
||||||
log.fatal(
|
log.fatal(
|
||||||
{ notify: true },
|
{ notify: true },
|
||||||
"Max reconnect attempts reached on the prodSql server. Stopping retries."
|
"Max reconnect attempts reached on the prodSql server. Stopping retries.",
|
||||||
);
|
);
|
||||||
reconnecting = false;
|
reconnecting = false;
|
||||||
// optional: exit process or alert someone here
|
// exit process or alert someone here
|
||||||
// process.exit(1);
|
// process.exit(1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const closePool = async () => {
|
export const closePool = async () => {
|
||||||
const log = createLogger({ module: "prodSql" });
|
const log = createLogger({ module: "prodSql" });
|
||||||
if (!connected) {
|
if (!connected) {
|
||||||
log.error("There is no connection a connection.");
|
log.error("There is no connection a connection.");
|
||||||
return { success: false, message: "There is already a connection." };
|
return { success: false, message: "There is already a connection." };
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await pool.close();
|
await pool.close();
|
||||||
log.info("Connection pool closed");
|
log.info("Connection pool closed");
|
||||||
connected = false;
|
connected = false;
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
message: "The sql server connection has been closed",
|
message: "The sql server connection has been closed",
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.fatal(
|
connected = false;
|
||||||
{ notify: true },
|
log.info(
|
||||||
`${JSON.stringify(
|
//{ notify: true },
|
||||||
error
|
{ error: error },
|
||||||
)}, "There was an error closing the sql connection"`
|
`${JSON.stringify(
|
||||||
);
|
error,
|
||||||
}
|
)}, "There was an error closing the sql connection"`,
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
export const activeArticle = `
|
export const activeArticle = `
|
||||||
use AlplaPROD_test1
|
use AlplaPROD_test1
|
||||||
|
|
||||||
SELECT V_Artikel.IdArtikelvarianten,
|
SELECT V_Artikel.IdArtikelvarianten as article,
|
||||||
V_Artikel.Bezeichnung,
|
V_Artikel.Bezeichnung as description,
|
||||||
V_Artikel.ArtikelvariantenTypBez,
|
V_Artikel.ArtikelvariantenTypBez as articleType,
|
||||||
V_Artikel.PreisEinheitBez,
|
V_Artikel.PreisEinheitBez as pricePoint,
|
||||||
case when sales.price is null then 0 else sales.price end as salesPrice,
|
case when sales.price is null then 0 else sales.price end as salesPrice,
|
||||||
TypeOfMaterial=CASE
|
CASE
|
||||||
WHEN
|
WHEN
|
||||||
V_Artikel.ArtikelvariantenTypBez LIKE'%Additive'
|
V_Artikel.ArtikelvariantenTypBez LIKE'%Additive'
|
||||||
Then 'AD'
|
Then 'AD'
|
||||||
@@ -90,14 +90,15 @@ THEN 'Caps'
|
|||||||
When
|
When
|
||||||
V_Artikel.ArtikelvariantenTypBez = 'Dummy'
|
V_Artikel.ArtikelvariantenTypBez = 'Dummy'
|
||||||
THEN 'Not used'
|
THEN 'Not used'
|
||||||
ELSE 'Item not defined' END
|
ELSE 'Item not defined' END as typeOfMaterial
|
||||||
,V_Artikel.IdArtikelvariantenTyp,
|
|
||||||
Round(V_Artikel.ArtikelGewicht, 3) as Article_Weight,
|
,V_Artikel.IdArtikelvariantenTyp as articleIdType,
|
||||||
IdAdresse,
|
Round(V_Artikel.ArtikelGewicht, 3) as articleWeight,
|
||||||
AdressBez,
|
IdAdresse as idAddress,
|
||||||
AdressTypBez,
|
AdressBez as addressDescription,
|
||||||
ProdBereichBez,
|
AdressTypBez as addressType,
|
||||||
FG=case when
|
ProdBereichBez as profitCenter,
|
||||||
|
case when
|
||||||
V_Artikel.ProdBereichBez = 'SBM' or
|
V_Artikel.ProdBereichBez = 'SBM' or
|
||||||
V_Artikel.ProdBereichBez = 'IM-Caps' or
|
V_Artikel.ProdBereichBez = 'IM-Caps' or
|
||||||
V_Artikel.ProdBereichBez = 'IM-PET' or
|
V_Artikel.ProdBereichBez = 'IM-PET' or
|
||||||
@@ -107,15 +108,16 @@ V_Artikel.ProdBereichBez = 'ISBM' or
|
|||||||
V_Artikel.ProdBereichBez = 'IM-Finishing'
|
V_Artikel.ProdBereichBez = 'IM-Finishing'
|
||||||
Then 'FG'
|
Then 'FG'
|
||||||
Else 'not Defined Profit Center'
|
Else 'not Defined Profit Center'
|
||||||
end,
|
end as fg,
|
||||||
|
|
||||||
V_Artikel.Umlaeufe as num_of_cycles,
|
V_Artikel.Umlaeufe as num_of_cycles,
|
||||||
V_FibuKonten_BASIS.FibuKontoNr as CostsCenterId,
|
V_FibuKonten_BASIS.FibuKontoNr as costsCenterId,
|
||||||
V_FibuKonten_BASIS.Bezeichnung as CostCenterDescription,
|
V_FibuKonten_BASIS.Bezeichnung as costCenterDescription,
|
||||||
sales.[KdArtNr] as CustomerArticleNumber,
|
sales.[KdArtNr] as customerArticleNumber,
|
||||||
sales.[KdArtBez] as CustomerArticleDescription,
|
sales.[KdArtBez] as customerArticleDescription,
|
||||||
round(V_Artikel.Zyklus, 2) as CycleTime,
|
round(V_Artikel.Zyklus, 2) as cycleTime,
|
||||||
Sypronummer as salesAgreement,
|
Sypronummer as salesAgreement,
|
||||||
V_Artikel.ProdArtikelBez as ProductFamily
|
V_Artikel.ProdArtikelBez as productFamily
|
||||||
--,REPLACE(pur.UOM,'UOM:','')
|
--,REPLACE(pur.UOM,'UOM:','')
|
||||||
,Case when LEFT(
|
,Case when LEFT(
|
||||||
LTRIM(REPLACE(pur.UOM,'UOM:','')),
|
LTRIM(REPLACE(pur.UOM,'UOM:','')),
|
||||||
@@ -123,7 +125,7 @@ V_Artikel.ProdArtikelBez as ProductFamily
|
|||||||
) is null then '1' else LEFT(
|
) is null then '1' else LEFT(
|
||||||
LTRIM(REPLACE(pur.UOM,'UOM:','')),
|
LTRIM(REPLACE(pur.UOM,'UOM:','')),
|
||||||
CHARINDEX(' ', LTRIM(REPLACE(REPLACE(pur.UOM,'UOM:',''), CHAR(13)+CHAR(10), ' ')) + ' ') - 1
|
CHARINDEX(' ', LTRIM(REPLACE(REPLACE(pur.UOM,'UOM:',''), CHAR(13)+CHAR(10), ' ')) + ' ') - 1
|
||||||
) end AS UOM
|
) end AS uom
|
||||||
--,*
|
--,*
|
||||||
FROM dbo.V_Artikel (nolock)
|
FROM dbo.V_Artikel (nolock)
|
||||||
|
|
||||||
|
|||||||
@@ -1,123 +1,125 @@
|
|||||||
import type { Address } from "nodemailer/lib/mailer/index.js";
|
|
||||||
import type { Transporter } 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 os from "os";
|
|
||||||
import nodemailer from "nodemailer";
|
import nodemailer from "nodemailer";
|
||||||
|
import type Mail from "nodemailer/lib/mailer/index.js";
|
||||||
|
import type { Address } from "nodemailer/lib/mailer/index.js";
|
||||||
|
import type SMTPTransport from "nodemailer/lib/smtp-transport/index.js";
|
||||||
|
import hbs from "nodemailer-express-handlebars";
|
||||||
|
import os from "os";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { fileURLToPath } from "url";
|
import { fileURLToPath } from "url";
|
||||||
import { promisify } from "util";
|
import { promisify } from "util";
|
||||||
import hbs from "nodemailer-express-handlebars";
|
|
||||||
import { createLogger } from "../../logger/logger.js";
|
import { createLogger } from "../../logger/logger.js";
|
||||||
|
|
||||||
interface HandlebarsMailOptions extends Mail.Options {
|
interface HandlebarsMailOptions extends Mail.Options {
|
||||||
template: string;
|
template: string;
|
||||||
context: Record<string, unknown>;
|
context: Record<string, unknown>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface EmailData {
|
interface EmailData {
|
||||||
email: string;
|
email: string;
|
||||||
subject: string;
|
subject: string;
|
||||||
template: string;
|
template: string;
|
||||||
context: Record<string, unknown>;
|
context: Record<string, unknown>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const sendEmail = async (data: EmailData): Promise<any> => {
|
export const sendEmail = async (data: EmailData): Promise<any> => {
|
||||||
const log = createLogger({ module: "pkg", subModule: "sendMail" });
|
const log = createLogger({ module: "pkg", subModule: "sendMail" });
|
||||||
let transporter: Transporter;
|
let transporter: Transporter;
|
||||||
let fromEmail: string | Address;
|
let fromEmail: string | Address;
|
||||||
|
|
||||||
if (
|
// if (
|
||||||
os.hostname().includes("OLP") &&
|
// os.hostname().includes("OLP") &&
|
||||||
process.env.EMAIL_USER &&
|
// process.env.EMAIL_USER &&
|
||||||
process.env.EMAIL_PASSWORD
|
// process.env.EMAIL_PASSWORD
|
||||||
) {
|
// ) {
|
||||||
transporter = nodemailer.createTransport({
|
// transporter = nodemailer.createTransport({
|
||||||
service: "gmail",
|
// service: "gmail",
|
||||||
auth: {
|
// auth: {
|
||||||
user: process.env.EMAIL_USER,
|
// user: process.env.EMAIL_USER,
|
||||||
pass: process.env.EMAIL_PASSWORD,
|
// pass: process.env.EMAIL_PASSWORD,
|
||||||
},
|
// },
|
||||||
//debug: true,
|
// //debug: true,
|
||||||
});
|
// });
|
||||||
|
|
||||||
// update the from email
|
// // update the from email
|
||||||
fromEmail = process.env.EMAIL_USER;
|
// fromEmail = process.env.EMAIL_USER;
|
||||||
} else {
|
// } else {
|
||||||
// convert to the correct plant token.
|
// // convert to the correct plant token.
|
||||||
|
|
||||||
let host = `${os.hostname().replace("VMS006", "")}-smtp.alpla.net`;
|
//let host = `${os.hostname().replace("VMS006", "")}-smtp.alpla.net`;
|
||||||
|
|
||||||
//const testServers = ["vms036", "VMS036"];
|
//const testServers = ["vms036", "VMS036"];
|
||||||
|
|
||||||
if (os.hostname().includes("VMS036")) {
|
// if (os.hostname().includes("VMS036")) {
|
||||||
host = "USMCD1-smtp.alpla.net";
|
// host = "USMCD1-smtp.alpla.net";
|
||||||
}
|
// }
|
||||||
|
|
||||||
// if (plantToken[0].value === "usiow2") {
|
// if (plantToken[0].value === "usiow2") {
|
||||||
// host = "USIOW1-smtp.alpla.net";
|
// host = "USIOW1-smtp.alpla.net";
|
||||||
// }
|
// }
|
||||||
|
|
||||||
transporter = nodemailer.createTransport({
|
transporter = nodemailer.createTransport({
|
||||||
host: host,
|
host: "smtp.azurecomm.net",
|
||||||
port: 25,
|
port: 587,
|
||||||
rejectUnauthorized: false,
|
//rejectUnauthorized: false,
|
||||||
//secure: false,
|
tls: {
|
||||||
// auth: {
|
minVersion: "TLSv1.2",
|
||||||
// user: "alplaprod",
|
},
|
||||||
// pass: "obelix",
|
auth: {
|
||||||
// },
|
user: "donotreply@mail.alpla.com",
|
||||||
debug: true,
|
pass: process.env.SMTP_PASSWORD,
|
||||||
} as SMTPTransport.Options);
|
},
|
||||||
|
debug: true,
|
||||||
|
} as SMTPTransport.Options);
|
||||||
|
|
||||||
// update the from email
|
// update the from email
|
||||||
fromEmail = `noreply@alpla.com`;
|
fromEmail = `DoNotReply@mail.alpla.com`;
|
||||||
}
|
//}
|
||||||
|
|
||||||
// creating the handlbar options
|
// creating the handlbar options
|
||||||
const viewPath = path.resolve(
|
const viewPath = path.resolve(
|
||||||
path.dirname(fileURLToPath(import.meta.url)),
|
path.dirname(fileURLToPath(import.meta.url)),
|
||||||
"./views/"
|
"./views/",
|
||||||
);
|
);
|
||||||
|
|
||||||
const handlebarOptions = {
|
const handlebarOptions = {
|
||||||
viewEngine: {
|
viewEngine: {
|
||||||
extname: ".hbs",
|
extname: ".hbs",
|
||||||
//layoutsDir: path.resolve(viewPath, "layouts"), // Path to layouts directory
|
//layoutsDir: path.resolve(viewPath, "layouts"), // Path to layouts directory
|
||||||
defaultLayout: "", // Specify the default layout
|
defaultLayout: "", // Specify the default layout
|
||||||
partialsDir: viewPath,
|
partialsDir: viewPath,
|
||||||
},
|
},
|
||||||
viewPath: viewPath,
|
viewPath: viewPath,
|
||||||
extName: ".hbs", // File extension for Handlebars templates
|
extName: ".hbs", // File extension for Handlebars templates
|
||||||
};
|
};
|
||||||
|
|
||||||
transporter.use("compile", hbs(handlebarOptions));
|
transporter.use("compile", hbs(handlebarOptions));
|
||||||
|
|
||||||
const mailOptions: HandlebarsMailOptions = {
|
const mailOptions: HandlebarsMailOptions = {
|
||||||
from: fromEmail,
|
from: fromEmail,
|
||||||
to: data.email,
|
to: data.email,
|
||||||
subject: data.subject,
|
subject: data.subject,
|
||||||
//text: "You will have a reset token here and only have 30min to click the link before it expires.",
|
//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"),
|
//html: emailTemplate("BlakesTest", "This is an example with css"),
|
||||||
template: data.template, // Name of the Handlebars template (e.g., 'welcome.hbs')
|
template: data.template, // Name of the Handlebars template (e.g., 'welcome.hbs')
|
||||||
context: data.context,
|
context: data.context,
|
||||||
};
|
};
|
||||||
|
|
||||||
// now verify and send the email
|
// now verify and send the email
|
||||||
const sendMailPromise = promisify(transporter.sendMail).bind(transporter);
|
const sendMailPromise = promisify(transporter.sendMail).bind(transporter);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Send email and await the result
|
// Send email and await the result
|
||||||
const info = await sendMailPromise(mailOptions);
|
const info = await sendMailPromise(mailOptions);
|
||||||
log.info(null, `Email was sent to: ${data.email}`);
|
log.info(null, `Email was sent to: ${data.email}`);
|
||||||
return { success: true, message: "Email sent.", data: info };
|
return { success: true, message: "Email sent.", data: info };
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
log.error(
|
log.error(
|
||||||
{ error: err },
|
{ error: err },
|
||||||
|
|
||||||
`Error sending Email to : ${data.email}`
|
`Error sending Email to : ${data.email}`,
|
||||||
);
|
);
|
||||||
return { success: false, message: "Error sending email.", error: err };
|
return { success: false, message: "Error sending email.", error: err };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -76,7 +76,9 @@ export const prodEndpoint = async <T>(
|
|||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
message: "There was an error processing the endpoint",
|
message: "There was an error processing the endpoint",
|
||||||
data: apiError.response.data,
|
data: apiError.response
|
||||||
|
? apiError.response.data
|
||||||
|
: [{ error: "There was an internal error." }],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -316,7 +316,7 @@ func runNPMInstall(rootDir string, folder string) error {
|
|||||||
} else {
|
} else {
|
||||||
folderDir = filepath.Join(rootDir, folder)
|
folderDir = filepath.Join(rootDir, folder)
|
||||||
}
|
}
|
||||||
cmd := exec.Command("npm", "install")
|
cmd := exec.Command("npm", "install", "--production")
|
||||||
cmd.Dir = folderDir
|
cmd.Dir = folderDir
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
|
|||||||
1942
frontend/package-lock.json
generated
1942
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -11,31 +11,31 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@dnd-kit/core": "^6.3.1",
|
"@dnd-kit/core": "^6.3.1",
|
||||||
"@radix-ui/react-avatar": "^1.1.10",
|
"@radix-ui/react-avatar": "^1.1.11",
|
||||||
"@radix-ui/react-checkbox": "^1.3.3",
|
"@radix-ui/react-checkbox": "^1.3.3",
|
||||||
"@radix-ui/react-collapsible": "^1.1.12",
|
"@radix-ui/react-collapsible": "^1.1.12",
|
||||||
"@radix-ui/react-dialog": "^1.1.15",
|
"@radix-ui/react-dialog": "^1.1.15",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
||||||
"@radix-ui/react-label": "^2.1.7",
|
"@radix-ui/react-label": "^2.1.8",
|
||||||
"@radix-ui/react-popover": "^1.1.15",
|
"@radix-ui/react-popover": "^1.1.15",
|
||||||
"@radix-ui/react-scroll-area": "^1.2.10",
|
"@radix-ui/react-scroll-area": "^1.2.10",
|
||||||
"@radix-ui/react-select": "^2.2.6",
|
"@radix-ui/react-select": "^2.2.6",
|
||||||
"@radix-ui/react-separator": "^1.1.7",
|
"@radix-ui/react-separator": "^1.1.8",
|
||||||
"@radix-ui/react-slot": "^1.2.4",
|
"@radix-ui/react-slot": "^1.2.4",
|
||||||
"@radix-ui/react-switch": "^1.2.6",
|
"@radix-ui/react-switch": "^1.2.6",
|
||||||
"@radix-ui/react-tabs": "^1.1.13",
|
"@radix-ui/react-tabs": "^1.1.13",
|
||||||
"@radix-ui/react-tooltip": "^1.2.8",
|
"@radix-ui/react-tooltip": "^1.2.8",
|
||||||
"@react-pdf/renderer": "^4.3.1",
|
"@react-pdf/renderer": "^4.3.1",
|
||||||
"@tailwindcss/vite": "^4.1.13",
|
"@tailwindcss/vite": "^4.1.17",
|
||||||
"@tanstack/react-form": "^1.23.0",
|
"@tanstack/react-form": "^1.26.0",
|
||||||
"@tanstack/react-query": "^5.89.0",
|
"@tanstack/react-query": "^5.90.11",
|
||||||
"@tanstack/react-query-devtools": "^5.90.2",
|
"@tanstack/react-query-devtools": "^5.91.1",
|
||||||
"@tanstack/react-router": "^1.131.36",
|
"@tanstack/react-router": "^1.139.6",
|
||||||
"@tanstack/react-router-devtools": "^1.131.36",
|
"@tanstack/react-router-devtools": "^1.139.6",
|
||||||
"@tanstack/react-table": "^8.21.3",
|
"@tanstack/react-table": "^8.21.3",
|
||||||
"@types/react-calendar-timeline": "^0.28.6",
|
"@types/react-calendar-timeline": "^0.28.6",
|
||||||
"axios": "^1.12.2",
|
"axios": "^1.13.2",
|
||||||
"better-auth": "^1.3.11",
|
"better-auth": "^1.4.2",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cmdk": "^1.1.1",
|
"cmdk": "^1.1.1",
|
||||||
@@ -43,39 +43,38 @@
|
|||||||
"is-mobile": "^5.0.0",
|
"is-mobile": "^5.0.0",
|
||||||
"js-cookie": "^3.0.5",
|
"js-cookie": "^3.0.5",
|
||||||
"jsbarcode": "^3.12.1",
|
"jsbarcode": "^3.12.1",
|
||||||
"lucide-react": "^0.542.0",
|
"lucide-react": "^0.554.0",
|
||||||
"marked": "^16.4.1",
|
"marked": "^17.0.1",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"r": "^0.0.5",
|
"react": "^19.2.0",
|
||||||
"react": "^19.1.1",
|
|
||||||
"react-barcode": "^1.6.1",
|
"react-barcode": "^1.6.1",
|
||||||
"react-calendar-timeline": "^0.30.0-beta.3",
|
"react-calendar-timeline": "^0.30.0-beta.4",
|
||||||
"react-day-picker": "^9.11.1",
|
"react-day-picker": "^9.11.2",
|
||||||
"react-dom": "^19.1.1",
|
"react-dom": "^19.2.0",
|
||||||
"react-hook-form": "^7.65.0",
|
"react-hook-form": "^7.66.1",
|
||||||
"react-resizable-panels": "^3.0.6",
|
"react-resizable-panels": "^3.0.6",
|
||||||
"recharts": "^2.15.4",
|
"recharts": "^2.15.4",
|
||||||
"socket.io-client": "^4.8.1",
|
"socket.io-client": "^4.8.1",
|
||||||
"sonner": "^2.0.7",
|
"sonner": "^2.0.7",
|
||||||
"tailwind-merge": "^3.3.1",
|
"tailwind-merge": "^3.4.0",
|
||||||
"tailwindcss": "^4.1.13",
|
"tailwindcss": "^4.1.17",
|
||||||
"zustand": "^5.0.8"
|
"zustand": "^5.0.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.33.0",
|
"@eslint/js": "^9.39.1",
|
||||||
"@tanstack/router-plugin": "^1.131.36",
|
"@tanstack/router-plugin": "^1.139.6",
|
||||||
"@types/js-cookie": "^3.0.6",
|
"@types/js-cookie": "^3.0.6",
|
||||||
"@types/node": "^24.3.1",
|
"@types/node": "^24.10.1",
|
||||||
"@types/react": "^19.1.10",
|
"@types/react": "^19.2.7",
|
||||||
"@types/react-dom": "^19.1.7",
|
"@types/react-dom": "^19.2.3",
|
||||||
"@vitejs/plugin-react-swc": "^4.0.0",
|
"@vitejs/plugin-react-swc": "^4.2.2",
|
||||||
"eslint": "^9.33.0",
|
"eslint": "^9.39.1",
|
||||||
"eslint-plugin-react-hooks": "^5.2.0",
|
"eslint-plugin-react-hooks": "^7.0.1",
|
||||||
"eslint-plugin-react-refresh": "^0.4.20",
|
"eslint-plugin-react-refresh": "^0.4.24",
|
||||||
"globals": "^16.3.0",
|
"globals": "^16.5.0",
|
||||||
"tw-animate-css": "^1.3.8",
|
"tw-animate-css": "^1.4.0",
|
||||||
"typescript": "~5.8.3",
|
"typescript": "~5.9.3",
|
||||||
"typescript-eslint": "^8.39.1",
|
"typescript-eslint": "^8.48.0",
|
||||||
"vite": "^7.1.2"
|
"vite": "^7.2.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export default function Admin() {
|
|||||||
const items: Items[] = [
|
const items: Items[] = [
|
||||||
{
|
{
|
||||||
title: "Users",
|
title: "Users",
|
||||||
url: "/lst/app/admin/users",
|
url: "/admin/users",
|
||||||
icon: User,
|
icon: User,
|
||||||
role: ["systemAdmin", "admin"],
|
role: ["systemAdmin", "admin"],
|
||||||
module: "admin",
|
module: "admin",
|
||||||
@@ -23,7 +23,7 @@ export default function Admin() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "System",
|
title: "System",
|
||||||
url: "/lst/app/admin/settings",
|
url: "/admin/settings",
|
||||||
icon: Settings,
|
icon: Settings,
|
||||||
role: ["systemAdmin", "admin"],
|
role: ["systemAdmin", "admin"],
|
||||||
module: "admin",
|
module: "admin",
|
||||||
@@ -31,7 +31,7 @@ export default function Admin() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Modules",
|
title: "Modules",
|
||||||
url: "/lst/app/admin/modules",
|
url: "/admin/modules",
|
||||||
icon: Settings,
|
icon: Settings,
|
||||||
role: ["systemAdmin", "admin"],
|
role: ["systemAdmin", "admin"],
|
||||||
module: "admin",
|
module: "admin",
|
||||||
@@ -39,7 +39,7 @@ export default function Admin() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Servers",
|
title: "Servers",
|
||||||
url: "/lst/app/admin/servers",
|
url: "/admin/servers",
|
||||||
icon: Server,
|
icon: Server,
|
||||||
role: ["systemAdmin", "admin"],
|
role: ["systemAdmin", "admin"],
|
||||||
module: "admin",
|
module: "admin",
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export default function ForkliftSideBar() {
|
|||||||
const items: Items[] = [
|
const items: Items[] = [
|
||||||
{
|
{
|
||||||
title: "Lease Companies",
|
title: "Lease Companies",
|
||||||
url: "/lst/app/forklifts/companies",
|
url: "/forklifts/companies",
|
||||||
icon: Building2,
|
icon: Building2,
|
||||||
role: ["systemAdmin", "admin"],
|
role: ["systemAdmin", "admin"],
|
||||||
module: "forklifts",
|
module: "forklifts",
|
||||||
@@ -29,7 +29,7 @@ export default function ForkliftSideBar() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Leases",
|
title: "Leases",
|
||||||
url: "/lst/app/forklifts/leases",
|
url: "/forklifts/leases",
|
||||||
icon: ReceiptText,
|
icon: ReceiptText,
|
||||||
role: ["systemAdmin", "admin"],
|
role: ["systemAdmin", "admin"],
|
||||||
module: "forklifts",
|
module: "forklifts",
|
||||||
@@ -37,7 +37,7 @@ export default function ForkliftSideBar() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Invoices",
|
title: "Invoices",
|
||||||
url: "/lst/app/forklifts/invoices",
|
url: "/forklifts/invoices",
|
||||||
icon: ReceiptText,
|
icon: ReceiptText,
|
||||||
role: ["systemAdmin", "admin", "manager"],
|
role: ["systemAdmin", "admin", "manager"],
|
||||||
module: "forklifts",
|
module: "forklifts",
|
||||||
@@ -45,7 +45,7 @@ export default function ForkliftSideBar() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Repairs",
|
title: "Repairs",
|
||||||
url: "/lst/app/admin/settings",
|
url: "/admin/settings",
|
||||||
icon: Wrench,
|
icon: Wrench,
|
||||||
role: ["systemAdmin", "admin", "manager"],
|
role: ["systemAdmin", "admin", "manager"],
|
||||||
module: "forklifts",
|
module: "forklifts",
|
||||||
@@ -53,7 +53,7 @@ export default function ForkliftSideBar() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Hours",
|
title: "Hours",
|
||||||
url: "/lst/app/admin/settings",
|
url: "/admin/settings",
|
||||||
icon: Hourglass,
|
icon: Hourglass,
|
||||||
role: ["systemAdmin", "admin", "manager", "supervisor"],
|
role: ["systemAdmin", "admin", "manager", "supervisor"],
|
||||||
module: "forklifts",
|
module: "forklifts",
|
||||||
@@ -61,7 +61,7 @@ export default function ForkliftSideBar() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Forklifts",
|
title: "Forklifts",
|
||||||
url: "/lst/app/forklifts/forklifts",
|
url: "/forklifts/forklifts",
|
||||||
icon: Forklift,
|
icon: Forklift,
|
||||||
role: ["systemAdmin", "admin", "manager", "supervisor"],
|
role: ["systemAdmin", "admin", "manager", "supervisor"],
|
||||||
module: "forklifts",
|
module: "forklifts",
|
||||||
|
|||||||
18
frontend/src/lib/querys/admin/getSettings.ts
Normal file
18
frontend/src/lib/querys/admin/getSettings.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { keepPreviousData, queryOptions } from "@tanstack/react-query";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
export function getSettings() {
|
||||||
|
return queryOptions({
|
||||||
|
queryKey: ["getSettings"],
|
||||||
|
queryFn: () => fetchSession(),
|
||||||
|
staleTime: 5000,
|
||||||
|
refetchOnWindowFocus: true,
|
||||||
|
placeholderData: keepPreviousData,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchSession = async () => {
|
||||||
|
const { data } = await axios.get("/lst/api/system/settings");
|
||||||
|
|
||||||
|
return data.data;
|
||||||
|
};
|
||||||
26
frontend/src/lib/tableStuff/GenericColumn.tsx
Normal file
26
frontend/src/lib/tableStuff/GenericColumn.tsx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { createColumnHelper } from "@tanstack/react-table";
|
||||||
|
import { ArrowDown, ArrowUp } from "lucide-react";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
|
||||||
|
export const GenericColumn = ({ columnName }: { columnName: string }) => {
|
||||||
|
const columnHelper = createColumnHelper();
|
||||||
|
|
||||||
|
return columnHelper.accessor(`${columnName}`, {
|
||||||
|
header: ({ column }) => {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
||||||
|
>
|
||||||
|
<span className="flex flex-row gap-2">{`${columnName.toUpperCase()}`}</span>
|
||||||
|
{column.getIsSorted() === "asc" ? (
|
||||||
|
<ArrowUp className="ml-2 h-4 w-4" />
|
||||||
|
) : (
|
||||||
|
<ArrowDown className="ml-2 h-4 w-4" />
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
cell: (i) => i.getValue(),
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
flexRender,
|
flexRender,
|
||||||
getCoreRowModel,
|
getCoreRowModel,
|
||||||
|
getFilteredRowModel,
|
||||||
getPaginationRowModel,
|
getPaginationRowModel,
|
||||||
getSortedRowModel,
|
getSortedRowModel,
|
||||||
type SortingState,
|
type SortingState,
|
||||||
@@ -26,6 +27,9 @@ export default function TableNoExpand({
|
|||||||
columns: any;
|
columns: any;
|
||||||
}) {
|
}) {
|
||||||
const [sorting, setSorting] = useState<SortingState>([]);
|
const [sorting, setSorting] = useState<SortingState>([]);
|
||||||
|
// const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
|
||||||
|
// []
|
||||||
|
// )
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data,
|
data,
|
||||||
columns,
|
columns,
|
||||||
@@ -33,11 +37,14 @@ export default function TableNoExpand({
|
|||||||
getPaginationRowModel: getPaginationRowModel(),
|
getPaginationRowModel: getPaginationRowModel(),
|
||||||
onSortingChange: setSorting,
|
onSortingChange: setSorting,
|
||||||
getSortedRowModel: getSortedRowModel(),
|
getSortedRowModel: getSortedRowModel(),
|
||||||
|
getFilteredRowModel: getFilteredRowModel(),
|
||||||
|
|
||||||
//renderSubComponent: ({ row }: { row: any }) => <ExpandedRow row={row} />,
|
//renderSubComponent: ({ row }: { row: any }) => <ExpandedRow row={row} />,
|
||||||
//getRowCanExpand: () => true,
|
//getRowCanExpand: () => true,
|
||||||
|
filterFns: {},
|
||||||
state: {
|
state: {
|
||||||
sorting,
|
sorting,
|
||||||
|
//columnFilters
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,7 +1,31 @@
|
|||||||
import { createFileRoute, Link, Outlet } from "@tanstack/react-router";
|
import {
|
||||||
|
createFileRoute,
|
||||||
|
Link,
|
||||||
|
Outlet,
|
||||||
|
redirect,
|
||||||
|
} from "@tanstack/react-router";
|
||||||
|
import { checkUserAccess } from "@/lib/authClient";
|
||||||
|
|
||||||
export const Route = createFileRoute("/_app/_adminLayout/admin/_system")({
|
export const Route = createFileRoute("/_app/_adminLayout/admin/_system")({
|
||||||
component: RouteComponent,
|
component: RouteComponent,
|
||||||
|
beforeLoad: async () => {
|
||||||
|
const auth = await checkUserAccess({
|
||||||
|
allowedRoles: ["systemAdmin", "admin"],
|
||||||
|
moduleName: "system", // optional
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!auth) {
|
||||||
|
throw redirect({
|
||||||
|
to: "/login",
|
||||||
|
search: {
|
||||||
|
// Use the current location to power a redirect after login
|
||||||
|
// (Do not use `router.state.resolvedLocation` as it can
|
||||||
|
// potentially lag behind the actual current location)
|
||||||
|
redirect: location.pathname + location.search,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
function RouteComponent() {
|
function RouteComponent() {
|
||||||
|
|||||||
@@ -1,11 +1,230 @@
|
|||||||
import { createFileRoute } from '@tanstack/react-router'
|
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||||
|
import { createFileRoute } from "@tanstack/react-router";
|
||||||
|
import { createColumnHelper } from "@tanstack/react-table";
|
||||||
|
import axios from "axios";
|
||||||
|
import { ArrowDown, ArrowUp } from "lucide-react";
|
||||||
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { getSettings } from "@/lib/querys/admin/getSettings";
|
||||||
|
import TableNoExpand from "@/lib/tableStuff/TableNoExpand";
|
||||||
|
|
||||||
|
type Settings = {
|
||||||
|
settings_id: string;
|
||||||
|
name: string;
|
||||||
|
active: boolean;
|
||||||
|
value: string;
|
||||||
|
description: string;
|
||||||
|
moduleName: string;
|
||||||
|
roles: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateSettings = async (
|
||||||
|
id: string,
|
||||||
|
data: Record<string, string | number | boolean | null>,
|
||||||
|
) => {
|
||||||
|
console.log(id, data);
|
||||||
|
try {
|
||||||
|
const res = await axios.patch(`/lst/api/system/settings/${id}`, data, {
|
||||||
|
withCredentials: true,
|
||||||
|
});
|
||||||
|
toast.success(`Setting just updated`);
|
||||||
|
return res;
|
||||||
|
} catch (err) {
|
||||||
|
toast.error("Error in updating the settings");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const Route = createFileRoute(
|
export const Route = createFileRoute(
|
||||||
'/_app/_adminLayout/admin/_system/settings',
|
"/_app/_adminLayout/admin/_system/settings",
|
||||||
)({
|
)({
|
||||||
component: RouteComponent,
|
component: RouteComponent,
|
||||||
})
|
});
|
||||||
|
|
||||||
function RouteComponent() {
|
function RouteComponent() {
|
||||||
return <div>Hello "/_app/_adminLayout/admin/_system/settings"!</div>
|
const { data, isLoading, refetch } = useQuery(getSettings());
|
||||||
|
const columnHelper = createColumnHelper<Settings>();
|
||||||
|
const submitting = useRef(false);
|
||||||
|
|
||||||
|
const updateSetting = useMutation({
|
||||||
|
mutationFn: ({
|
||||||
|
id,
|
||||||
|
field,
|
||||||
|
value,
|
||||||
|
}: {
|
||||||
|
id: string;
|
||||||
|
field: string;
|
||||||
|
value: string | number | boolean | null;
|
||||||
|
}) => updateSettings(id, { [field]: value }),
|
||||||
|
|
||||||
|
onSuccess: () => {
|
||||||
|
// refetch or update cache
|
||||||
|
refetch();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
columnHelper.accessor("name", {
|
||||||
|
header: ({ column }) => {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
||||||
|
>
|
||||||
|
<span className="flex flex-row gap-2">Name</span>
|
||||||
|
{column.getIsSorted() === "asc" ? (
|
||||||
|
<ArrowUp className="ml-2 h-4 w-4" />
|
||||||
|
) : (
|
||||||
|
<ArrowDown className="ml-2 h-4 w-4" />
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
cell: (i) => i.getValue(),
|
||||||
|
}),
|
||||||
|
columnHelper.accessor("description", {
|
||||||
|
header: ({ column }) => {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
||||||
|
>
|
||||||
|
<span className="flex flex-row gap-2">Description</span>
|
||||||
|
{column.getIsSorted() === "asc" ? (
|
||||||
|
<ArrowUp className="ml-2 h-4 w-4" />
|
||||||
|
) : (
|
||||||
|
<ArrowDown className="ml-2 h-4 w-4" />
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
cell: (i) => i.getValue(),
|
||||||
|
}),
|
||||||
|
columnHelper.accessor("value", {
|
||||||
|
header: ({ column }) => {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
||||||
|
>
|
||||||
|
<span className="flex flex-row gap-2">Value</span>
|
||||||
|
{column.getIsSorted() === "asc" ? (
|
||||||
|
<ArrowUp className="ml-2 h-4 w-4" />
|
||||||
|
) : (
|
||||||
|
<ArrowDown className="ml-2 h-4 w-4" />
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
cell: ({ row, getValue }) => {
|
||||||
|
const initialValue = String(getValue() ?? "");
|
||||||
|
const [localValue, setLocalValue] = useState(initialValue);
|
||||||
|
|
||||||
|
const id = row.original.settings_id;
|
||||||
|
const field = "value";
|
||||||
|
|
||||||
|
useEffect(() => setLocalValue(initialValue), [initialValue]);
|
||||||
|
|
||||||
|
const handleSubmit = (newValue: string) => {
|
||||||
|
if (newValue !== initialValue) {
|
||||||
|
setLocalValue(newValue);
|
||||||
|
updateSetting.mutate({ id, field, value: newValue });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
value={localValue}
|
||||||
|
onChange={(e) => setLocalValue(e.currentTarget.value)}
|
||||||
|
onBlur={(e) => {
|
||||||
|
if (!submitting.current) {
|
||||||
|
submitting.current = true;
|
||||||
|
handleSubmit(e.currentTarget.value.trim());
|
||||||
|
setTimeout(() => (submitting.current = false), 100); // reset after slight delay
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (e.key === "Enter") {
|
||||||
|
e.preventDefault();
|
||||||
|
submitting.current = true;
|
||||||
|
handleSubmit(e.currentTarget.value.trim());
|
||||||
|
e.currentTarget.blur(); // will trigger blur, but we ignore it
|
||||||
|
setTimeout(() => (submitting.current = false), 100);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
columnHelper.accessor("moduleName", {
|
||||||
|
header: ({ column }) => {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
||||||
|
>
|
||||||
|
<span className="flex flex-row gap-2">Module Name</span>
|
||||||
|
{column.getIsSorted() === "asc" ? (
|
||||||
|
<ArrowUp className="ml-2 h-4 w-4" />
|
||||||
|
) : (
|
||||||
|
<ArrowDown className="ml-2 h-4 w-4" />
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
cell: ({ row, getValue }) => {
|
||||||
|
const initialValue = String(getValue() ?? "");
|
||||||
|
const [localValue, setLocalValue] = useState(initialValue);
|
||||||
|
|
||||||
|
const id = row.original.settings_id;
|
||||||
|
const field = "moduleName";
|
||||||
|
|
||||||
|
useEffect(() => setLocalValue(initialValue), [initialValue]);
|
||||||
|
|
||||||
|
const handleSubmit = (newValue: string) => {
|
||||||
|
if (newValue !== initialValue) {
|
||||||
|
setLocalValue(newValue);
|
||||||
|
updateSetting.mutate({ id, field, value: newValue });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
value={localValue}
|
||||||
|
onChange={(e) => setLocalValue(e.currentTarget.value)}
|
||||||
|
onBlur={(e) => {
|
||||||
|
if (!submitting.current) {
|
||||||
|
submitting.current = true;
|
||||||
|
handleSubmit(e.currentTarget.value.trim());
|
||||||
|
setTimeout(() => (submitting.current = false), 100); // reset after slight delay
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (e.key === "Enter") {
|
||||||
|
e.preventDefault();
|
||||||
|
submitting.current = true;
|
||||||
|
handleSubmit(e.currentTarget.value.trim());
|
||||||
|
e.currentTarget.blur(); // will trigger blur, but we ignore it
|
||||||
|
setTimeout(() => (submitting.current = false), 100);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
if (isLoading)
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<span>Loading settings data</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<div className="m-2">
|
||||||
|
<TableNoExpand data={data} columns={columns} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,72 +3,60 @@ import ForecastImport from "./ForecastImport";
|
|||||||
import OrderImport from "./OrderImport";
|
import OrderImport from "./OrderImport";
|
||||||
|
|
||||||
export default function DMButtons() {
|
export default function DMButtons() {
|
||||||
const { settings } = useSettingStore();
|
const { settings } = useSettingStore();
|
||||||
const testServers = ["test1", "test2", "test3"];
|
const testServers = ["test1", "test2", "test3"];
|
||||||
const plantToken = settings.filter((n) => n.name === "plantToken");
|
const plantToken = settings.filter((n) => n.name === "plantToken");
|
||||||
|
|
||||||
//console.log(plantToken);
|
//console.log(plantToken);
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-row-reverse gap-1">
|
<div className="flex flex-row-reverse gap-1">
|
||||||
<OrderImport fileType={"macro"} name={"Macro Import"} />
|
<OrderImport fileType={"macro"} name={"Macro Import"} />
|
||||||
{/* dev and testserver sees all */}
|
{/* dev and testserver sees all */}
|
||||||
{testServers.includes(plantToken[0]?.value) && (
|
{testServers.includes(plantToken[0]?.value) && (
|
||||||
<div className="flex flex-row gap-2">
|
<div className="flex flex-row gap-2">
|
||||||
<OrderImport
|
<OrderImport fileType={"abbott"} name={"Abbott truck list"} />
|
||||||
fileType={"abbott"}
|
<OrderImport fileType={"energizer"} name={"Energizer Truck List"} />
|
||||||
name={"Abbott truck list"}
|
<OrderImport fileType={"scj"} name={"SCJ Orders"} />
|
||||||
/>
|
<ForecastImport fileType={"loreal"} name={"VMI Import"} />
|
||||||
<OrderImport
|
<ForecastImport fileType={"pg"} name={"P&G"} />
|
||||||
fileType={"energizer"}
|
<ForecastImport fileType={"energizer"} name={"Energizer Forecast"} />
|
||||||
name={"Energizer Truck List"}
|
</div>
|
||||||
/>
|
)}
|
||||||
<ForecastImport fileType={"loreal"} name={"VMI Import"} />
|
{plantToken[0]?.value === "usday1" && (
|
||||||
<ForecastImport fileType={"pg"} name={"P&G"} />
|
<div className="flex flex-row gap-2">
|
||||||
<ForecastImport
|
<OrderImport fileType={"abbott"} name={"Abbott truck list"} />
|
||||||
fileType={"energizer"}
|
<OrderImport fileType={"energizer"} name={"Energizer Truck List"} />
|
||||||
name={"Energizer Forecast"}
|
<ForecastImport fileType={"energizer"} name={"Energizer Forecast"} />
|
||||||
/>
|
</div>
|
||||||
</div>
|
)}
|
||||||
)}
|
{plantToken[0]?.value === "usflo1" && (
|
||||||
{plantToken[0]?.value === "usday1" && (
|
<div className="flex flex-row gap-2">
|
||||||
<div className="flex flex-row gap-2">
|
<ForecastImport fileType={"loreal"} name={"VMI Import"} />
|
||||||
<OrderImport
|
</div>
|
||||||
fileType={"abbott"}
|
)}
|
||||||
name={"Abbott truck list"}
|
{plantToken[0]?.value === "usstp1" && (
|
||||||
/>
|
<div className="flex flex-row gap-2"></div>
|
||||||
<OrderImport
|
)}
|
||||||
fileType={"energizer"}
|
{plantToken[0]?.value === "usiow1" && (
|
||||||
name={"Energizer Truck List"}
|
<div className="flex flex-row gap-2">
|
||||||
/>
|
<ForecastImport fileType={"pg"} name={"P&G"} />
|
||||||
<ForecastImport
|
</div>
|
||||||
fileType={"energizer"}
|
)}
|
||||||
name={"Energizer Forecast"}
|
{plantToken[0]?.value === "usiow2" && (
|
||||||
/>
|
<div className="flex flex-row gap-2">
|
||||||
</div>
|
<ForecastImport fileType={"pg"} name={"P&G"} />
|
||||||
)}
|
</div>
|
||||||
{plantToken[0]?.value === "usflo1" && (
|
)}
|
||||||
<div className="flex flex-row gap-2">
|
{plantToken[0]?.value === "usksc1" && (
|
||||||
<ForecastImport fileType={"loreal"} name={"VMI Import"} />
|
<div className="flex flex-row gap-2">
|
||||||
</div>
|
<ForecastImport fileType={"pg"} name={"P&G"} />
|
||||||
)}
|
</div>
|
||||||
{plantToken[0]?.value === "usstp1" && (
|
)}
|
||||||
<div className="flex flex-row gap-2"></div>
|
{plantToken[0]?.value === "usweb1" && (
|
||||||
)}
|
<div className="flex flex-row gap-2">
|
||||||
{plantToken[0]?.value === "usiow1" && (
|
<OrderImport fileType={"scj"} name={"SCJ Orders"} />
|
||||||
<div className="flex flex-row gap-2">
|
</div>
|
||||||
<ForecastImport fileType={"pg"} name={"P&G"} />
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
);
|
||||||
{plantToken[0]?.value === "usiow2" && (
|
|
||||||
<div className="flex flex-row gap-2">
|
|
||||||
<ForecastImport fileType={"pg"} name={"P&G"} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{plantToken[0]?.value === "usksc1" && (
|
|
||||||
<div className="flex flex-row gap-2">
|
|
||||||
<ForecastImport fileType={"pg"} name={"P&G"} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,14 +12,15 @@ import { LstCard } from "../../../extendedUi/LstCard";
|
|||||||
export default function Relocate() {
|
export default function Relocate() {
|
||||||
const [bookingIn, setBookingIn] = useState(false);
|
const [bookingIn, setBookingIn] = useState(false);
|
||||||
const form = useForm({
|
const form = useForm({
|
||||||
defaultValues: { runningNr: " ", lane: "" },
|
defaultValues: { runningNr: " ", laneID: "" },
|
||||||
onSubmit: async ({ value }) => {
|
onSubmit: async ({ value }) => {
|
||||||
// Do something with form data
|
// Do something with form data
|
||||||
setBookingIn(true);
|
setBookingIn(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await axios.post("/lst/old/api/ocp/bookin", {
|
const res = await axios.post("/lst/old/api/logistics/relocate", {
|
||||||
runningNr: parseInt(value.runningNr),
|
runningNr: parseInt(value.runningNr),
|
||||||
|
laneID: parseInt(value.laneID),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.data.success) {
|
if (res.data.success) {
|
||||||
@@ -27,15 +28,15 @@ export default function Relocate() {
|
|||||||
form.reset();
|
form.reset();
|
||||||
setBookingIn(false);
|
setBookingIn(false);
|
||||||
} else {
|
} else {
|
||||||
console.log(res.data.data.errors);
|
console.log(res.data.message);
|
||||||
toast.error(res.data.data.errors[0]?.message);
|
toast.error(res.data.message);
|
||||||
form.reset();
|
//form.reset();
|
||||||
setBookingIn(false);
|
setBookingIn(false);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
toast.error(
|
toast.error(
|
||||||
"There was an error booking in pallet please validate you entered the correct info and try again.",
|
"There was an error relocating the pallet please validate the data.",
|
||||||
);
|
);
|
||||||
setBookingIn(false);
|
setBookingIn(false);
|
||||||
}
|
}
|
||||||
@@ -58,7 +59,7 @@ export default function Relocate() {
|
|||||||
validators={{
|
validators={{
|
||||||
// We can choose between form-wide and field-specific validators
|
// We can choose between form-wide and field-specific validators
|
||||||
onChange: ({ value }) =>
|
onChange: ({ value }) =>
|
||||||
value.length > 2
|
value.length > 0
|
||||||
? undefined
|
? undefined
|
||||||
: "Please enter a valid running number",
|
: "Please enter a valid running number",
|
||||||
}}
|
}}
|
||||||
@@ -83,19 +84,17 @@ export default function Relocate() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<form.Field
|
<form.Field
|
||||||
name="lane"
|
name="laneID"
|
||||||
validators={{
|
validators={{
|
||||||
// We can choose between form-wide and field-specific validators
|
// We can choose between form-wide and field-specific validators
|
||||||
onChange: ({ value }) =>
|
onChange: ({ value }) =>
|
||||||
value.length > 2
|
value.length > 0 ? undefined : "Please enter a valid lane ID",
|
||||||
? undefined
|
|
||||||
: "Please enter a valid running number",
|
|
||||||
}}
|
}}
|
||||||
children={(field) => {
|
children={(field) => {
|
||||||
return (
|
return (
|
||||||
<div className="">
|
<div className="">
|
||||||
<Label htmlFor="runningNr" className="mb-2">
|
<Label htmlFor="laneID" className="mb-2">
|
||||||
Enter lane
|
Enter lane ID
|
||||||
</Label>
|
</Label>
|
||||||
<Input
|
<Input
|
||||||
name={field.name}
|
name={field.name}
|
||||||
|
|||||||
@@ -3,17 +3,25 @@ import Relocate from "./commands/Relocate";
|
|||||||
import RemoveAsNonReusable from "./commands/RemoveAsNonReusable";
|
import RemoveAsNonReusable from "./commands/RemoveAsNonReusable";
|
||||||
|
|
||||||
export default function HelperPage() {
|
export default function HelperPage() {
|
||||||
const url: string = window.location.host.split(":")[0];
|
const url: string = window.location.host.split(":")[0];
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-wrap m-2 justify-center">
|
<div className="flex flex-wrap m-2 justify-center">
|
||||||
<div className="m-1">
|
<div className="m-1">
|
||||||
<Bookin />
|
<div className="m-1 ">
|
||||||
</div>
|
<Bookin />
|
||||||
|
</div>
|
||||||
|
<div className="w-96 m-1">
|
||||||
|
<Relocate />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="m-1">
|
<div className="m-1">
|
||||||
<RemoveAsNonReusable />
|
{url === "localhost" && (
|
||||||
</div>
|
<div className="m-1">
|
||||||
<div className="m-1">{url === "localhost" && <Relocate />}</div>
|
<RemoveAsNonReusable />
|
||||||
</div>
|
</div>
|
||||||
);
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import { LstCard } from "../../../extendedUi/LstCard";
|
|||||||
export default function TransferToNextLot() {
|
export default function TransferToNextLot() {
|
||||||
const [gaylordFilled, setGaylordFilled] = useState([0]);
|
const [gaylordFilled, setGaylordFilled] = useState([0]);
|
||||||
const [actualAmount, setActualAmount] = useState(0);
|
const [actualAmount, setActualAmount] = useState(0);
|
||||||
const [tab, setTab] = useState("esitmate");
|
const [tab, setTab] = useState("estimate");
|
||||||
const [typeSwitch, setTypeSwitch] = useState(false);
|
const [typeSwitch, setTypeSwitch] = useState(false);
|
||||||
const { settings } = useSettingStore();
|
const { settings } = useSettingStore();
|
||||||
|
|
||||||
@@ -207,7 +207,7 @@ export default function TransferToNextLot() {
|
|||||||
<span>"EOM Transfer"</span>
|
<span>"EOM Transfer"</span>
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger>
|
<TooltipTrigger>
|
||||||
<Info className="h-[16px] w-[16px]" />
|
<Info className="h-4 w-4" />
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>
|
<TooltipContent>
|
||||||
<p>
|
<p>
|
||||||
@@ -223,7 +223,7 @@ export default function TransferToNextLot() {
|
|||||||
<span>"Lot Transfer"</span>
|
<span>"Lot Transfer"</span>
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger>
|
<TooltipTrigger>
|
||||||
<Info className="h-[16px] w-[16px]" />
|
<Info className="h-4 w-4" />
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>
|
<TooltipContent>
|
||||||
<p>
|
<p>
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import { useSettingStore } from "../../../-lib/store/useSettings";
|
|||||||
const printReason = [
|
const printReason = [
|
||||||
{ key: "printerIssue", label: "Printer Related" },
|
{ key: "printerIssue", label: "Printer Related" },
|
||||||
{ key: "missingRfidTag", label: "Missing or incorrect tag" },
|
{ key: "missingRfidTag", label: "Missing or incorrect tag" },
|
||||||
|
{ key: "multipleTags", label: "More than one tag on pallet." },
|
||||||
{ key: "rfidMissScan", label: "Missed Scan from RFID reader" },
|
{ key: "rfidMissScan", label: "Missed Scan from RFID reader" },
|
||||||
{ key: "strapper", label: "Strapper Error" },
|
{ key: "strapper", label: "Strapper Error" },
|
||||||
{ key: "manualCheck", label: "20th pallet check" },
|
{ key: "manualCheck", label: "20th pallet check" },
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ export const readerColumns: ColumnDef<Readers>[] = [
|
|||||||
const resetReads = async () => {
|
const resetReads = async () => {
|
||||||
setReaderReset(true);
|
setReaderReset(true);
|
||||||
try {
|
try {
|
||||||
const res = await axios.post("/api/rfid/resetRatio", {
|
const res = await axios.post("/lst/old/api/rfid/resetRatio", {
|
||||||
reader: name,
|
reader: name,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
1129
lstDocs/package-lock.json
generated
1129
lstDocs/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -15,19 +15,19 @@
|
|||||||
"typecheck": "tsc"
|
"typecheck": "tsc"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "^3.9.1",
|
"@docusaurus/core": "^3.9.2",
|
||||||
"@docusaurus/preset-classic": "^3.9.1",
|
"@docusaurus/preset-classic": "^3.9.2",
|
||||||
"@mdx-js/react": "^3.0.0",
|
"@mdx-js/react": "^3.1.1",
|
||||||
"clsx": "^2.0.0",
|
"clsx": "^2.1.1",
|
||||||
"prism-react-renderer": "^2.3.0",
|
"prism-react-renderer": "^2.4.1",
|
||||||
"react": "^19.0.0",
|
"react": "^19.2.0",
|
||||||
"react-dom": "^19.0.0"
|
"react-dom": "^19.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/module-type-aliases": "^3.9.1",
|
"@docusaurus/module-type-aliases": "^3.9.2",
|
||||||
"@docusaurus/tsconfig": "^3.9.1",
|
"@docusaurus/tsconfig": "^3.9.2",
|
||||||
"@docusaurus/types": "^3.9.1",
|
"@docusaurus/types": "^3.9.2",
|
||||||
"typescript": "~5.6.2"
|
"typescript": "~5.9.3"
|
||||||
},
|
},
|
||||||
"browserslist": {
|
"browserslist": {
|
||||||
"production": [
|
"production": [
|
||||||
|
|||||||
2
lstV2/database/migrations/0078_cheerful_the_leader.sql
Normal file
2
lstV2/database/migrations/0078_cheerful_the_leader.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE "invHistoricalData" ADD COLUMN "whse_id" text DEFAULT '';--> statement-breakpoint
|
||||||
|
ALTER TABLE "invHistoricalData" ADD COLUMN "whse_name" text DEFAULT 'missing whseName';
|
||||||
2298
lstV2/database/migrations/meta/0078_snapshot.json
Normal file
2298
lstV2/database/migrations/meta/0078_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -547,6 +547,13 @@
|
|||||||
"when": 1763407463567,
|
"when": 1763407463567,
|
||||||
"tag": "0077_lucky_texas_twister",
|
"tag": "0077_lucky_texas_twister",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 78,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1766514890344,
|
||||||
|
"tag": "0078_cheerful_the_leader",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,20 +1,20 @@
|
|||||||
import { text, pgTable, timestamp, uuid, jsonb } from "drizzle-orm/pg-core";
|
import { jsonb, pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";
|
||||||
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
|
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const commandLog = pgTable(
|
export const commandLog = pgTable(
|
||||||
"commandLog",
|
"commandLog",
|
||||||
{
|
{
|
||||||
commandLog_id: uuid("commandLog_id").defaultRandom().primaryKey(),
|
commandLog_id: uuid("commandLog_id").defaultRandom().primaryKey(),
|
||||||
commandUsed: text("commandUsed").notNull(),
|
commandUsed: text("commandUsed").notNull(),
|
||||||
bodySent: jsonb("bodySent").default([]),
|
bodySent: jsonb("bodySent").default([]),
|
||||||
reasonUsed: text("reasonUsed"),
|
reasonUsed: text("reasonUsed"),
|
||||||
add_at: timestamp("add_Date").defaultNow(),
|
addDate: timestamp("add_Date").defaultNow(),
|
||||||
},
|
},
|
||||||
(table) => [
|
(table) => [
|
||||||
// uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`),
|
// uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`),
|
||||||
// uniqueIndex("role_name").on(table.name),
|
// uniqueIndex("role_name").on(table.name),
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Schema for inserting a user - can be used to validate API requests
|
// Schema for inserting a user - can be used to validate API requests
|
||||||
|
|||||||
@@ -1,36 +1,38 @@
|
|||||||
import {
|
import {
|
||||||
date,
|
date,
|
||||||
integer,
|
integer,
|
||||||
pgTable,
|
pgTable,
|
||||||
text,
|
text,
|
||||||
timestamp,
|
timestamp,
|
||||||
uuid,
|
uuid,
|
||||||
} from "drizzle-orm/pg-core";
|
} from "drizzle-orm/pg-core";
|
||||||
import { createSelectSchema } from "drizzle-zod";
|
import { createSelectSchema } from "drizzle-zod";
|
||||||
|
|
||||||
export const invHistoricalData = pgTable(
|
export const invHistoricalData = pgTable(
|
||||||
"invHistoricalData",
|
"invHistoricalData",
|
||||||
{
|
{
|
||||||
inv_id: uuid("inv_id").defaultRandom().primaryKey(),
|
inv_id: uuid("inv_id").defaultRandom().primaryKey(),
|
||||||
histDate: date("histDate").notNull(), // this date should always be yesterday when we post it.
|
histDate: date("histDate").notNull(), // this date should always be yesterday when we post it.
|
||||||
plantToken: text("plantToken"),
|
plantToken: text("plantToken"),
|
||||||
article: text("article").notNull(),
|
article: text("article").notNull(),
|
||||||
articleDescription: text("articleDescription").notNull(),
|
articleDescription: text("articleDescription").notNull(),
|
||||||
materialType: text("materialType"),
|
materialType: text("materialType"),
|
||||||
total_QTY: text("total_QTY"),
|
total_QTY: text("total_QTY"),
|
||||||
avaliable_QTY: text("avaliable_QTY"),
|
avaliable_QTY: text("avaliable_QTY"),
|
||||||
coa_QTY: text("coa_QTY"),
|
coa_QTY: text("coa_QTY"),
|
||||||
held_QTY: text("held_QTY"),
|
held_QTY: text("held_QTY"),
|
||||||
lot_Number: text("lot_number"),
|
lot_Number: text("lot_number"),
|
||||||
consignment: text("consignment"),
|
consignment: text("consignment"),
|
||||||
location: text("location"),
|
location: text("location"),
|
||||||
upd_user: text("upd_user").default("lst"),
|
whseId: text("whse_id").default(""),
|
||||||
upd_date: timestamp("upd_date").defaultNow(),
|
whseName: text("whse_name").default("missing whseName"),
|
||||||
}
|
upd_user: text("upd_user").default("lst"),
|
||||||
// (table) => [
|
upd_date: timestamp("upd_date").defaultNow(),
|
||||||
// // uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`),
|
},
|
||||||
// uniqueIndex("role_name").on(table.name),
|
// (table) => [
|
||||||
// ]
|
// // uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`),
|
||||||
|
// uniqueIndex("role_name").on(table.name),
|
||||||
|
// ]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Schema for inserting a user - can be used to validate API requests
|
// Schema for inserting a user - can be used to validate API requests
|
||||||
|
|||||||
@@ -10,7 +10,8 @@
|
|||||||
"dev:dbgen": " drizzle-kit generate --config=drizzle-dev.config.ts",
|
"dev:dbgen": " drizzle-kit generate --config=drizzle-dev.config.ts",
|
||||||
"dev:dbmigrate": " drizzle-kit migrate --config=drizzle-dev.config.ts",
|
"dev:dbmigrate": " drizzle-kit migrate --config=drizzle-dev.config.ts",
|
||||||
"build": "npm run build:server",
|
"build": "npm run build:server",
|
||||||
"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:server": "rimraf dist && tsc --build && npm run copy:scripts && xcopy server\\services\\notifications\\utils\\views\\ dist\\server\\services\\notifications\\utils\\views\\ /E /I /Y && npm run build:copySql",
|
||||||
|
"build:copySql": "xcopy server\\services\\sqlServer\\querys\\newQueries dist\\server\\services\\sqlServer\\querys\\newQueries\\ /E /I /Y ",
|
||||||
"build:frontend": "cd frontend && npm run build",
|
"build:frontend": "cd frontend && npm run build",
|
||||||
"build:iisNet": "rimraf dotnetwrapper\\bin && xcopy frontend\\dist dotnetwrapper\\wwwroot /E /I /Y && cd dotnetwrapper && dotnet publish lst-wrapper.csproj --configuration Release --output ../prodBuild",
|
"build:iisNet": "rimraf dotnetwrapper\\bin && xcopy frontend\\dist dotnetwrapper\\wwwroot /E /I /Y && cd dotnetwrapper && dotnet publish lst-wrapper.csproj --configuration Release --output ../prodBuild",
|
||||||
"copy:scripts": "tsx server/scripts/copyScripts.ts",
|
"copy:scripts": "tsx server/scripts/copyScripts.ts",
|
||||||
|
|||||||
@@ -1,92 +1,94 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
import { createLog } from "../services/logger/logger.js";
|
||||||
import { prodEndpointCreation } from "./createUrl.js";
|
import { prodEndpointCreation } from "./createUrl.js";
|
||||||
import { tryCatch } from "./tryCatch.js";
|
import { tryCatch } from "./tryCatch.js";
|
||||||
import { createLog } from "../services/logger/logger.js";
|
|
||||||
|
|
||||||
type bodyData = any;
|
type bodyData = any;
|
||||||
|
|
||||||
type Data = {
|
type Data = {
|
||||||
endpoint: string;
|
endpoint: string;
|
||||||
data: bodyData[];
|
data: bodyData[];
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* @param timeoutDelay
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
export const runProdApi = async (data: Data) => {
|
export const runProdApi = async (data: Data) => {
|
||||||
/**
|
let url = await prodEndpointCreation(data.endpoint);
|
||||||
* Detachs a silo
|
|
||||||
*/
|
|
||||||
|
|
||||||
let url = await prodEndpointCreation(data.endpoint);
|
const { data: d, error } = await tryCatch(
|
||||||
|
axios.post(url, data.data[0], {
|
||||||
|
headers: {
|
||||||
|
"X-API-Key": process.env.TEC_API_KEY || "",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
const { data: d, error } = await tryCatch(
|
let e = error as any;
|
||||||
axios.post(url, data.data[0], {
|
if (e) {
|
||||||
headers: {
|
//console.log(e.response);
|
||||||
"X-API-Key": process.env.TEC_API_KEY || "",
|
if (e.status === 401) {
|
||||||
"Content-Type": "application/json",
|
createLog(
|
||||||
},
|
"error",
|
||||||
})
|
"lst",
|
||||||
);
|
"logistics",
|
||||||
|
`Not authorized: ${JSON.stringify(e.response?.data)}`,
|
||||||
|
);
|
||||||
|
const data = {
|
||||||
|
success: false,
|
||||||
|
message: `Not authorized: ${JSON.stringify(e.response?.data)}`,
|
||||||
|
data: {
|
||||||
|
status: e.response?.status,
|
||||||
|
statusText: e.response?.statusText,
|
||||||
|
data: e.response?.data,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return data;
|
||||||
|
} else {
|
||||||
|
createLog(
|
||||||
|
"error",
|
||||||
|
"lst",
|
||||||
|
"logistics",
|
||||||
|
`There was an error processing the endpoint: ${JSON.stringify(
|
||||||
|
e.response?.data,
|
||||||
|
)}`,
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: `There was an error processing the endpoint: ${JSON.stringify(
|
||||||
|
e.response?.data,
|
||||||
|
)}`,
|
||||||
|
data: {
|
||||||
|
status: e.response?.status,
|
||||||
|
statusText: e.response?.statusText,
|
||||||
|
data: e.response?.data,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let e = error as any;
|
if (d?.status !== 200) {
|
||||||
if (e) {
|
return {
|
||||||
//console.log(e.response);
|
success: false,
|
||||||
if (e.status === 401) {
|
message: "Error processing endpoint",
|
||||||
createLog(
|
data: {
|
||||||
"error",
|
status: d?.status,
|
||||||
"lst",
|
statusText: d?.statusText,
|
||||||
"logistics",
|
data: d?.data,
|
||||||
`Not autorized: ${JSON.stringify(e.response?.data)}`
|
},
|
||||||
);
|
};
|
||||||
const data = {
|
} else {
|
||||||
success: false,
|
return {
|
||||||
message: `Not autorized: ${JSON.stringify(e.response?.data)}`,
|
success: true,
|
||||||
data: {
|
message: "Endpoint was processed",
|
||||||
status: e.response?.status,
|
data: {
|
||||||
statusText: e.response?.statusText,
|
status: d.status,
|
||||||
data: e.response?.data,
|
statusText: d.statusText,
|
||||||
},
|
data: d.data,
|
||||||
};
|
},
|
||||||
return data;
|
};
|
||||||
} else {
|
}
|
||||||
createLog(
|
|
||||||
"error",
|
|
||||||
"lst",
|
|
||||||
"logistics",
|
|
||||||
`There was an error processing the endpoint: ${JSON.stringify(
|
|
||||||
e.response?.data
|
|
||||||
)}`
|
|
||||||
);
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
message: `There was an error processing the endpoint: ${JSON.stringify(
|
|
||||||
e.response?.data
|
|
||||||
)}`,
|
|
||||||
data: {
|
|
||||||
status: e.response?.status,
|
|
||||||
statusText: e.response?.statusText,
|
|
||||||
data: e.response?.data,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (d?.status !== 200) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
message: "Error processing endpoint",
|
|
||||||
data: {
|
|
||||||
status: d?.status,
|
|
||||||
statusText: d?.statusText,
|
|
||||||
data: d?.data,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
message: "Endpoint was processed",
|
|
||||||
data: {
|
|
||||||
status: d.status,
|
|
||||||
statusText: d.statusText,
|
|
||||||
data: d.data,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|||||||
191
lstV2/server/globalUtils/scannerConnect.ts
Normal file
191
lstV2/server/globalUtils/scannerConnect.ts
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
/**
|
||||||
|
* Using this to make a scanner connection to the server.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import net from "net";
|
||||||
|
|
||||||
|
interface QueuedCommand {
|
||||||
|
command: string;
|
||||||
|
resolve: (value: string) => void;
|
||||||
|
reject: (reason?: any) => void;
|
||||||
|
timeout: NodeJS.Timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
const STX = "\x02";
|
||||||
|
const ETX = "\x03";
|
||||||
|
|
||||||
|
// const prodIP = process.env.SERVER_IP as string;
|
||||||
|
// const prodPort = parseInt(process.env.SCANNER_PORT || "50000", 10);
|
||||||
|
// const scannerID = `${process.env.SCANNER_ID}@`;
|
||||||
|
//const scannerCommand = "AlplaPRODcmd00000042#000028547"; // top of the picksheet
|
||||||
|
|
||||||
|
export class ScannerClient {
|
||||||
|
private socket = new net.Socket();
|
||||||
|
private connected = false;
|
||||||
|
|
||||||
|
private queue: QueuedCommand[] = [];
|
||||||
|
private processing = false;
|
||||||
|
|
||||||
|
private incomingBuffer = "";
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private host: string,
|
||||||
|
private port: number,
|
||||||
|
private scannerId: string,
|
||||||
|
) {
|
||||||
|
this.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private initialize() {
|
||||||
|
if (!this.host || !this.port) {
|
||||||
|
console.log("Host or port is missing");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.socket.connect(this.port, this.host, () => {
|
||||||
|
console.info("Connected to scanner");
|
||||||
|
this.connected = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.socket.on("data", (data) => this.handleData(data));
|
||||||
|
|
||||||
|
this.socket.on("close", () => {
|
||||||
|
console.log("Scanner connection closed");
|
||||||
|
this.connected = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.socket.on("error", (err) => {
|
||||||
|
console.error("Scanner error:", err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ Public method you use
|
||||||
|
public scan(command: string): Promise<string> {
|
||||||
|
if (!this.connected) {
|
||||||
|
return Promise.reject("Scanner not connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
this.processing = false;
|
||||||
|
reject("Scanner timeout");
|
||||||
|
this.processQueue();
|
||||||
|
}, 5000); // 5s safety timeout
|
||||||
|
|
||||||
|
this.queue.push({
|
||||||
|
command,
|
||||||
|
resolve,
|
||||||
|
reject,
|
||||||
|
timeout,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.processQueue();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ Ensures strict FIFO processing
|
||||||
|
private processQueue() {
|
||||||
|
if (this.processing) return;
|
||||||
|
if (this.queue.length === 0) return;
|
||||||
|
|
||||||
|
this.processing = true;
|
||||||
|
|
||||||
|
const current = this.queue[0];
|
||||||
|
const message = Buffer.from(
|
||||||
|
`${STX}${this.scannerId}${current.command}${ETX}`,
|
||||||
|
"ascii",
|
||||||
|
);
|
||||||
|
|
||||||
|
this.socket.write(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ Handles full STX/ETX framed responses
|
||||||
|
private handleData(data: Buffer) {
|
||||||
|
console.log(
|
||||||
|
"ASCII:",
|
||||||
|
data
|
||||||
|
.toString("ascii")
|
||||||
|
.replace(/\x00/g, "") // remove null bytes
|
||||||
|
.replace(/\x1B\[[0-9;?]*[A-Za-z]/g, "") // remove ANSI escape codes
|
||||||
|
.trim(),
|
||||||
|
);
|
||||||
|
|
||||||
|
const current = this.queue.shift();
|
||||||
|
if (current) {
|
||||||
|
clearTimeout(current.timeout);
|
||||||
|
current.resolve(data.toString("ascii"));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.processing = false;
|
||||||
|
this.processQueue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const scanner = new ScannerClient(
|
||||||
|
process.env.SERVER_IP!,
|
||||||
|
parseInt(process.env.SCANNER_PORT!, 10),
|
||||||
|
`${process.env.SCANNER_ID}@`,
|
||||||
|
);
|
||||||
|
|
||||||
|
// export const connectToScanner = () => {
|
||||||
|
// if (!process.env.SERVER_IP || !process.env.SCANNER_PORT) {
|
||||||
|
// return {
|
||||||
|
// success: false,
|
||||||
|
// message: "Missing ServerIP or ServerPort",
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
|
// scanner.connect(prodPort, prodIP, () => {
|
||||||
|
// console.log("Connected to scanner");
|
||||||
|
// connected = true;
|
||||||
|
// });
|
||||||
|
// };
|
||||||
|
|
||||||
|
// export const scan = async (command: string) => {
|
||||||
|
// if (!connected) {
|
||||||
|
// return {
|
||||||
|
// success: false,
|
||||||
|
// message: "Scanner is not connected, please contact admin",
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
// if (inScanCommand) {
|
||||||
|
// bufferCommands.push({ timeStamp: new Date(Date.now()), command: command });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // we are going to set to scanning
|
||||||
|
// inScanCommand = true;
|
||||||
|
|
||||||
|
// const message = Buffer.from(`${STX}${scannerID}${command}${ETX}`, "ascii");
|
||||||
|
// scanner.write(message);
|
||||||
|
// await new Promise((resolve) => setTimeout(resolve, 750));
|
||||||
|
|
||||||
|
// inScanCommand = false;
|
||||||
|
|
||||||
|
// if (bufferCommands.length > 0) {
|
||||||
|
// await scan(bufferCommands[0].command);
|
||||||
|
// bufferCommands.shift();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return {
|
||||||
|
// success: true,
|
||||||
|
// message: "Scan completed",
|
||||||
|
// };
|
||||||
|
// };
|
||||||
|
|
||||||
|
// scanner.on("data", async (data) => {
|
||||||
|
// console.log(
|
||||||
|
// "Response:",
|
||||||
|
// data
|
||||||
|
// .toString("ascii")
|
||||||
|
// .replace(/\x00/g, "") // remove null bytes
|
||||||
|
// .replace(/\x1B\[[0-9;?]*[A-Za-z]/g, "") // remove ANSI escape codes
|
||||||
|
// .trim(),
|
||||||
|
// );
|
||||||
|
// });
|
||||||
|
|
||||||
|
// scanner.on("close", () => {
|
||||||
|
// console.log("Connection closed");
|
||||||
|
// });
|
||||||
|
|
||||||
|
// scanner.on("error", (err) => {
|
||||||
|
// console.error("Scanner error:", err);
|
||||||
|
// });
|
||||||
@@ -253,12 +253,60 @@ process.on("beforeExit", async () => {
|
|||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// const port =
|
||||||
|
// process.env.NODE_ENV === "development"
|
||||||
|
// ? process.env.VITE_SERVER_PORT
|
||||||
|
// : process.env.PROD_PORT;
|
||||||
|
|
||||||
|
// const ocmeport = process.env.OCME_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}`,
|
||||||
|
// );
|
||||||
|
// },
|
||||||
|
// );
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * Only for ocme until we get them switched over to the single port setup.
|
||||||
|
// */
|
||||||
|
// // const setting = await db.select().from(settings);
|
||||||
|
// const setting = serverSettings;
|
||||||
|
// const isActive = setting.filter((n) => n.name === "ocmeService");
|
||||||
|
// if (ocmeport && isActive[0]?.value === "1") {
|
||||||
|
// serve(
|
||||||
|
// {
|
||||||
|
// fetch: app.fetch,
|
||||||
|
// port: Number(ocmeport),
|
||||||
|
// hostname: "0.0.0.0",
|
||||||
|
// },
|
||||||
|
// (info) => {
|
||||||
|
// createLog(
|
||||||
|
// "info",
|
||||||
|
// "LST",
|
||||||
|
// "server",
|
||||||
|
// `Ocme section is listening on http://${info.address}:${info.port}`,
|
||||||
|
// );
|
||||||
|
// },
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
const port =
|
const port =
|
||||||
process.env.NODE_ENV === "development"
|
process.env.NODE_ENV === "development"
|
||||||
? process.env.VITE_SERVER_PORT
|
? process.env.VITE_SERVER_PORT
|
||||||
: process.env.PROD_PORT;
|
: process.env.PROD_PORT;
|
||||||
|
|
||||||
const ocmeport = process.env.OCME_PORT;
|
const ocmeport = process.env.OCME_PORT;
|
||||||
|
|
||||||
serve(
|
serve(
|
||||||
{
|
{
|
||||||
fetch: app.fetch,
|
fetch: app.fetch,
|
||||||
@@ -275,10 +323,6 @@ serve(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
|
||||||
* Only for ocme until we get them switched over to the single port setup.
|
|
||||||
*/
|
|
||||||
// const setting = await db.select().from(settings);
|
|
||||||
const setting = serverSettings;
|
const setting = serverSettings;
|
||||||
const isActive = setting.filter((n) => n.name === "ocmeService");
|
const isActive = setting.filter((n) => n.name === "ocmeService");
|
||||||
if (ocmeport && isActive[0]?.value === "1") {
|
if (ocmeport && isActive[0]?.value === "1") {
|
||||||
|
|||||||
@@ -1,84 +1,95 @@
|
|||||||
|
import { addDays, format } from "date-fns";
|
||||||
|
import { formatInTimeZone } from "date-fns-tz";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import { db } from "../../../../database/dbclient.js";
|
import { db } from "../../../../database/dbclient.js";
|
||||||
import { settings } from "../../../../database/schema/settings.js";
|
import { settings } from "../../../../database/schema/settings.js";
|
||||||
import { tryCatch } from "../../../globalUtils/tryCatch.js";
|
import { tryCatch } from "../../../globalUtils/tryCatch.js";
|
||||||
import { query } from "../../sqlServer/prodSqlServer.js";
|
import { query } from "../../sqlServer/prodSqlServer.js";
|
||||||
import { deliveryByDateRange } from "../../sqlServer/querys/dataMart/deleveryByDateRange.js";
|
import { deliveryByDateRange } from "../../sqlServer/querys/dataMart/deleveryByDateRange.js";
|
||||||
import { addDays, format } from "date-fns";
|
|
||||||
|
|
||||||
export const getDeliveryByDateRange = async (data: any | null) => {
|
export const getDeliveryByDateRange = async (data: any | null) => {
|
||||||
// const { data: plantToken, error: plantError } = await tryCatch(
|
// const { data: plantToken, error: plantError } = await tryCatch(
|
||||||
// db.select().from(settings).where(eq(settings.name, "plantToken"))
|
// db.select().from(settings).where(eq(settings.name, "plantToken"))
|
||||||
// );
|
// );
|
||||||
// if (plantError) {
|
// if (plantError) {
|
||||||
// return {
|
// return {
|
||||||
// success: false,
|
// success: false,
|
||||||
// message: "Error getting Settings",
|
// message: "Error getting Settings",
|
||||||
// data: plantError,
|
// data: plantError,
|
||||||
// };
|
// };
|
||||||
// }
|
// }
|
||||||
let deliverys: any = [];
|
let deliverys: any = [];
|
||||||
|
|
||||||
let updatedQuery = deliveryByDateRange;
|
let updatedQuery = deliveryByDateRange;
|
||||||
|
|
||||||
// start days can be sent over
|
// start days can be sent over
|
||||||
if (data?.start) {
|
if (data?.start) {
|
||||||
updatedQuery = updatedQuery.replaceAll("[startDate]", data.start[0]);
|
updatedQuery = updatedQuery.replaceAll("[startDate]", data.start[0]);
|
||||||
} else {
|
} else {
|
||||||
updatedQuery = updatedQuery.replaceAll("[startDate]", "1990-1-1");
|
updatedQuery = updatedQuery.replaceAll("[startDate]", "1990-1-1");
|
||||||
}
|
}
|
||||||
|
|
||||||
// end days can be sent over
|
// end days can be sent over
|
||||||
if (data?.end) {
|
if (data?.end) {
|
||||||
updatedQuery = updatedQuery.replaceAll("[endDate]", data.end[0]);
|
updatedQuery = updatedQuery.replaceAll("[endDate]", data.end[0]);
|
||||||
} else {
|
} else {
|
||||||
const defaultEndDate = format(
|
const defaultEndDate = format(addDays(new Date(Date.now()), 5), "yyyy-M-d");
|
||||||
addDays(new Date(Date.now()), 5),
|
updatedQuery = updatedQuery.replaceAll("[endDate]", defaultEndDate);
|
||||||
"yyyy-M-d"
|
}
|
||||||
);
|
|
||||||
updatedQuery = updatedQuery.replaceAll("[endDate]", defaultEndDate);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res: any = await query(
|
const res: any = await query(updatedQuery, "Get Delivery by date range");
|
||||||
updatedQuery,
|
deliverys = res.data;
|
||||||
"Get Delivery by date range"
|
//console.log(res.data);
|
||||||
);
|
} catch (error) {
|
||||||
deliverys = res.data;
|
console.log(error);
|
||||||
//console.log(res.data);
|
return {
|
||||||
} catch (error) {
|
success: false,
|
||||||
console.log(error);
|
message: "All Deliveries within the range.",
|
||||||
return {
|
data: error,
|
||||||
success: false,
|
};
|
||||||
message: "All Deliveries within the range.",
|
}
|
||||||
data: error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!data) {
|
// if (!data) {
|
||||||
deliverys = deliverys.splice(1000, 0);
|
// deliverys = deliverys.splice(1000, 0);
|
||||||
}
|
// }
|
||||||
// add plant token in
|
// add plant token in
|
||||||
// const pOrders = deliverys.map((item: any) => {
|
// const pOrders = deliverys.map((item: any) => {
|
||||||
// // const dateCon = new Date(item.loadingDate).toLocaleString("en-US", {
|
// // const dateCon = new Date(item.loadingDate).toLocaleString("en-US", {
|
||||||
// // month: "numeric",
|
// // month: "numeric",
|
||||||
// // day: "numeric",
|
// // day: "numeric",
|
||||||
// // year: "numeric",
|
// // year: "numeric",
|
||||||
// // hour: "2-digit",
|
// // hour: "2-digit",
|
||||||
// // minute: "2-digit",
|
// // minute: "2-digit",
|
||||||
// // hour12: false,
|
// // hour12: false,
|
||||||
// // });
|
// // });
|
||||||
|
|
||||||
// //const dateCon = new Date(item.loadingDate).toISOString().replace("T", " ").split(".")[0];
|
// //const dateCon = new Date(item.loadingDate).toISOString().replace("T", " ").split(".")[0];
|
||||||
// const dateCon = new Date(item.loadingDate).toISOString().split("T")[0];
|
// const dateCon = new Date(item.loadingDate).toISOString().split("T")[0];
|
||||||
// //const delDate = new Date(item.deliveryDate).toISOString().replace("T", " ").split(".")[0];
|
// //const delDate = new Date(item.deliveryDate).toISOString().replace("T", " ").split(".")[0];
|
||||||
// const delDate = new Date(item.deliveryDate).toISOString().split("T")[0];
|
// const delDate = new Date(item.deliveryDate).toISOString().split("T")[0];
|
||||||
// return {
|
// return {
|
||||||
// plantToken: plantToken[0].value,
|
// plantToken: plantToken[0].value,
|
||||||
// ...item,
|
// ...item,
|
||||||
// loadingDate: dateCon,
|
// loadingDate: dateCon,
|
||||||
// deliveryDate: delDate,
|
// deliveryDate: delDate,
|
||||||
// };
|
// };
|
||||||
// });
|
// });
|
||||||
return { success: true, message: "Current open orders", data: deliverys };
|
return {
|
||||||
|
success: true,
|
||||||
|
message: "Current open orders",
|
||||||
|
data: deliverys.map((i: any) => {
|
||||||
|
const orderDate = new Date(i.OrderDate);
|
||||||
|
const delDate = new Date(i.DeliveryDate);
|
||||||
|
const loadDate = new Date(i.LoadingDate);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...i,
|
||||||
|
OrderDate: format(orderDate, "yyyy-MM-dd HH:mm"),
|
||||||
|
DeliveryDate: format(delDate, "yyyy-MM-dd HH:mm"),
|
||||||
|
LoadingDate: format(loadDate, "yyyy-MM-dd HH:mm"),
|
||||||
|
dbDate: i.DeliveryDate,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,84 +1,97 @@
|
|||||||
|
import { addDays, format } from "date-fns";
|
||||||
import { query } from "../../sqlServer/prodSqlServer.js";
|
import { query } from "../../sqlServer/prodSqlServer.js";
|
||||||
import { deliveryByDateRangeAndAv } from "../../sqlServer/querys/dataMart/deleveryByDateRange.js";
|
import { deliveryByDateRangeAndAv } from "../../sqlServer/querys/dataMart/deleveryByDateRange.js";
|
||||||
import { addDays, format } from "date-fns";
|
|
||||||
|
|
||||||
export const getDeliveryByDateRangeAndAv = async (
|
export const getDeliveryByDateRangeAndAv = async (
|
||||||
avs: string,
|
avs: string,
|
||||||
startDate: string,
|
startDate: string,
|
||||||
endDate: string
|
endDate: string,
|
||||||
) => {
|
) => {
|
||||||
// const { data: plantToken, error: plantError } = await tryCatch(
|
// const { data: plantToken, error: plantError } = await tryCatch(
|
||||||
// db.select().from(settings).where(eq(settings.name, "plantToken"))
|
// db.select().from(settings).where(eq(settings.name, "plantToken"))
|
||||||
// );
|
// );
|
||||||
// if (plantError) {
|
// if (plantError) {
|
||||||
// return {
|
// return {
|
||||||
// success: false,
|
// success: false,
|
||||||
// message: "Error getting Settings",
|
// message: "Error getting Settings",
|
||||||
// data: plantError,
|
// data: plantError,
|
||||||
// };
|
// };
|
||||||
// }
|
// }
|
||||||
let deliverys: any = [];
|
let deliverys: any = [];
|
||||||
|
|
||||||
let updatedQuery = deliveryByDateRangeAndAv;
|
let updatedQuery = deliveryByDateRangeAndAv;
|
||||||
|
|
||||||
// start days can be sent over
|
// start days can be sent over
|
||||||
if (startDate) {
|
if (startDate) {
|
||||||
updatedQuery = updatedQuery.replaceAll("[startDate]", startDate);
|
updatedQuery = updatedQuery.replaceAll("[startDate]", startDate);
|
||||||
} else {
|
} else {
|
||||||
updatedQuery = updatedQuery.replaceAll("[startDate]", "1990-1-1");
|
updatedQuery = updatedQuery.replaceAll("[startDate]", "1990-1-1");
|
||||||
}
|
}
|
||||||
|
|
||||||
// end days can be sent over
|
// end days can be sent over
|
||||||
if (endDate) {
|
if (endDate) {
|
||||||
updatedQuery = updatedQuery.replaceAll("[endDate]", endDate);
|
updatedQuery = updatedQuery.replaceAll("[endDate]", endDate);
|
||||||
} else {
|
} else {
|
||||||
const defaultEndDate = format(
|
const defaultEndDate = format(addDays(new Date(Date.now()), 5), "yyyy-M-d");
|
||||||
addDays(new Date(Date.now()), 5),
|
updatedQuery = updatedQuery.replaceAll("[endDate]", defaultEndDate);
|
||||||
"yyyy-M-d"
|
}
|
||||||
);
|
|
||||||
updatedQuery = updatedQuery.replaceAll("[endDate]", defaultEndDate);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res: any = await query(
|
const res: any = await query(
|
||||||
updatedQuery.replace("[articles]", avs),
|
updatedQuery.replace("[articles]", avs),
|
||||||
"Get Delivery by date range"
|
"Get Delivery by date range",
|
||||||
);
|
);
|
||||||
deliverys = res.data;
|
deliverys = res.data;
|
||||||
//console.log(res.data);
|
//console.log(res.data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
message: "All Deliveries within the range.",
|
message: "All Deliveries within the range.",
|
||||||
data: error,
|
data: error,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (!data) {
|
// if (!data) {
|
||||||
// deliverys = deliverys.splice(1000, 0);
|
// deliverys = deliverys.splice(1000, 0);
|
||||||
// }
|
// }
|
||||||
// add plant token in
|
// add plant token in
|
||||||
// const pOrders = deliverys.map((item: any) => {
|
// const pOrders = deliverys.map((item: any) => {
|
||||||
// // const dateCon = new Date(item.loadingDate).toLocaleString("en-US", {
|
// // const dateCon = new Date(item.loadingDate).toLocaleString("en-US", {
|
||||||
// // month: "numeric",
|
// // month: "numeric",
|
||||||
// // day: "numeric",
|
// // day: "numeric",
|
||||||
// // year: "numeric",
|
// // year: "numeric",
|
||||||
// // hour: "2-digit",
|
// // hour: "2-digit",
|
||||||
// // minute: "2-digit",
|
// // minute: "2-digit",
|
||||||
// // hour12: false,
|
// // hour12: false,
|
||||||
// // });
|
// // });
|
||||||
|
|
||||||
// //const dateCon = new Date(item.loadingDate).toISOString().replace("T", " ").split(".")[0];
|
// //const dateCon = new Date(item.loadingDate).toISOString().replace("T", " ").split(".")[0];
|
||||||
// const dateCon = new Date(item.loadingDate).toISOString().split("T")[0];
|
// const dateCon = new Date(item.loadingDate).toISOString().split("T")[0];
|
||||||
// //const delDate = new Date(item.deliveryDate).toISOString().replace("T", " ").split(".")[0];
|
// //const delDate = new Date(item.deliveryDate).toISOString().replace("T", " ").split(".")[0];
|
||||||
// const delDate = new Date(item.deliveryDate).toISOString().split("T")[0];
|
// const delDate = new Date(item.deliveryDate).toISOString().split("T")[0];
|
||||||
// return {
|
// return {
|
||||||
// plantToken: plantToken[0].value,
|
// plantToken: plantToken[0].value,
|
||||||
// ...item,
|
// ...item,
|
||||||
// loadingDate: dateCon,
|
// loadingDate: dateCon,
|
||||||
// deliveryDate: delDate,
|
// deliveryDate: delDate,
|
||||||
// };
|
// };
|
||||||
// });
|
// });
|
||||||
return { success: true, message: "Current open orders", data: deliverys };
|
return {
|
||||||
|
success: true,
|
||||||
|
message: "Current open orders",
|
||||||
|
data: deliverys.map((i: any) => {
|
||||||
|
const orderDate = new Date(i.OrderDate);
|
||||||
|
const delDate = new Date(i.DeliveryDate);
|
||||||
|
const loadDate = new Date(i.LoadingDate);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...i,
|
||||||
|
OrderDate: format(orderDate, "yyyy-MM-dd HH:mm"),
|
||||||
|
DeliveryDate: format(delDate, "yyyy-MM-dd HH:mm"),
|
||||||
|
LoadingDate: format(loadDate, "yyyy-MM-dd HH:mm"),
|
||||||
|
dbDate: i.DeliveryDate,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
import { addDays, format } from "date-fns";
|
||||||
|
import { query } from "../../sqlServer/prodSqlServer.js";
|
||||||
|
import { inhouseDelivery } from "../../sqlServer/querys/dataMart/inhouseDelivery.js";
|
||||||
|
|
||||||
|
export const getInhouseDeliveryByDateRange = async (data: any | null) => {
|
||||||
|
// const { data: plantToken, error: plantError } = await tryCatch(
|
||||||
|
// db.select().from(settings).where(eq(settings.name, "plantToken"))
|
||||||
|
// );
|
||||||
|
// if (plantError) {
|
||||||
|
// return {
|
||||||
|
// success: false,
|
||||||
|
// message: "Error getting Settings",
|
||||||
|
// data: plantError,
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
let deliverys: any = [];
|
||||||
|
|
||||||
|
let updatedQuery = inhouseDelivery;
|
||||||
|
|
||||||
|
// start days can be sent over
|
||||||
|
if (data?.start) {
|
||||||
|
updatedQuery = updatedQuery.replaceAll("[startDate]", data.start[0]);
|
||||||
|
} else {
|
||||||
|
updatedQuery = updatedQuery.replaceAll("[startDate]", "1990-1-1");
|
||||||
|
}
|
||||||
|
|
||||||
|
// end days can be sent over
|
||||||
|
if (data?.end) {
|
||||||
|
updatedQuery = updatedQuery.replaceAll("[endDate]", data.end[0]);
|
||||||
|
} else {
|
||||||
|
const defaultEndDate = format(addDays(new Date(Date.now()), 5), "yyyy-M-d");
|
||||||
|
updatedQuery = updatedQuery.replaceAll("[endDate]", defaultEndDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res: any = await query(
|
||||||
|
updatedQuery,
|
||||||
|
"Get inhouse Delivery by date range",
|
||||||
|
);
|
||||||
|
deliverys = res.data;
|
||||||
|
//console.log(res.data);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: "All In-House Deliveries within the range.",
|
||||||
|
data: error,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
deliverys = deliverys.splice(1000, 0);
|
||||||
|
}
|
||||||
|
// add plant token in
|
||||||
|
// const pOrders = deliverys.map((item: any) => {
|
||||||
|
// // const dateCon = new Date(item.loadingDate).toLocaleString("en-US", {
|
||||||
|
// // month: "numeric",
|
||||||
|
// // day: "numeric",
|
||||||
|
// // year: "numeric",
|
||||||
|
// // hour: "2-digit",
|
||||||
|
// // minute: "2-digit",
|
||||||
|
// // hour12: false,
|
||||||
|
// // });
|
||||||
|
|
||||||
|
// //const dateCon = new Date(item.loadingDate).toISOString().replace("T", " ").split(".")[0];
|
||||||
|
// const dateCon = new Date(item.loadingDate).toISOString().split("T")[0];
|
||||||
|
// //const delDate = new Date(item.deliveryDate).toISOString().replace("T", " ").split(".")[0];
|
||||||
|
// const delDate = new Date(item.deliveryDate).toISOString().split("T")[0];
|
||||||
|
// return {
|
||||||
|
// plantToken: plantToken[0].value,
|
||||||
|
// ...item,
|
||||||
|
// loadingDate: dateCon,
|
||||||
|
// deliveryDate: delDate,
|
||||||
|
// };
|
||||||
|
// });
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: "Current In-House deliveries by range",
|
||||||
|
data: deliverys,
|
||||||
|
};
|
||||||
|
};
|
||||||
52
lstV2/server/services/dataMart/controller/psiForecastData.ts
Normal file
52
lstV2/server/services/dataMart/controller/psiForecastData.ts
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import { format } from "date-fns-tz/format";
|
||||||
|
import { tryCatch } from "../../../globalUtils/tryCatch.js";
|
||||||
|
import { createLog } from "../../logger/logger.js";
|
||||||
|
import { query } from "../../sqlServer/prodSqlServer.js";
|
||||||
|
import { forecastData } from "../../sqlServer/querys/psiReport/forecast.js";
|
||||||
|
|
||||||
|
// type ArticleData = {
|
||||||
|
// id: string
|
||||||
|
// }
|
||||||
|
export const getGetPSIForecastData = async (customer: string) => {
|
||||||
|
let articles: any = [];
|
||||||
|
let queryData = forecastData;
|
||||||
|
console.log(customer);
|
||||||
|
if (customer) {
|
||||||
|
queryData = forecastData.replace("[customer]", customer);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data, error } = (await tryCatch(
|
||||||
|
query(queryData, "PSI forecast info"),
|
||||||
|
)) as any;
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
createLog(
|
||||||
|
"error",
|
||||||
|
"datamart",
|
||||||
|
"datamart",
|
||||||
|
`There was an error getting the forecast info: ${JSON.stringify(error)}`,
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
messsage: `There was an error getting the forecast info`,
|
||||||
|
data: error,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
articles = data.data;
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: "PSI forecast Data",
|
||||||
|
data: articles.map((i: any) => {
|
||||||
|
const requirementDate = new Date(i.requirementDate);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...i,
|
||||||
|
requirementDate: format(requirementDate, "yyyy-MM-dd"),
|
||||||
|
|
||||||
|
dbDate: i.requirementDate,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { and, between, inArray, sql } from "drizzle-orm";
|
import { and, between, inArray, notInArray, sql } from "drizzle-orm";
|
||||||
import { db } from "../../../../database/dbclient.js";
|
import { db } from "../../../../database/dbclient.js";
|
||||||
import { invHistoricalData } from "../../../../database/schema/historicalINV.js";
|
import { invHistoricalData } from "../../../../database/schema/historicalINV.js";
|
||||||
import { tryCatch } from "../../../globalUtils/tryCatch.js";
|
import { tryCatch } from "../../../globalUtils/tryCatch.js";
|
||||||
@@ -8,56 +8,79 @@ import { createLog } from "../../logger/logger.js";
|
|||||||
// id: string
|
// id: string
|
||||||
// }
|
// }
|
||||||
export const psiGetInventory = async (
|
export const psiGetInventory = async (
|
||||||
avs: string,
|
avs: string,
|
||||||
startDate: string,
|
startDate: string,
|
||||||
endDate: string
|
endDate: string,
|
||||||
|
whseToInclude: string,
|
||||||
|
exludeLanes: string
|
||||||
) => {
|
) => {
|
||||||
let articles: any = [];
|
let articles: any = [];
|
||||||
|
|
||||||
if (!avs) {
|
if (!avs) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
message: `Missing av's please send at least one over`,
|
message: `Missing av's please send at least one over`,
|
||||||
data: [],
|
data: [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const ids = avs.split(",").map((id) => id.trim());
|
const ids = avs.split(",").map((id) => id.trim());
|
||||||
|
const whse = whseToInclude
|
||||||
|
? whseToInclude
|
||||||
|
.split(",")
|
||||||
|
.map((w) => w.trim())
|
||||||
|
.filter(Boolean)
|
||||||
|
: [];
|
||||||
|
|
||||||
const { data, error } = (await tryCatch(
|
const locations = exludeLanes
|
||||||
db
|
? exludeLanes.split(",").map((l) => l.trim()).filter(Boolean)
|
||||||
.select()
|
: [];
|
||||||
.from(invHistoricalData)
|
|
||||||
.where(
|
|
||||||
and(
|
|
||||||
inArray(invHistoricalData.article, ids),
|
|
||||||
between(invHistoricalData.histDate, startDate, endDate)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
//.limit(100)
|
|
||||||
)) as any;
|
|
||||||
|
|
||||||
if (error) {
|
const conditions = [
|
||||||
createLog(
|
inArray(invHistoricalData.article, ids),
|
||||||
"error",
|
between(invHistoricalData.histDate, startDate, endDate),
|
||||||
"datamart",
|
];
|
||||||
"datamart",
|
|
||||||
`There was an error getting the planning info: ${JSON.stringify(
|
|
||||||
error
|
|
||||||
)}`
|
|
||||||
);
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
messsage: `There was an error getting the planning info`,
|
|
||||||
data: error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
articles = data;
|
// only add the warehouse condition if there are any whse values
|
||||||
console.log(articles.length);
|
if (whse.length > 0) {
|
||||||
return {
|
console.log("adding whse to include in");
|
||||||
success: true,
|
conditions.push(inArray(invHistoricalData.whseId, whse));
|
||||||
message: "PSI planning Data",
|
}
|
||||||
data: articles,
|
|
||||||
};
|
// locations we dont want in the system
|
||||||
|
if (locations.length > 0) {
|
||||||
|
console.log("adding excluded lanes in ",locations);
|
||||||
|
|
||||||
|
conditions.push(notInArray(invHistoricalData.location, locations));
|
||||||
|
}
|
||||||
|
|
||||||
|
const query = db
|
||||||
|
.select()
|
||||||
|
.from(invHistoricalData)
|
||||||
|
.where(and(...conditions));
|
||||||
|
|
||||||
|
// optional tryCatch or await as you had
|
||||||
|
const { data, error } = (await tryCatch(query)) as any;
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
createLog(
|
||||||
|
"error",
|
||||||
|
"datamart",
|
||||||
|
"datamart",
|
||||||
|
`There was an error getting the planning info: ${JSON.stringify(error)}`,
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
messsage: `There was an error getting the planning info`,
|
||||||
|
data: error,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
articles = data;
|
||||||
|
console.log(articles.length);
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: "PSI planning Data",
|
||||||
|
data: articles,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,62 +2,72 @@ import { tryCatch } from "../../../globalUtils/tryCatch.js";
|
|||||||
import { createLog } from "../../logger/logger.js";
|
import { createLog } from "../../logger/logger.js";
|
||||||
import { query } from "../../sqlServer/prodSqlServer.js";
|
import { query } from "../../sqlServer/prodSqlServer.js";
|
||||||
import { planningNumbersByAVDate } from "../../sqlServer/querys/psiReport/planningNumbersByAv.js";
|
import { planningNumbersByAVDate } from "../../sqlServer/querys/psiReport/planningNumbersByAv.js";
|
||||||
|
import { improvedPsiPlanningInfo } from "./psiPlanningDataImproved.js";
|
||||||
|
|
||||||
// type ArticleData = {
|
// type ArticleData = {
|
||||||
// id: string
|
// id: string
|
||||||
// }
|
// }
|
||||||
export const psiGetPlanningData = async (
|
export const psiGetPlanningData = async (
|
||||||
avs: string,
|
avs: string,
|
||||||
startDate: string,
|
startDate: string,
|
||||||
endDate: string
|
endDate: string,
|
||||||
) => {
|
) => {
|
||||||
let articles: any = [];
|
let articles: any = [];
|
||||||
|
|
||||||
if (!avs) {
|
if (!avs) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
message: `Missing av's please send at least one over`,
|
message: `Missing av's please send at least one over`,
|
||||||
data: [],
|
data: [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const { data, error } = (await tryCatch(
|
const { data, error } = (await tryCatch(
|
||||||
query(
|
query(
|
||||||
planningNumbersByAVDate
|
planningNumbersByAVDate
|
||||||
.replace("[articles]", avs)
|
.replace("[articles]", avs)
|
||||||
.replace("[startDate]", startDate)
|
.replace("[startDate]", startDate)
|
||||||
.replace("[endDate]", endDate),
|
.replace("[endDate]", endDate),
|
||||||
"PSI planning info"
|
"PSI planning info",
|
||||||
)
|
),
|
||||||
)) as any;
|
)) as any;
|
||||||
|
|
||||||
if (error) {
|
// improvedPsiPlanningInfo({
|
||||||
createLog(
|
// avs,
|
||||||
"error",
|
// startDate,
|
||||||
"datamart",
|
// endDate,
|
||||||
"datamart",
|
// });
|
||||||
`There was an error getting the planning info: ${JSON.stringify(
|
if (error) {
|
||||||
error
|
createLog(
|
||||||
)}`
|
"error",
|
||||||
);
|
"datamart",
|
||||||
return {
|
"datamart",
|
||||||
success: false,
|
`There was an error getting the planning info: ${JSON.stringify(error)}`,
|
||||||
messsage: `There was an error getting the planning info`,
|
);
|
||||||
data: error,
|
return {
|
||||||
};
|
success: false,
|
||||||
}
|
messsage: `There was an error getting the planning info`,
|
||||||
|
data: error,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
articles = data.data;
|
// TODO: if we are not running planning we no pass the old structure if we are running new planning use the below improved version that makes sure we dont have negative numebrs.
|
||||||
|
articles = data.data;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
message: "PSI planning Data",
|
message: "PSI planning Data",
|
||||||
data: articles.map((n: any) => {
|
data: await improvedPsiPlanningInfo({
|
||||||
if (n.PalDay) {
|
avs,
|
||||||
return { ...n, PalDay: n.PalDay.toFixed(2) };
|
startDate,
|
||||||
}
|
endDate,
|
||||||
|
}),
|
||||||
|
// data: articles.map((n: any) => {
|
||||||
|
// if (n.PalDay) {
|
||||||
|
// return { ...n, PalDay: n.PalDay.toFixed(2) };
|
||||||
|
// }
|
||||||
|
|
||||||
return n;
|
// return n;
|
||||||
}),
|
// }),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,171 @@
|
|||||||
|
import { format } from "date-fns-tz";
|
||||||
|
import { tryCatch } from "../../../globalUtils/tryCatch.js";
|
||||||
|
import { query } from "../../sqlServer/prodSqlServer.js";
|
||||||
|
|
||||||
|
const improvedQuery = `
|
||||||
|
|
||||||
|
DECLARE @StartDate DATE = '[startDate]' -- 2025-1-1
|
||||||
|
DECLARE @EndDate DATE = '[endDate]' -- 2025-1-31
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
[RunningNumber] as lot
|
||||||
|
,[ProfitCentreDescription]
|
||||||
|
,[MachineDescription]
|
||||||
|
,[ArticleHumanReadableId]
|
||||||
|
,[ArticleDescription]
|
||||||
|
,[DeliveryAddressHumanReadableId]
|
||||||
|
,[DeliveryAddressDescription]
|
||||||
|
,[MouldHumanReadableId]
|
||||||
|
,[BlowheadHumanReadableId1]
|
||||||
|
,[PackagingInstructionHumanReadableId]
|
||||||
|
,[PackagingInstructionDescription]
|
||||||
|
,[MainMaterialHumanReadableId]
|
||||||
|
,[MainMaterialDescription]
|
||||||
|
,[CompoundHumanReadableId]
|
||||||
|
,[CompoundDescription]
|
||||||
|
,[ProductionLotState]
|
||||||
|
,[PlanType]
|
||||||
|
,[ProducedQuantityLoadingUnit]
|
||||||
|
,[ProducedQuantityPieces]
|
||||||
|
,[PlanStart]
|
||||||
|
,[PlanEnd]
|
||||||
|
,[ProdStart]
|
||||||
|
,[TheoreticEnd]
|
||||||
|
,[ProdDuration]
|
||||||
|
,[SetupDuration]
|
||||||
|
,[StartupDuration]
|
||||||
|
|
||||||
|
,[NetEquipmentEfficiency]
|
||||||
|
,[UtilisationDuration]
|
||||||
|
,[CycleTime]
|
||||||
|
,[Cavities]
|
||||||
|
,[FixedQuantity]
|
||||||
|
,[ProducedQuantityTrucks]
|
||||||
|
,[ProducedQuantityTradeUnit]
|
||||||
|
,[MaxRegrind]
|
||||||
|
,[Conflict]
|
||||||
|
,[ProductionOrderHumanReadableId]
|
||||||
|
,[ProductionDataImportSource]
|
||||||
|
,[Remark]
|
||||||
|
,[BlowheadDescription1]
|
||||||
|
,[MouldDescription]
|
||||||
|
,[ProcessLossPercentage]
|
||||||
|
,[SetupTypeNumberOfPersons]
|
||||||
|
,[UnplannedDowntimePercentage]
|
||||||
|
,[PlanQuantityLoadingUnit]
|
||||||
|
,[PlanQuantityPieces]
|
||||||
|
,[PlanQuantityTradeUnit]
|
||||||
|
,[PlanQuantityTrucks]
|
||||||
|
,[PublishState]
|
||||||
|
,[LastChange]
|
||||||
|
,[MaterialConsumed]
|
||||||
|
,[MaterialStaged]
|
||||||
|
,[MachineLocation]
|
||||||
|
,[HasPrioritization]
|
||||||
|
,[ArticleAlias]
|
||||||
|
|
||||||
|
FROM [test1_AlplaPROD2.0_Read].[productionScheduling].[ProductionLot] with (nolock)
|
||||||
|
where PlanEnd between @StartDate and @EndDate
|
||||||
|
and ArticleHumanReadableId in ([articles])
|
||||||
|
and PublishState = 1
|
||||||
|
order by PlanStart
|
||||||
|
|
||||||
|
`;
|
||||||
|
export const improvedPsiPlanningInfo = async (something: any) => {
|
||||||
|
const { data, error } = (await tryCatch(
|
||||||
|
query(
|
||||||
|
improvedQuery
|
||||||
|
.replace("[articles]", something.avs)
|
||||||
|
.replace("[startDate]", something.startDate)
|
||||||
|
.replace("[endDate]", something.endDate),
|
||||||
|
"PSI planning info",
|
||||||
|
),
|
||||||
|
)) as any;
|
||||||
|
|
||||||
|
// add error handling in later here
|
||||||
|
|
||||||
|
return splitProduction(data.data);
|
||||||
|
};
|
||||||
|
|
||||||
|
const splitProduction = (runs: any) => {
|
||||||
|
const results: any = [];
|
||||||
|
const WORKDAY_START_HOUR = 7; // 07:00 start well later get this from the shift def
|
||||||
|
|
||||||
|
runs.forEach((e: any) => {
|
||||||
|
const {
|
||||||
|
PlanStart,
|
||||||
|
PlanEnd,
|
||||||
|
PlanQuantityPieces,
|
||||||
|
ArticleHumanReadableId,
|
||||||
|
ProdDuration,
|
||||||
|
} = e;
|
||||||
|
|
||||||
|
const prodStart: any = new Date(PlanStart);
|
||||||
|
const prodEnd: any = new Date(PlanEnd);
|
||||||
|
const prodDuration = ProdDuration
|
||||||
|
? ProdDuration * 60 * 60 * 1000
|
||||||
|
: prodEnd - prodStart;
|
||||||
|
|
||||||
|
// get the prod date the production falls under
|
||||||
|
function getProdDayStart(date: Date) {
|
||||||
|
const d = new Date(date);
|
||||||
|
d.setHours(WORKDAY_START_HOUR, 0, 0, 0);
|
||||||
|
|
||||||
|
if (date.getHours() < WORKDAY_START_HOUR) {
|
||||||
|
// before 07:00, belongs to previous calendar day
|
||||||
|
d.setDate(d.getDate() - 1);
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
// current pointer starts at the work-day start that contains our start time
|
||||||
|
let currentStart = new Date(prodStart);
|
||||||
|
let prodDayStart = getProdDayStart(currentStart);
|
||||||
|
|
||||||
|
while (prodDayStart < prodEnd) {
|
||||||
|
// 1️⃣ The next day’s start = prodDayStart + 1 day at 07:00
|
||||||
|
const nextProdDayStart = new Date(prodDayStart);
|
||||||
|
nextProdDayStart.setDate(nextProdDayStart.getDate() + 1);
|
||||||
|
|
||||||
|
// 2️⃣ Segment end is either the next work-day start or the actual end, whichever is sooner
|
||||||
|
const segmentEnd = new Date(
|
||||||
|
Math.min(nextProdDayStart.getTime(), prodEnd.getTime()),
|
||||||
|
);
|
||||||
|
|
||||||
|
// 3️⃣ Determine overlap window within (startTime..endTime)
|
||||||
|
const segStart: any = new Date(
|
||||||
|
Math.max(prodDayStart.getTime(), prodStart.getTime()),
|
||||||
|
);
|
||||||
|
const segEnd: any = segmentEnd;
|
||||||
|
|
||||||
|
if (segEnd > segStart) {
|
||||||
|
const segMs = segEnd - segStart;
|
||||||
|
const proportion = segMs / prodDuration;
|
||||||
|
const qty = PlanQuantityPieces * proportion;
|
||||||
|
const pal = e.PlanQuantityLoadingUnit * proportion;
|
||||||
|
|
||||||
|
results.push({
|
||||||
|
Article: ArticleHumanReadableId,
|
||||||
|
Description: e.ArticleAlias,
|
||||||
|
MachineId: e.MachineLocation,
|
||||||
|
MachineName: e.MachineDescription,
|
||||||
|
LotNumber: e.lot,
|
||||||
|
ProductionDay: format(prodDayStart, "M/d/yyyy"),
|
||||||
|
TotalPlanned: e.PlanQuantityPieces,
|
||||||
|
// PlanEnd,
|
||||||
|
// TheoreticEnd,
|
||||||
|
QTYPerDay: parseInt(qty.toFixed(0)),
|
||||||
|
PalDay: parseFloat(pal.toFixed(2)),
|
||||||
|
finished: e.ProductionLotState === 3 ? 1 : 0,
|
||||||
|
cavities: e.Cavities,
|
||||||
|
//prodDuration,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// move to next production-day window
|
||||||
|
prodDayStart = nextProdDayStart;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return results;
|
||||||
|
};
|
||||||
@@ -1,43 +1,48 @@
|
|||||||
import { OpenAPIHono } from "@hono/zod-openapi";
|
import { OpenAPIHono } from "@hono/zod-openapi";
|
||||||
import activequerys from "./route/getCurrentQuerys.js";
|
|
||||||
import getArticles from "./route/getActiveArticles.js";
|
|
||||||
import currentInv from "./route/getInventory.js";
|
|
||||||
import getCustomerInv from "./route/getCustomerInv.js";
|
|
||||||
import getOpenOrders from "./route/getOpenOrders.js";
|
|
||||||
import getDeliveryByDate from "./route/getDeliveryDateByRange.js";
|
|
||||||
import fakeEDI from "./route/fakeEDI.js";
|
import fakeEDI from "./route/fakeEDI.js";
|
||||||
|
import getArticles from "./route/getActiveArticles.js";
|
||||||
import addressCorrections from "./route/getCityStateData.js";
|
import addressCorrections from "./route/getCityStateData.js";
|
||||||
|
import activequerys from "./route/getCurrentQuerys.js";
|
||||||
|
import getCustomerInv from "./route/getCustomerInv.js";
|
||||||
|
import getDeliveryByDate from "./route/getDeliveryDateByRange.js";
|
||||||
|
import getDeliveryByDateRangeAndAv from "./route/getDeliveryDateByRangeAndAv.js";
|
||||||
import fifoIndex from "./route/getFifoIndex.js";
|
import fifoIndex from "./route/getFifoIndex.js";
|
||||||
import financeAudit from "./route/getFinanceAudit.js";
|
import financeAudit from "./route/getFinanceAudit.js";
|
||||||
|
import getForecastByAv from "./route/getForecastDataByAv.js";
|
||||||
|
import getInhouseDeliveryByDate from "./route/getInHouseDeliveryDateByRange.js";
|
||||||
|
import currentInv from "./route/getInventory.js";
|
||||||
|
import getOpenOrders from "./route/getOpenOrders.js";
|
||||||
import psiArticleData from "./route/getPsiArticleData.js";
|
import psiArticleData from "./route/getPsiArticleData.js";
|
||||||
|
import psiForecastData from "./route/getPsiForecast.js";
|
||||||
|
import psiInventory from "./route/getPsiinventory.js";
|
||||||
import psiPlanningData from "./route/getPsiPlanningData.js";
|
import psiPlanningData from "./route/getPsiPlanningData.js";
|
||||||
import psiProductionData from "./route/getPsiProductionData.js";
|
import psiProductionData from "./route/getPsiProductionData.js";
|
||||||
import psiInventory from "./route/getPsiinventory.js";
|
|
||||||
import getForecastByAv from "./route/getForecastDataByAv.js";
|
|
||||||
import getDeliveryByDateRangeAndAv from "./route/getDeliveryDateByRangeAndAv.js";
|
|
||||||
const app = new OpenAPIHono();
|
const app = new OpenAPIHono();
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
activequerys,
|
activequerys,
|
||||||
getArticles,
|
getArticles,
|
||||||
currentInv,
|
currentInv,
|
||||||
getCustomerInv,
|
getCustomerInv,
|
||||||
getOpenOrders,
|
getOpenOrders,
|
||||||
getDeliveryByDate,
|
getDeliveryByDate,
|
||||||
getDeliveryByDateRangeAndAv,
|
getInhouseDeliveryByDate,
|
||||||
getForecastByAv,
|
getDeliveryByDateRangeAndAv,
|
||||||
fakeEDI,
|
getForecastByAv,
|
||||||
addressCorrections,
|
fakeEDI,
|
||||||
fifoIndex,
|
addressCorrections,
|
||||||
financeAudit,
|
fifoIndex,
|
||||||
psiArticleData,
|
financeAudit,
|
||||||
psiPlanningData,
|
psiArticleData,
|
||||||
psiProductionData,
|
psiPlanningData,
|
||||||
psiInventory,
|
psiProductionData,
|
||||||
|
psiInventory,
|
||||||
|
psiForecastData,
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
const appRoutes = routes.forEach((route) => {
|
const appRoutes = routes.forEach((route) => {
|
||||||
app.route("/datamart", route);
|
app.route("/datamart", route);
|
||||||
});
|
});
|
||||||
|
|
||||||
export default app;
|
export default app;
|
||||||
|
|||||||
@@ -1,146 +1,153 @@
|
|||||||
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
|
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
|
||||||
import { responses } from "../../../globalUtils/routeDefs/responses.js";
|
|
||||||
import { apiHit } from "../../../globalUtils/apiHits.js";
|
import { apiHit } from "../../../globalUtils/apiHits.js";
|
||||||
|
import { responses } from "../../../globalUtils/routeDefs/responses.js";
|
||||||
|
|
||||||
const app = new OpenAPIHono({ strict: false });
|
const app = new OpenAPIHono({ strict: false });
|
||||||
const current: any = [
|
const current: any = [
|
||||||
{
|
{
|
||||||
name: "getActiveAv",
|
name: "getActiveAv",
|
||||||
endpoint: "/api/datamart/getarticles",
|
endpoint: "/api/datamart/getarticles",
|
||||||
description: "Gets all current active AV, with specific critiera.",
|
description: "Gets all current active AV, with specific critiera.",
|
||||||
},
|
},
|
||||||
// {
|
// {
|
||||||
// name: "getStockLaneDims",
|
// name: "getStockLaneDims",
|
||||||
// endpoint: "/api/v1/masterData/getStockDims",
|
// endpoint: "/api/v1/masterData/getStockDims",
|
||||||
// description: "Returns the lane dims along with a column to send actaul dims to be updated.",
|
// description: "Returns the lane dims along with a column to send actaul dims to be updated.",
|
||||||
// },
|
// },
|
||||||
// {
|
// {
|
||||||
// name: "getAddressInfo",
|
// name: "getAddressInfo",
|
||||||
// endpoint: "/api/v1/masterData/getAddressInfo",
|
// endpoint: "/api/v1/masterData/getAddressInfo",
|
||||||
// description: "Returns current active addresses with street and zip",
|
// description: "Returns current active addresses with street and zip",
|
||||||
// },
|
// },
|
||||||
// {
|
// {
|
||||||
// name: "getMissingPkgData",
|
// name: "getMissingPkgData",
|
||||||
// endpoint: "/api/v1/masterData/getMissingPKGData",
|
// endpoint: "/api/v1/masterData/getMissingPKGData",
|
||||||
// description: "Returns all packaging data that is missing either printer, layout, or carton layout",
|
// description: "Returns all packaging data that is missing either printer, layout, or carton layout",
|
||||||
// },
|
// },
|
||||||
{
|
{
|
||||||
name: "getCustomerInventory",
|
name: "getCustomerInventory",
|
||||||
endpoint: "/api/datamart/getcustomerinventory",
|
endpoint: "/api/datamart/getcustomerinventory",
|
||||||
description:
|
description:
|
||||||
"Returns specific customer inventory based on there address ID, with optional to include warehouses, IE 36,41,5. leaving warehouse blank will just pull everything",
|
"Returns specific customer inventory based on there address ID, with optional to include warehouses, IE 36,41,5. leaving warehouse blank will just pull everything",
|
||||||
criteria: "customer,whseToInclude",
|
criteria: "customer,whseToInclude",
|
||||||
},
|
},
|
||||||
// {
|
// {
|
||||||
// name: "getPalletLabels",
|
// name: "getPalletLabels",
|
||||||
// endpoint: "/api/v1/masterData/getPalletLabels",
|
// endpoint: "/api/v1/masterData/getPalletLabels",
|
||||||
// description: "Returns specific amount of pallets RN, Needs label number and printer, Specfic to Dayton.",
|
// description: "Returns specific amount of pallets RN, Needs label number and printer, Specfic to Dayton.",
|
||||||
// criteria: "runningNumber,printerName,count",
|
// criteria: "runningNumber,printerName,count",
|
||||||
// },
|
// },
|
||||||
{
|
{
|
||||||
name: "getopenorders",
|
name: "getopenorders",
|
||||||
endpoint: "/api/datamart/getopenorders",
|
endpoint: "/api/datamart/getopenorders",
|
||||||
description:
|
description:
|
||||||
"Returns open orders based on day count sent over, sDay 15 days in the past eDay 5 days in the future, can be left empty for this default days",
|
"Returns open orders based on day count sent over, sDay 15 days in the past eDay 5 days in the future, can be left empty for this default days",
|
||||||
criteria: "sDay,eDay",
|
criteria: "sDay,eDay",
|
||||||
},
|
},
|
||||||
// {
|
// {
|
||||||
// name: "getOpenIncoming",
|
// name: "getOpenIncoming",
|
||||||
// endpoint: "/api/v1/masterData/getOpenIncoming",
|
// endpoint: "/api/v1/masterData/getOpenIncoming",
|
||||||
// description:
|
// description:
|
||||||
// "Returns open orders based on day count sent over, sDay 15 days in the past eDay 5 days in the future, can be left empty for this default days",
|
// "Returns open orders based on day count sent over, sDay 15 days in the past eDay 5 days in the future, can be left empty for this default days",
|
||||||
// criteria: "sDay,eDay",
|
// criteria: "sDay,eDay",
|
||||||
// },
|
// },
|
||||||
// {
|
// {
|
||||||
// name: "planningCheckPkg",
|
// name: "planningCheckPkg",
|
||||||
// endpoint: "/api/v1/masterData/planningPkgCheck",
|
// endpoint: "/api/v1/masterData/planningPkgCheck",
|
||||||
// description: "Returns all lots starting later than today and has a pkg that is missing layouts.",
|
// description: "Returns all lots starting later than today and has a pkg that is missing layouts.",
|
||||||
// },
|
// },
|
||||||
{
|
{
|
||||||
name: "getinventory",
|
name: "getinventory",
|
||||||
endpoint: "/api/datamart/getinventory",
|
endpoint: "/api/datamart/getinventory",
|
||||||
// description: "Returns all inventory, by default excludes running numebrs, also excludes inv locations.",
|
// description: "Returns all inventory, by default excludes running numebrs, also excludes inv locations.",
|
||||||
description:
|
description:
|
||||||
"Returns all inventory, excludes inv locations. no running numbers",
|
"Returns all inventory, excludes inv locations. no running numbers",
|
||||||
criteria: "includeRunnningNumbers", // uncomment this out once the improt process can be faster
|
criteria: "includeRunnningNumbers", // uncomment this out once the improt process can be faster
|
||||||
},
|
},
|
||||||
// {
|
// {
|
||||||
// name: "getOpenOrderUpdates",
|
// name: "getOpenOrderUpdates",
|
||||||
// endpoint: "/api/v1/masterData/getOpenOrderUpdates",
|
// endpoint: "/api/v1/masterData/getOpenOrderUpdates",
|
||||||
// // description: "Returns all inventory, by default excludes running numebrs, also excludes inv locations.",
|
// // description: "Returns all inventory, by default excludes running numebrs, also excludes inv locations.",
|
||||||
// description: "Returns all orders based on customer id, leaving empty will pull everythinng in.",
|
// description: "Returns all orders based on customer id, leaving empty will pull everythinng in.",
|
||||||
// criteria: "customer", // uncomment this out once the improt process can be faster
|
// criteria: "customer", // uncomment this out once the improt process can be faster
|
||||||
// },
|
// },
|
||||||
{
|
{
|
||||||
name: "getSiloAdjustment",
|
name: "getSiloAdjustment",
|
||||||
endpoint: "/api/logistics/getsilosdjustment",
|
endpoint: "/api/logistics/getsilosdjustment",
|
||||||
// description: "Returns all inventory, by default excludes running numebrs, also excludes inv locations.",
|
// description: "Returns all inventory, by default excludes running numebrs, also excludes inv locations.",
|
||||||
description:
|
description:
|
||||||
"Returns all siloadjustments in selected date range IE: 1/1/2025 to 1/31/2025",
|
"Returns all siloadjustments in selected date range IE: 1/1/2025 to 1/31/2025",
|
||||||
criteria: "startDate,endDate", // uncomment this out once the improt process can be faster
|
criteria: "startDate,endDate", // uncomment this out once the improt process can be faster
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Delivery by date trange",
|
name: "Delivery by date range",
|
||||||
endpoint: "/api/datamart/deliverybydaterange",
|
endpoint: "/api/datamart/deliverybydaterange",
|
||||||
// description: "Returns all inventory, by default excludes running numebrs, also excludes inv locations.",
|
// description: "Returns all inventory, by default excludes running numebrs, also excludes inv locations.",
|
||||||
description:
|
description:
|
||||||
"Returns all Deliverys in selected date range IE: 1/1/2025 to 1/31/2025",
|
"Returns all Deliverys in selected date range IE: 1/1/2025 to 1/31/2025",
|
||||||
criteria: "start,end", // uncomment this out once the improt process can be faster
|
criteria: "start,end", // uncomment this out once the improt process can be faster
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Fake Edi Update",
|
name: "In House Delivery by date range",
|
||||||
endpoint: "/api/datamart/fakeediupdate",
|
endpoint: "/api/datamart/inhousedeliverybydaterange",
|
||||||
// description: "Returns all inventory, by default excludes running numebrs, also excludes inv locations.",
|
// description: "Returns all inventory, by default excludes running numebrs, also excludes inv locations.",
|
||||||
description:
|
description:
|
||||||
"Returns all open orders to correct and resubmit, leaving blank will get everything putting an address only returns the specified address",
|
"Returns all in-house deliveries in selected date range IE: 1/1/2025 to 1/31/2025",
|
||||||
criteria: "address", // uncomment this out once the improt process can be faster
|
criteria: "start,end", // uncomment this out once the improt process can be faster
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Address Corrections",
|
name: "Fake Edi Update",
|
||||||
endpoint: "/api/datamart/getaddressdata",
|
endpoint: "/api/datamart/fakeediupdate",
|
||||||
// description: "Returns all inventory, by default excludes running numebrs, also excludes inv locations.",
|
// description: "Returns all inventory, by default excludes running numebrs, also excludes inv locations.",
|
||||||
description:
|
description:
|
||||||
"Returns all addresses that will not process correctly in tms due to incorrect city state setup.",
|
"Returns all open orders to correct and resubmit, leaving blank will get everything putting an address only returns the specified address",
|
||||||
//criteria: "address", // uncomment this out once the improt process can be faster
|
criteria: "address", // uncomment this out once the improt process can be faster
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Fifo index",
|
name: "Address Corrections",
|
||||||
endpoint: "/api/datamart/getfifoindex",
|
endpoint: "/api/datamart/getaddressdata",
|
||||||
// description: "Returns all inventory, by default excludes running numebrs, also excludes inv locations.",
|
// description: "Returns all inventory, by default excludes running numebrs, also excludes inv locations.",
|
||||||
description:
|
description:
|
||||||
"Returns fifo index for all pallets shipped within the last 90 days.",
|
"Returns all addresses that will not process correctly in tms due to incorrect city state setup.",
|
||||||
//criteria: "address", // uncomment this out once the improt process can be faster
|
//criteria: "address", // uncomment this out once the improt process can be faster
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Finance Audit inv",
|
name: "Fifo index",
|
||||||
endpoint: "/api/datamart/getfinanceaudit",
|
endpoint: "/api/datamart/getfifoindex",
|
||||||
// description: "Returns all inventory, by default excludes running numebrs, also excludes inv locations.",
|
// description: "Returns all inventory, by default excludes running numebrs, also excludes inv locations.",
|
||||||
description:
|
description:
|
||||||
"Returns all inventory past the date provided, ie: 5/31/2025",
|
"Returns fifo index for all pallets shipped within the last 90 days.",
|
||||||
criteria: "date", // uncomment this out once the improt process can be faster
|
//criteria: "address", // uncomment this out once the improt process can be faster
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "Finance Audit inv",
|
||||||
|
endpoint: "/api/datamart/getfinanceaudit",
|
||||||
|
// description: "Returns all inventory, by default excludes running numebrs, also excludes inv locations.",
|
||||||
|
description: "Returns all inventory past the date provided, ie: 5/31/2025",
|
||||||
|
criteria: "date", // uncomment this out once the improt process can be faster
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
app.openapi(
|
app.openapi(
|
||||||
createRoute({
|
createRoute({
|
||||||
tags: ["dataMart"],
|
tags: ["dataMart"],
|
||||||
summary: "Returns all avalible querys.",
|
summary: "Returns all avalible querys.",
|
||||||
method: "get",
|
method: "get",
|
||||||
path: "/getavalibleaquerys",
|
path: "/getavalibleaquerys",
|
||||||
|
|
||||||
responses: responses(),
|
responses: responses(),
|
||||||
}),
|
}),
|
||||||
async (c) => {
|
async (c) => {
|
||||||
//const body = await c.req.json();
|
//const body = await c.req.json();
|
||||||
// make sure we have a vaid user being accessed thats really logged in
|
// make sure we have a vaid user being accessed thats really logged in
|
||||||
apiHit(c, { endpoint: "/getavalibleaquerys" });
|
apiHit(c, { endpoint: "/getavalibleaquerys" });
|
||||||
|
|
||||||
return c.json({
|
return c.json({
|
||||||
success: true,
|
success: true,
|
||||||
message: "All Current Active Querys.",
|
message: "All Current Active Querys.",
|
||||||
sheetVersion: 2.8,
|
sheetVersion: 2.8, // TODO: when this gets switched change this
|
||||||
data: current,
|
data: current,
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
export default app;
|
export default app;
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
|
||||||
|
import { apiHit } from "../../../globalUtils/apiHits.js";
|
||||||
|
import { responses } from "../../../globalUtils/routeDefs/responses.js";
|
||||||
|
import { tryCatch } from "../../../globalUtils/tryCatch.js";
|
||||||
|
import { getInhouseDeliveryByDateRange } from "../controller/getInhouseDeliveryByDateRange.js";
|
||||||
|
|
||||||
|
const app = new OpenAPIHono({ strict: false });
|
||||||
|
const Body = z.object({
|
||||||
|
includeRunnningNumbers: z.string().openapi({ example: "x" }),
|
||||||
|
});
|
||||||
|
app.openapi(
|
||||||
|
createRoute({
|
||||||
|
tags: ["dataMart"],
|
||||||
|
summary: "Returns deliveries by date range.",
|
||||||
|
method: "get",
|
||||||
|
path: "/inhousedeliverybydaterange",
|
||||||
|
request: {
|
||||||
|
body: {
|
||||||
|
content: {
|
||||||
|
"application/json": { schema: Body },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
responses: responses(),
|
||||||
|
}),
|
||||||
|
async (c) => {
|
||||||
|
const delivery: any = c.req.queries();
|
||||||
|
|
||||||
|
// make sure we have a vaid user being accessed thats really logged in
|
||||||
|
apiHit(c, { endpoint: "/inhousedeliverybydaterange" });
|
||||||
|
const { data, error } = await tryCatch(
|
||||||
|
getInhouseDeliveryByDateRange(delivery ? delivery : null),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
console.log(error);
|
||||||
|
return c.json(
|
||||||
|
{
|
||||||
|
success: false,
|
||||||
|
message: "There was an error getting the deliveries.",
|
||||||
|
data: error,
|
||||||
|
},
|
||||||
|
400,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.json({
|
||||||
|
success: data.success,
|
||||||
|
message: data.message,
|
||||||
|
data: data.data,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
export default app;
|
||||||
65
lstV2/server/services/dataMart/route/getPsiForecast.ts
Normal file
65
lstV2/server/services/dataMart/route/getPsiForecast.ts
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
|
||||||
|
import { apiHit } from "../../../globalUtils/apiHits.js";
|
||||||
|
import { responses } from "../../../globalUtils/routeDefs/responses.js";
|
||||||
|
import { tryCatch } from "../../../globalUtils/tryCatch.js";
|
||||||
|
import { getGetPSIForecastData } from "../controller/psiForecastData.js";
|
||||||
|
|
||||||
|
const app = new OpenAPIHono({ strict: false });
|
||||||
|
const Body = z.object({
|
||||||
|
includeRunnningNumbers: z.string().openapi({ example: "x" }),
|
||||||
|
});
|
||||||
|
app.openapi(
|
||||||
|
createRoute({
|
||||||
|
tags: ["dataMart"],
|
||||||
|
summary: "Returns the psiforecastdata.",
|
||||||
|
method: "get",
|
||||||
|
path: "/psiforecastdata",
|
||||||
|
request: {
|
||||||
|
body: {
|
||||||
|
content: {
|
||||||
|
"application/json": { schema: Body },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
responses: responses(),
|
||||||
|
}),
|
||||||
|
async (c) => {
|
||||||
|
const customer: any = c.req.queries();
|
||||||
|
|
||||||
|
// make sure we have a vaid user being accessed thats really logged in
|
||||||
|
apiHit(c, { endpoint: "/psiforecastdata" });
|
||||||
|
//console.log(articles["avs"][0]);
|
||||||
|
|
||||||
|
let customeArticle = null;
|
||||||
|
if (customer) {
|
||||||
|
customeArticle = customer["customer"][0];
|
||||||
|
}
|
||||||
|
const { data, error } = await tryCatch(
|
||||||
|
getGetPSIForecastData(customeArticle),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
console.log(error);
|
||||||
|
return c.json(
|
||||||
|
{
|
||||||
|
success: false,
|
||||||
|
message: "There was an error getting the articles.",
|
||||||
|
data: error,
|
||||||
|
},
|
||||||
|
400,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
//console.log(data);
|
||||||
|
|
||||||
|
return c.json(
|
||||||
|
{
|
||||||
|
success: data.success,
|
||||||
|
message: data.message,
|
||||||
|
data: data.data,
|
||||||
|
},
|
||||||
|
data.success ? 200 : 400,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
export default app;
|
||||||
@@ -1,64 +1,66 @@
|
|||||||
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 { responses } from "../../../globalUtils/routeDefs/responses.js";
|
||||||
import { tryCatch } from "../../../globalUtils/tryCatch.js";
|
import { tryCatch } from "../../../globalUtils/tryCatch.js";
|
||||||
import { apiHit } from "../../../globalUtils/apiHits.js";
|
|
||||||
import { psiGetInventory } from "../controller/psiGetInventory.js";
|
import { psiGetInventory } from "../controller/psiGetInventory.js";
|
||||||
|
|
||||||
const app = new OpenAPIHono({ strict: false });
|
const app = new OpenAPIHono({ strict: false });
|
||||||
const Body = z.object({
|
const Body = z.object({
|
||||||
includeRunnningNumbers: z.string().openapi({ example: "x" }),
|
includeRunnningNumbers: z.string().openapi({ example: "x" }),
|
||||||
});
|
});
|
||||||
app.openapi(
|
app.openapi(
|
||||||
createRoute({
|
createRoute({
|
||||||
tags: ["dataMart"],
|
tags: ["dataMart"],
|
||||||
summary: "Returns the getPsiinventory.",
|
summary: "Returns the getPsiinventory.",
|
||||||
method: "get",
|
method: "get",
|
||||||
path: "/getpsiinventory",
|
path: "/getpsiinventory",
|
||||||
request: {
|
request: {
|
||||||
body: {
|
body: {
|
||||||
content: {
|
content: {
|
||||||
"application/json": { schema: Body },
|
"application/json": { schema: Body },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
responses: responses(),
|
responses: responses(),
|
||||||
}),
|
}),
|
||||||
async (c) => {
|
async (c) => {
|
||||||
const q: any = c.req.queries();
|
const q: any = c.req.queries();
|
||||||
|
|
||||||
// make sure we have a vaid user being accessed thats really logged in
|
// make sure we have a vaid user being accessed thats really logged in
|
||||||
apiHit(c, { endpoint: "/getpsiinventory" });
|
apiHit(c, { endpoint: "/getpsiinventory" });
|
||||||
//console.log(articles["avs"][0]);
|
//console.log(articles["avs"][0]);
|
||||||
const { data, error } = await tryCatch(
|
const { data, error } = await tryCatch(
|
||||||
psiGetInventory(
|
psiGetInventory(
|
||||||
q["avs"] ? q["avs"][0] : null,
|
q["avs"] ? q["avs"][0] : null,
|
||||||
q["startDate"] ? q["startDate"][0] : null,
|
q["startDate"] ? q["startDate"][0] : null,
|
||||||
q["endDate"] ? q["endDate"][0] : null
|
q["endDate"] ? q["endDate"][0] : null,
|
||||||
)
|
q["whseToInclude"] ? q["whseToInclude"][0] : null,
|
||||||
);
|
q["exludeLanes"] ? q["exludeLanes"][0] : null,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
return c.json(
|
return c.json(
|
||||||
{
|
{
|
||||||
success: false,
|
success: false,
|
||||||
message: "There was an error getting the production.",
|
message: "There was an error getting the production.",
|
||||||
data: error,
|
data: error,
|
||||||
},
|
},
|
||||||
400
|
400,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
//console.log(data);
|
//console.log(data);
|
||||||
|
|
||||||
return c.json(
|
return c.json(
|
||||||
{
|
{
|
||||||
success: data.success,
|
success: data.success,
|
||||||
message: data.message,
|
message: data.message,
|
||||||
data: data.data,
|
data: data.data,
|
||||||
},
|
},
|
||||||
data.success ? 200 : 400
|
data.success ? 200 : 400,
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
export default app;
|
export default app;
|
||||||
|
|||||||
@@ -2,65 +2,71 @@ import { OpenAPIHono } from "@hono/zod-openapi";
|
|||||||
|
|
||||||
const app = new OpenAPIHono();
|
const app = new OpenAPIHono();
|
||||||
|
|
||||||
import stats from "./route/stats.js";
|
|
||||||
import history from "./route/invHistory.js";
|
|
||||||
import { createJob } from "../notifications/utils/processNotifications.js";
|
|
||||||
import { historicalInvIMmport } from "./utils/historicalInv.js";
|
|
||||||
import { tryCatch } from "../../globalUtils/tryCatch.js";
|
import { tryCatch } from "../../globalUtils/tryCatch.js";
|
||||||
|
import { createLog } from "../logger/logger.js";
|
||||||
|
import { createJob } from "../notifications/utils/processNotifications.js";
|
||||||
import { query } from "../sqlServer/prodSqlServer.js";
|
import { query } from "../sqlServer/prodSqlServer.js";
|
||||||
import { shiftChange } from "../sqlServer/querys/misc/shiftChange.js";
|
import { shiftChange } from "../sqlServer/querys/misc/shiftChange.js";
|
||||||
import { createLog } from "../logger/logger.js";
|
import gpData from "./route/getGpData.js";
|
||||||
import lastPurch from "./route/getLastPurchPrice.js";
|
import lastPurch from "./route/getLastPurchPrice.js";
|
||||||
import lastSales from "./route/getLastSalesPrice.js";
|
import lastSales from "./route/getLastSalesPrice.js";
|
||||||
import gpData from "./route/getGpData.js";
|
|
||||||
import consumptionData from "./route/getProductionConsumption.js";
|
import consumptionData from "./route/getProductionConsumption.js";
|
||||||
|
import purchased from "./route/getPurchased.js";
|
||||||
import regrind from "./route/getregrind.js";
|
import regrind from "./route/getregrind.js";
|
||||||
import soldItems from "./route/getSoldItems.js";
|
import soldItems from "./route/getSoldItems.js";
|
||||||
import purchased from "./route/getPurchased.js";
|
import history from "./route/invHistory.js";
|
||||||
|
import stats from "./route/stats.js";
|
||||||
|
import { historicalInvIMmport } from "./utils/historicalInv.js";
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
stats,
|
stats,
|
||||||
history,
|
history,
|
||||||
lastPurch,
|
lastPurch,
|
||||||
lastSales,
|
lastSales,
|
||||||
gpData,
|
gpData,
|
||||||
consumptionData,
|
consumptionData,
|
||||||
regrind,
|
regrind,
|
||||||
soldItems,
|
soldItems,
|
||||||
purchased,
|
purchased,
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
const appRoutes = routes.forEach((route) => {
|
const appRoutes = routes.forEach((route) => {
|
||||||
app.route("/eom", route);
|
app.route("/eom", route);
|
||||||
});
|
});
|
||||||
|
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
const { data: shift, error: shiftError } = (await tryCatch(
|
const { data: shift, error: shiftError } = (await tryCatch(
|
||||||
query(shiftChange, "shift change from material.")
|
query(shiftChange, "shift change from material."),
|
||||||
)) as any;
|
)) as any;
|
||||||
|
|
||||||
if (shiftError) {
|
if (shiftError) {
|
||||||
createLog(
|
createLog(
|
||||||
"error",
|
"error",
|
||||||
"eom",
|
"eom",
|
||||||
"eom",
|
"eom",
|
||||||
"There was an error getting the shift times will use fallback times"
|
"There was an error getting the shift times will use fallback times",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// shift split
|
// shift split
|
||||||
const shiftTimeSplit = shift?.data[0]?.shiftChange.split(":");
|
const shiftTimeSplit = shift?.data[0]?.shiftChange.split(":");
|
||||||
|
|
||||||
const cronSetup = `${
|
const cronSetup = `${
|
||||||
shiftTimeSplit?.length > 0 ? `${parseInt(shiftTimeSplit[1])}` : "0"
|
shiftTimeSplit?.length > 0 ? `${parseInt(shiftTimeSplit[1])}` : "0"
|
||||||
} ${
|
} ${
|
||||||
shiftTimeSplit?.length > 0 ? `${parseInt(shiftTimeSplit[0])}` : "7"
|
shiftTimeSplit?.length > 0 ? `${parseInt(shiftTimeSplit[0])}` : "7"
|
||||||
} * * *`;
|
} * * *`;
|
||||||
|
|
||||||
//console.log(cronSetup);
|
//console.log(cronSetup);
|
||||||
createJob("eom_historical_inv", cronSetup, historicalInvIMmport);
|
createJob("eom_historical_inv", cronSetup, historicalInvIMmport);
|
||||||
}, 5 * 1000);
|
}, 5 * 1000);
|
||||||
// the time we want to run the hostircal data should be the same time the historical data run on the server
|
// the time we want to run the hostircal data should be the same time the historical data run on the server
|
||||||
// getting this from the shift time
|
// getting this from the shift time
|
||||||
|
|
||||||
|
//if (process.env.NODE_ENV?.trim() !== "production") {
|
||||||
|
setTimeout(() => {
|
||||||
|
historicalInvIMmport();
|
||||||
|
}, 15 * 1000);
|
||||||
|
//}
|
||||||
|
|
||||||
export default app;
|
export default app;
|
||||||
|
|||||||
@@ -76,7 +76,10 @@ export const historicalInvIMmport = async () => {
|
|||||||
coa_QTY: i.COA_QTY,
|
coa_QTY: i.COA_QTY,
|
||||||
held_QTY: i.Held_QTY,
|
held_QTY: i.Held_QTY,
|
||||||
consignment: i.Consigment,
|
consignment: i.Consigment,
|
||||||
lot_Number: i.lot,
|
lot_Number: i.Lot,
|
||||||
|
location: i.location,
|
||||||
|
whseId: i.warehouseID,
|
||||||
|
whseName: i.warehouseName,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
155
lstV2/server/services/logistics/controller/commands/bookout.ts
Normal file
155
lstV2/server/services/logistics/controller/commands/bookout.ts
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
import net from "net";
|
||||||
|
import { db } from "../../../../../database/dbclient.js";
|
||||||
|
import { commandLog } from "../../../../../database/schema/commandLog.js";
|
||||||
|
import { createSSCC } from "../../../../globalUtils/createSSCC.js";
|
||||||
|
import { prodEndpointCreation } from "../../../../globalUtils/createUrl.js";
|
||||||
|
import { scanner } from "../../../../globalUtils/scannerConnect.js";
|
||||||
|
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
|
||||||
|
import { createLog } from "../../../logger/logger.js";
|
||||||
|
import { query } from "../../../sqlServer/prodSqlServer.js";
|
||||||
|
import { sqlQuerySelector } from "../../../sqlServer/utils/querySelector.utils.js";
|
||||||
|
|
||||||
|
type Data = {
|
||||||
|
runningNr: number;
|
||||||
|
reason: string;
|
||||||
|
user: string;
|
||||||
|
};
|
||||||
|
export const bookOutPallet = async (data: Data) => {
|
||||||
|
const { runningNr, reason, user } = data;
|
||||||
|
|
||||||
|
if (!reason || reason.length < 4) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
status: 400,
|
||||||
|
message: "The reason provided is to short",
|
||||||
|
data: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryCheck = sqlQuerySelector("inventoryInfo.query");
|
||||||
|
|
||||||
|
if (!queryCheck.success) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
status: 400,
|
||||||
|
message: queryCheck.message,
|
||||||
|
data: data,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const { data: label, error: labelError } = (await tryCatch(
|
||||||
|
query(
|
||||||
|
queryCheck.query!.replace("[runningNr]", `${runningNr}`),
|
||||||
|
"labelQuery",
|
||||||
|
),
|
||||||
|
)) as any;
|
||||||
|
|
||||||
|
if (labelError) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
status: 400,
|
||||||
|
message: labelError.message,
|
||||||
|
data: labelError,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if we are in ppoo
|
||||||
|
if (label.data.length <= 0) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
status: 400,
|
||||||
|
message: `${runningNr} is not currently in ppoo, please move to ppoo before trying to book-out`,
|
||||||
|
data: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the label is blocked for coa.
|
||||||
|
if (
|
||||||
|
label.data[0].blockingReason &&
|
||||||
|
!label.data[0].blockingReason?.includes("COA")
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
status: 400,
|
||||||
|
message: `${runningNr} is not currently blocked for coa, to get this pallet booked out please take the label to quality to be released then you can book-out.`,
|
||||||
|
data: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (label.data[0].blockingReason) {
|
||||||
|
await scanner.scan("AlplaPRODcmd89");
|
||||||
|
await scanner.scan(`${label.data[0].barcode}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the url to post
|
||||||
|
const url = await prodEndpointCreation(
|
||||||
|
"/public/v1.1/Manufacturing/ProductionControlling/BookOut",
|
||||||
|
);
|
||||||
|
const SSCC = await createSSCC(runningNr);
|
||||||
|
|
||||||
|
const bookOutData = {
|
||||||
|
sscc: SSCC.slice(2),
|
||||||
|
scannerId: "666",
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const results = await axios.post(url, bookOutData, {
|
||||||
|
headers: {
|
||||||
|
"X-API-Key": process.env.TEC_API_KEY || "",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (results.data.Errors) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
status: 400,
|
||||||
|
message: results.data.Errors.Error.Description,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (results.data.Result !== 0) {
|
||||||
|
// console.log("stopping here and closing to soon", results);
|
||||||
|
// return {
|
||||||
|
// success: false,
|
||||||
|
// status: 400,
|
||||||
|
// message: results.data.Message,
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
|
const { data: commandL, error: ce } = await tryCatch(
|
||||||
|
db.insert(commandLog).values({
|
||||||
|
commandUsed: "book out",
|
||||||
|
bodySent: data,
|
||||||
|
reasonUsed: reason,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: `${runningNr} was booked out`,
|
||||||
|
status: results.status,
|
||||||
|
};
|
||||||
|
} catch (error: any) {
|
||||||
|
console.log(bookOutData);
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
status: 400,
|
||||||
|
message: error.response?.data,
|
||||||
|
data: error.response?.data,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* book out the label with
|
||||||
|
* url /public/v1.1/Manufacturing/ProductionControlling/BookOut
|
||||||
|
* {
|
||||||
|
* "sscc": "string",
|
||||||
|
* "scannerId": "string"
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
//---------------------------------------------------------------------------------------\\
|
||||||
|
};
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
import { db } from "../../../../../database/dbclient.js";
|
||||||
|
import { commandLog } from "../../../../../database/schema/commandLog.js";
|
||||||
|
import { createSSCC } from "../../../../globalUtils/createSSCC.js";
|
||||||
|
import { prodEndpointCreation } from "../../../../globalUtils/createUrl.js";
|
||||||
|
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
|
||||||
|
import { createLog } from "../../../logger/logger.js";
|
||||||
|
import { query } from "../../../sqlServer/prodSqlServer.js";
|
||||||
|
|
||||||
|
type Data = {
|
||||||
|
runningNr: number;
|
||||||
|
laneID: number;
|
||||||
|
};
|
||||||
|
export const relatePallet = async (data: Data) => {
|
||||||
|
const { runningNr, laneID } = data;
|
||||||
|
// replace the rn
|
||||||
|
|
||||||
|
// console.log(data);
|
||||||
|
// create the url to post
|
||||||
|
|
||||||
|
// do we have warehousing turned on?
|
||||||
|
const { data: feature, error: featureError } = (await tryCatch(
|
||||||
|
query(
|
||||||
|
`SELECT [Id]
|
||||||
|
,[Feature]
|
||||||
|
,[Enabled]
|
||||||
|
,[ActivationDate]
|
||||||
|
FROM [test1_AlplaPROD2.0_Read].[support].[FeatureActivation] where [Feature] = 7`,
|
||||||
|
"feature switch check",
|
||||||
|
),
|
||||||
|
)) as any;
|
||||||
|
|
||||||
|
let prodUrl = "/public/v1.0/Warehousing/Relocate";
|
||||||
|
if (featureError) {
|
||||||
|
prodUrl = "/public/v1.0/Warehousing/Relocate";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (feature?.data.length > 0) {
|
||||||
|
prodUrl = "/public/v1.1/Warehousing/Unit/Relocate";
|
||||||
|
}
|
||||||
|
// 1.0 "/public/v1.0/Warehousing/AdjustSiloStockLevel","
|
||||||
|
// 1.1 "/public/v1.1/Warehousing/Lane/AdjustSiloStockLevel"
|
||||||
|
|
||||||
|
let url = await prodEndpointCreation(prodUrl);
|
||||||
|
|
||||||
|
const SSCC = await createSSCC(runningNr);
|
||||||
|
const consumeSomething = {
|
||||||
|
ScannerId: 999,
|
||||||
|
laneId: laneID,
|
||||||
|
sscc: SSCC.slice(2),
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log(consumeSomething);
|
||||||
|
try {
|
||||||
|
const results = await axios.post(url, consumeSomething, {
|
||||||
|
headers: {
|
||||||
|
"X-API-Key": process.env.TEC_API_KEY || "",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (results.data.Errors) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: results.data.Errors.Error.Description,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (results.data.Result !== 0 || results.data.data.length <= 0) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: results.data.Message,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data: commandL, error: ce } = await tryCatch(
|
||||||
|
db.insert(commandLog).values({
|
||||||
|
commandUsed: "relocate",
|
||||||
|
bodySent: data,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: "Pallet Was Relocated",
|
||||||
|
status: results.status,
|
||||||
|
};
|
||||||
|
} catch (error: any) {
|
||||||
|
console.log(error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
status: 200,
|
||||||
|
message: error.response?.data.errors[0].message,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,120 +1,50 @@
|
|||||||
import axios from "axios";
|
|
||||||
import { commandLog } from "../../../../../database/schema/commandLog.js";
|
|
||||||
import { prodEndpointCreation } from "../../../../globalUtils/createUrl.js";
|
|
||||||
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
|
|
||||||
import { lstAuth } from "../../../../index.js";
|
|
||||||
import { createSSCC } from "../../../../globalUtils/createSSCC.js";
|
|
||||||
import { db } from "../../../../../database/dbclient.js";
|
import { db } from "../../../../../database/dbclient.js";
|
||||||
import net from "net";
|
import { commandLog } from "../../../../../database/schema/commandLog.js";
|
||||||
|
import { scanner } from "../../../../globalUtils/scannerConnect.js";
|
||||||
|
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
|
||||||
import { query } from "../../../sqlServer/prodSqlServer.js";
|
import { query } from "../../../sqlServer/prodSqlServer.js";
|
||||||
import { labelInfo } from "../../../sqlServer/querys/warehouse/labelInfo.js";
|
import { labelInfo } from "../../../sqlServer/querys/warehouse/labelInfo.js";
|
||||||
import { settings } from "../../../../../database/schema/settings.js";
|
|
||||||
import { eq } from "drizzle-orm";
|
|
||||||
import { serverData } from "../../../../../database/schema/serverData.js";
|
|
||||||
export const removeAsNonReusable = async (data: any) => {
|
export const removeAsNonReusable = async (data: any) => {
|
||||||
// const removalUrl = await prodEndpointCreation(
|
// get the label info
|
||||||
// "/public/v1.0/Warehousing/RemoveAsNonReusableMaterial"
|
const { data: label, error: labelError } = (await tryCatch(
|
||||||
// );
|
query(labelInfo.replaceAll("[runningNr]", data.runningNr), "Label Info"),
|
||||||
|
)) as any;
|
||||||
|
|
||||||
// const sscc = await createSSCC(data.runningNr);
|
if (label.data[0].stockStatus === "notOnStock") {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: `The label: ${data.runningNr} is not currently in stock`,
|
||||||
|
data: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// const { data: remove, error } = await tryCatch(
|
if (label.data[0].blockingReason) {
|
||||||
// axios.post(
|
return {
|
||||||
// removalUrl,
|
success: false,
|
||||||
// { scannerId: "500", sscc: sscc.slice(2) },
|
status: 400,
|
||||||
// {
|
message: `${data.runningNr} is currently blocked, to get this pallet removed please take the label to quality to be released then you can remove.`,
|
||||||
// headers: { Authorization: `Basic ${lstAuth}` },
|
data: [],
|
||||||
// }
|
};
|
||||||
// )
|
}
|
||||||
// );
|
|
||||||
|
|
||||||
// use a scanner tcp connection to trigger this process
|
await scanner.scan("AlplaPRODcmd23");
|
||||||
const STX = "\x02";
|
await scanner.scan(`${label.data[0].barcode}`);
|
||||||
const ETX = "\x03";
|
|
||||||
const scanner = new net.Socket();
|
|
||||||
let stage = 0;
|
|
||||||
// get the label info
|
|
||||||
const { data: label, error: labelError } = (await tryCatch(
|
|
||||||
query(labelInfo.replaceAll("[runningNr]", data.runningNr), "Label Info")
|
|
||||||
)) as any;
|
|
||||||
|
|
||||||
if (label.data[0].stockStatus === "notOnStock") {
|
let reason = data.reason || "";
|
||||||
return {
|
delete data.reason;
|
||||||
success: false,
|
|
||||||
message: `The label: ${data.runningNr} is not currently in stock`,
|
|
||||||
data: [],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the server ip based on the token.
|
const { data: commandL, error: ce } = await tryCatch(
|
||||||
const setting = await db.select().from(settings);
|
db.insert(commandLog).values({
|
||||||
|
commandUsed: "removeAsNonReusable",
|
||||||
|
bodySent: data,
|
||||||
|
reasonUsed: reason,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
const plantInfo = await db.select().from(serverData);
|
return {
|
||||||
const plantToken = setting.filter((n: any) => n.name === "plantToken");
|
success: true,
|
||||||
const scannerID = setting.filter((n: any) => n.name === "scannerID");
|
message: `The label: ${data.runningNr}, was removed`,
|
||||||
const scannerPort = setting.filter((n: any) => n.name === "scannerPort");
|
data: [],
|
||||||
const plantData = plantInfo.filter(
|
};
|
||||||
(p: any) => p.plantToken === plantToken[0].value
|
|
||||||
);
|
|
||||||
|
|
||||||
scanner.connect(
|
|
||||||
parseInt(scannerPort[0].value),
|
|
||||||
plantData[0].idAddress!,
|
|
||||||
async () => {
|
|
||||||
// need to get the ip from the server data and scanner port
|
|
||||||
//console.log(`connected to scanner`);
|
|
||||||
scanner.write(`${STX}${scannerID[0].value}@AlplaPRODcmd23${ETX}`);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
scanner.on("data", (data) => {
|
|
||||||
const response = data.toString();
|
|
||||||
//console.log("Received:", response.trimStart());
|
|
||||||
if (stage === 0) {
|
|
||||||
stage = 1;
|
|
||||||
scanner.write(
|
|
||||||
`${STX}${scannerID[0].value}@${label.data[0].Barcode}${ETX}`
|
|
||||||
);
|
|
||||||
} else if (stage === 1) {
|
|
||||||
scanner.end();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
scanner.on("close", () => {
|
|
||||||
//console.log("Connection closed");
|
|
||||||
scanner.destroy();
|
|
||||||
});
|
|
||||||
scanner.on("error", (err) => {
|
|
||||||
//console.error("Scanner error:", err);
|
|
||||||
scanner.destroy();
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
message: `The label: ${data.runningNr} encountering an error while being removed, please try again`,
|
|
||||||
data: [],
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// if (error) {
|
|
||||||
// //console.log(error);
|
|
||||||
// return {
|
|
||||||
// success: false,
|
|
||||||
// message: `There was an error removing ${data.runningNr}`,
|
|
||||||
// data: [],
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
|
|
||||||
let reason = data.reason || "";
|
|
||||||
delete data.reason;
|
|
||||||
|
|
||||||
const { data: commandL, error: ce } = await tryCatch(
|
|
||||||
db.insert(commandLog).values({
|
|
||||||
commandUsed: "removeAsNonReusable",
|
|
||||||
bodySent: data,
|
|
||||||
reasonUsed: reason,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
message: `The label: ${data.runningNr}, was removed`,
|
|
||||||
data: [],
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
import XLSX from "xlsx";
|
||||||
|
import { db } from "../../../../../../../database/dbclient.js";
|
||||||
|
import { settings } from "../../../../../../../database/schema/settings.js";
|
||||||
|
import { delay } from "../../../../../../globalUtils/delay.js";
|
||||||
|
import { tryCatch } from "../../../../../../globalUtils/tryCatch.js";
|
||||||
|
import { excelDateStuff } from "../../../../utils/excelDateStuff.js";
|
||||||
|
import { postForecast } from "../postForecast.js";
|
||||||
|
|
||||||
|
export const abbottForecast = async (sheet: any, user: any) => {
|
||||||
|
const customerId = 8;
|
||||||
|
const posting: any = [];
|
||||||
|
const { data: s, error: e } = await tryCatch(db.select().from(settings));
|
||||||
|
|
||||||
|
if (e) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: `Error getting settings`,
|
||||||
|
data: e,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const plantToken = s.filter((s) => s.name === "plantToken");
|
||||||
|
const customHeaders = [
|
||||||
|
"date",
|
||||||
|
"time",
|
||||||
|
"newton8oz",
|
||||||
|
"newton10oz",
|
||||||
|
"E",
|
||||||
|
"F",
|
||||||
|
"fDate",
|
||||||
|
"f8ozqty",
|
||||||
|
"I",
|
||||||
|
"J",
|
||||||
|
"K",
|
||||||
|
"L",
|
||||||
|
"M",
|
||||||
|
"f10ozqty",
|
||||||
|
];
|
||||||
|
const forecastData = XLSX.utils.sheet_to_json(sheet, {
|
||||||
|
range: 5, // Start at row 5 (index 4)
|
||||||
|
header: customHeaders,
|
||||||
|
defval: "", // Default value for empty cells
|
||||||
|
});
|
||||||
|
|
||||||
|
for (let i = 1; i < forecastData.length; i++) {
|
||||||
|
const row: any = forecastData[i];
|
||||||
|
//console.log(row);
|
||||||
|
//if (row.fDate == undefined) continue;
|
||||||
|
|
||||||
|
if (row.fDate !== "") {
|
||||||
|
const date = isNaN(row.fDate)
|
||||||
|
? new Date(row.fDate)
|
||||||
|
: excelDateStuff(row.fDate);
|
||||||
|
// for 8oz do
|
||||||
|
if (row.f8ozqty > 0) {
|
||||||
|
posting.push({
|
||||||
|
customerArticleNo: "45300DA",
|
||||||
|
quantity: row.f8ozqty,
|
||||||
|
requirementDate: date,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (row.f10ozqty > 0) {
|
||||||
|
posting.push({
|
||||||
|
customerArticleNo: "43836DA",
|
||||||
|
quantity: row.f10ozqty,
|
||||||
|
requirementDate: date,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// the predefined data that will never change
|
||||||
|
const predefinedObject = {
|
||||||
|
receivingPlantId: plantToken[0].value,
|
||||||
|
documentName: `ForecastFromLST-${new Date(Date.now()).toLocaleString(
|
||||||
|
"en-US",
|
||||||
|
)}`,
|
||||||
|
sender: user.username || "lst-system",
|
||||||
|
customerId: customerId,
|
||||||
|
positions: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
// add the new forecast to the predefined data
|
||||||
|
let updatedPredefinedObject = {
|
||||||
|
...predefinedObject,
|
||||||
|
positions: [...predefinedObject.positions, ...posting],
|
||||||
|
};
|
||||||
|
|
||||||
|
const forecast: any = await postForecast(updatedPredefinedObject, user);
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: forecast.success,
|
||||||
|
message: forecast.message,
|
||||||
|
data: forecast.data,
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -1,95 +1,102 @@
|
|||||||
|
import { addDays } from "date-fns";
|
||||||
|
import XLSX from "xlsx";
|
||||||
import { db } from "../../../../../../../database/dbclient.js";
|
import { db } from "../../../../../../../database/dbclient.js";
|
||||||
import { settings } from "../../../../../../../database/schema/settings.js";
|
import { settings } from "../../../../../../../database/schema/settings.js";
|
||||||
import { tryCatch } from "../../../../../../globalUtils/tryCatch.js";
|
import { tryCatch } from "../../../../../../globalUtils/tryCatch.js";
|
||||||
import XLSX from "xlsx";
|
import { createLog } from "../../../../../logger/logger.js";
|
||||||
import { postForecast } from "../postForecast.js";
|
import { sendEmail } from "../../../../../notifications/controller/sendMail.js";
|
||||||
import { query } from "../../../../../sqlServer/prodSqlServer.js";
|
import { query } from "../../../../../sqlServer/prodSqlServer.js";
|
||||||
import { activeArticle } from "../../../../../sqlServer/querys/dataMart/article.js";
|
import { activeArticle } from "../../../../../sqlServer/querys/dataMart/article.js";
|
||||||
import { addDays } from "date-fns";
|
import { excelDateStuff } from "../../../../utils/excelDateStuff.js";
|
||||||
import { sendEmail } from "../../../../../notifications/controller/sendMail.js";
|
import { postForecast } from "../postForecast.js";
|
||||||
import { createLog } from "../../../../../logger/logger.js";
|
|
||||||
|
|
||||||
export const energizerForecast = async (data: any, user: any) => {
|
export const energizerForecast = async (data: any, user: any) => {
|
||||||
/**
|
/**
|
||||||
* Post a standard forecast based on the standard template.
|
* Post a standard forecast based on the standard template.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const { data: s, error: e } = await tryCatch(db.select().from(settings));
|
const { data: s, error: e } = await tryCatch(db.select().from(settings));
|
||||||
|
|
||||||
if (e) {
|
if (e) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
message: `Error getting settings`,
|
message: `Error getting settings`,
|
||||||
data: e,
|
data: e,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const plantToken = s.filter((s) => s.name === "plantToken");
|
const plantToken = s.filter((s) => s.name === "plantToken");
|
||||||
|
|
||||||
const arrayBuffer = await data.arrayBuffer();
|
const arrayBuffer = await data.arrayBuffer();
|
||||||
const buffer = Buffer.from(arrayBuffer);
|
const buffer = Buffer.from(arrayBuffer);
|
||||||
|
|
||||||
const workbook = XLSX.read(buffer, { type: "buffer" });
|
const workbook = XLSX.read(buffer, { type: "buffer" });
|
||||||
|
|
||||||
const sheet: any = workbook.Sheets["Sheet1"];
|
const sheet: any = workbook.Sheets["Sheet1"];
|
||||||
const range = XLSX.utils.decode_range(sheet["!ref"]);
|
const range = XLSX.utils.decode_range(sheet["!ref"]);
|
||||||
|
|
||||||
const headers = [
|
const headers = [
|
||||||
"CustomerArticleNumber",
|
"CustomerArticleNumber",
|
||||||
"Quantity",
|
"Quantity",
|
||||||
"RequirementDate",
|
"RequirementDate",
|
||||||
"CustomerID",
|
"CustomerID",
|
||||||
];
|
];
|
||||||
|
|
||||||
// formatting the data
|
// formatting the data
|
||||||
const rows = XLSX.utils.sheet_to_json(sheet, { header: 1 }) as any;
|
const rows = XLSX.utils.sheet_to_json(sheet, { header: 1 }) as any;
|
||||||
|
|
||||||
const posting: any = [];
|
const posting: any = [];
|
||||||
const customerId = 44;
|
const customerId = 44;
|
||||||
|
|
||||||
for (let i = 1; i < rows.length; i++) {
|
for (let i = 1; i < rows.length; i++) {
|
||||||
const row: any = rows[i];
|
const row: any = rows[i];
|
||||||
const material = row[0];
|
const material = row[0];
|
||||||
|
|
||||||
if (material == undefined) continue;
|
if (material == undefined) continue;
|
||||||
for (let j = 1; j < row.length; j++) {
|
for (let j = 1; j < row.length; j++) {
|
||||||
const qty = row[j];
|
const qty = row[j];
|
||||||
|
|
||||||
if (qty && qty !== 0) {
|
if (qty && qty > 0) {
|
||||||
const requirementDate = rows[0][j]; // first row is dates
|
const requirementDate = rows[0][j]; // first row is dates
|
||||||
|
const date = isNaN(requirementDate)
|
||||||
|
? new Date(requirementDate)
|
||||||
|
: excelDateStuff(requirementDate);
|
||||||
|
|
||||||
posting.push({
|
console.log(isNaN(requirementDate), requirementDate, date);
|
||||||
customerArticleNo: material,
|
posting.push({
|
||||||
quantity: qty,
|
customerArticleNo: material,
|
||||||
requirementDate: new Date(requirementDate),
|
quantity: qty,
|
||||||
});
|
requirementDate: date,
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// the predefined data that will never change
|
//console.log(posting);
|
||||||
const predefinedObject = {
|
|
||||||
receivingPlantId: plantToken[0].value,
|
|
||||||
documentName: `ForecastFromLST-${new Date(Date.now()).toLocaleString(
|
|
||||||
"en-US"
|
|
||||||
)}`,
|
|
||||||
sender: user.username || "lst-system",
|
|
||||||
customerId: customerId,
|
|
||||||
positions: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
// add the new forecast to the predefined data
|
// the predefined data that will never change
|
||||||
let updatedPredefinedObject = {
|
const predefinedObject = {
|
||||||
...predefinedObject,
|
receivingPlantId: plantToken[0].value,
|
||||||
positions: [...predefinedObject.positions, ...posting],
|
documentName: `ForecastFromLST-${new Date(Date.now()).toLocaleString(
|
||||||
};
|
"en-US",
|
||||||
|
)}`,
|
||||||
|
sender: user.username || "lst-system",
|
||||||
|
customerId: customerId,
|
||||||
|
positions: [],
|
||||||
|
};
|
||||||
|
|
||||||
//post it
|
// add the new forecast to the predefined data
|
||||||
const forecastData: any = await postForecast(updatedPredefinedObject, user);
|
let updatedPredefinedObject = {
|
||||||
|
...predefinedObject,
|
||||||
|
positions: [...predefinedObject.positions, ...posting],
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
//post it
|
||||||
success: forecastData.success,
|
const forecastData: any = await postForecast(updatedPredefinedObject, user);
|
||||||
message: forecastData.message,
|
|
||||||
data: forecastData.data,
|
return {
|
||||||
};
|
success: forecastData.success,
|
||||||
|
message: forecastData.message,
|
||||||
|
data: forecastData.data,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
|
import { addDays, addHours, isAfter, parse, subDays } from "date-fns";
|
||||||
|
import { format } from "date-fns-tz";
|
||||||
import XLSX from "xlsx";
|
import XLSX from "xlsx";
|
||||||
import { excelDateStuff } from "../../../../utils/excelDateStuff.js";
|
|
||||||
import { tryCatch } from "../../../../../../globalUtils/tryCatch.js";
|
|
||||||
import { db } from "../../../../../../../database/dbclient.js";
|
import { db } from "../../../../../../../database/dbclient.js";
|
||||||
import { settings } from "../../../../../../../database/schema/settings.js";
|
import { settings } from "../../../../../../../database/schema/settings.js";
|
||||||
|
import { tryCatch } from "../../../../../../globalUtils/tryCatch.js";
|
||||||
import { query } from "../../../../../sqlServer/prodSqlServer.js";
|
import { query } from "../../../../../sqlServer/prodSqlServer.js";
|
||||||
import { bulkOrderArticleInfo } from "../../../../../sqlServer/querys/dm/bulkOrderArticleInfo.js";
|
import { bulkOrderArticleInfo } from "../../../../../sqlServer/querys/dm/bulkOrderArticleInfo.js";
|
||||||
import { addDays, addHours, isAfter, parse } from "date-fns";
|
|
||||||
import { orderState } from "../../../../../sqlServer/querys/dm/orderState.js";
|
import { orderState } from "../../../../../sqlServer/querys/dm/orderState.js";
|
||||||
|
import { excelDateStuff } from "../../../../utils/excelDateStuff.js";
|
||||||
|
import { abbottForecast } from "../../forecast/mappings/abbott.js";
|
||||||
import { postOrders } from "../postOrders.js";
|
import { postOrders } from "../postOrders.js";
|
||||||
|
|
||||||
// customeris/articles stuff will be in basis once we move to iowa
|
// customeris/articles stuff will be in basis once we move to iowa
|
||||||
@@ -14,171 +16,181 @@ let customerID = 8;
|
|||||||
let invoiceID = 9;
|
let invoiceID = 9;
|
||||||
let articles = "118,120";
|
let articles = "118,120";
|
||||||
export const abbottOrders = async (data: any, user: any) => {
|
export const abbottOrders = async (data: any, user: any) => {
|
||||||
/**
|
/**
|
||||||
* Standard orders meaning that we get the standard file exported and fill it out and uplaod to lst.
|
* Standard orders meaning that we get the standard file exported and fill it out and uplaod to lst.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const { data: s, error: e } = await tryCatch(db.select().from(settings));
|
const { data: s, error: e } = await tryCatch(db.select().from(settings));
|
||||||
|
|
||||||
if (e) {
|
if (e) {
|
||||||
return {
|
return {
|
||||||
sucess: false,
|
sucess: false,
|
||||||
message: `Error getting settings`,
|
message: `Error getting settings`,
|
||||||
data: e,
|
data: e,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// articleInfo
|
// articleInfo
|
||||||
const { data: article, error: ae } = await tryCatch(
|
const { data: article, error: ae } = await tryCatch(
|
||||||
query(
|
query(
|
||||||
bulkOrderArticleInfo.replace("[articles]", articles),
|
bulkOrderArticleInfo.replace("[articles]", articles),
|
||||||
"Get Article data for bulk orders"
|
"Get Article data for bulk orders",
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
const a: any = article?.data;
|
const a: any = article?.data;
|
||||||
if (ae) {
|
if (ae) {
|
||||||
return {
|
return {
|
||||||
sucess: false,
|
sucess: false,
|
||||||
message: `Error getting article data`,
|
message: `Error getting article data`,
|
||||||
data: ae,
|
data: ae,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// order state
|
// order state
|
||||||
const { data: o, error: oe } = await tryCatch(
|
const { data: o, error: oe } = await tryCatch(
|
||||||
query(orderState, "Gets the next 500 orders that have not been started")
|
query(orderState, "Gets the next 500 orders that have not been started"),
|
||||||
);
|
);
|
||||||
|
|
||||||
const openOrders: any = o?.data;
|
const openOrders: any = o?.data;
|
||||||
|
|
||||||
if (oe) {
|
if (oe) {
|
||||||
return {
|
return {
|
||||||
sucess: false,
|
sucess: false,
|
||||||
message: `Error getting article data`,
|
message: `Error getting article data`,
|
||||||
data: oe,
|
data: oe,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const plantToken = s.filter((s) => s.name === "plantToken");
|
const plantToken = s.filter((s) => s.name === "plantToken");
|
||||||
|
|
||||||
const arrayBuffer = await data.arrayBuffer();
|
const arrayBuffer = await data.arrayBuffer();
|
||||||
const buffer = Buffer.from(arrayBuffer);
|
const buffer = Buffer.from(arrayBuffer);
|
||||||
|
|
||||||
const workbook = XLSX.read(buffer, { type: "buffer" });
|
const workbook = XLSX.read(buffer, { type: "buffer" });
|
||||||
|
|
||||||
const sheetName = workbook.SheetNames[0];
|
const sheetName = workbook.SheetNames[0];
|
||||||
const sheet = workbook.Sheets[sheetName];
|
const sheet = workbook.Sheets[sheetName];
|
||||||
|
|
||||||
// Define custom headers
|
abbottForecast(sheet, user);
|
||||||
const customHeaders = ["date", "time", "newton8oz", "newton10oz"];
|
// Define custom headers
|
||||||
const orderData = XLSX.utils.sheet_to_json(sheet, {
|
const customHeaders = ["date", "time", "newton8oz", "newton10oz"];
|
||||||
range: 5, // Start at row 5 (index 4)
|
const orderData = XLSX.utils.sheet_to_json(sheet, {
|
||||||
header: customHeaders,
|
range: 5, // Start at row 5 (index 4)
|
||||||
defval: "", // Default value for empty cells
|
header: customHeaders,
|
||||||
});
|
defval: "", // Default value for empty cells
|
||||||
|
});
|
||||||
|
|
||||||
// the base of the import
|
// the base of the import
|
||||||
const predefinedObject = {
|
const predefinedObject = {
|
||||||
receivingPlantId: plantToken[0].value,
|
receivingPlantId: plantToken[0].value,
|
||||||
documentName: `OrdersFromLST-${new Date(Date.now()).toLocaleString(
|
documentName: `OrdersFromLST-${new Date(Date.now()).toLocaleString(
|
||||||
"en-US"
|
"en-US",
|
||||||
)}`,
|
)}`,
|
||||||
sender: user.username || "lst-system",
|
sender: user.username || "lst-system",
|
||||||
externalRefNo: `OrdersFromLST-${new Date(Date.now()).toLocaleString(
|
externalRefNo: `OrdersFromLST-${new Date(Date.now()).toLocaleString(
|
||||||
"en-US"
|
"en-US",
|
||||||
)}`,
|
)}`,
|
||||||
orders: [],
|
orders: [],
|
||||||
};
|
};
|
||||||
const oOrders: any = openOrders;
|
const oOrders: any = openOrders;
|
||||||
|
//console.log(orderData);
|
||||||
|
|
||||||
let correctedOrders: any = orderData
|
function trimAll(str: string) {
|
||||||
.filter(
|
return str.replace(/\s+/g, "");
|
||||||
(o: any) =>
|
}
|
||||||
(o.newton8oz && o.newton8oz.trim() !== "") ||
|
let correctedOrders: any = orderData
|
||||||
(o.newton10oz && o.newton10oz.trim() !== "")
|
.filter(
|
||||||
)
|
(o: any) =>
|
||||||
.map((o: any) => ({
|
(o.newton8oz && o.newton8oz.trim() !== "") ||
|
||||||
date: excelDateStuff(o.date, o.time),
|
(o.newton10oz && o.newton10oz.trim() !== ""),
|
||||||
po:
|
)
|
||||||
o.newton8oz.replace(/\s+/g, "") !== ""
|
.map((o: any) => ({
|
||||||
? o.newton8oz.replace(/\s+/g, "")
|
date: excelDateStuff(o.date, o.time),
|
||||||
: o.newton10oz.replace(/\s+/g, ""),
|
po:
|
||||||
customerArticlenumber:
|
trimAll(o.newton8oz) !== ""
|
||||||
o.newton8oz != ""
|
? trimAll(o.newton8oz)
|
||||||
? a.filter((a: any) => a.av === 118)[0]
|
: o.newton10oz.replace(/[\s\u00A0]+/g, ""),
|
||||||
.CustomerArticleNumber
|
customerArticlenumber:
|
||||||
: a.filter((a: any) => a.av === 120)[0]
|
o.newton8oz != ""
|
||||||
.CustomerArticleNumber,
|
? a.filter((a: any) => a.av === 118)[0].CustomerArticleNumber
|
||||||
qty:
|
: a.filter((a: any) => a.av === 120)[0].CustomerArticleNumber,
|
||||||
o.newton8oz != ""
|
qty:
|
||||||
? a.filter((a: any) => a.av === 118)[0].totalTruckLoad
|
o.newton8oz != ""
|
||||||
: a.filter((a: any) => a.av === 120)[0].totalTruckLoad,
|
? a.filter((a: any) => a.av === 118)[0].totalTruckLoad
|
||||||
}));
|
: a.filter((a: any) => a.av === 120)[0].totalTruckLoad,
|
||||||
|
}));
|
||||||
|
|
||||||
// now we want to make sure we only correct orders that or after now
|
//console.log(correctedOrders);
|
||||||
correctedOrders = correctedOrders.filter((o: any) => {
|
// now we want to make sure we only correct orders that or after now
|
||||||
const parsedDate = parse(o.date, "M/d/yyyy, h:mm:ss a", new Date());
|
correctedOrders = correctedOrders.filter((o: any) => {
|
||||||
return isAfter(o.date, new Date().toISOString());
|
const parsedDate = parse(o.date, "M/d/yyyy, h:mm:ss a", new Date());
|
||||||
});
|
return isAfter(new Date(o.date), new Date().toISOString());
|
||||||
|
});
|
||||||
|
//console.log(correctedOrders);
|
||||||
|
// last map to remove orders that have already been started
|
||||||
|
// correctedOrders = correctedOrders.filter((oo: any) =>
|
||||||
|
// oOrders.some((o: any) => o.CustomerOrderNumber === oo.po)
|
||||||
|
// );
|
||||||
|
let postedOrders: any = [];
|
||||||
|
const filterOrders: any = correctedOrders;
|
||||||
|
|
||||||
// last map to remove orders that have already been started
|
//console.log(filterOrders);
|
||||||
// correctedOrders = correctedOrders.filter((oo: any) =>
|
|
||||||
// oOrders.some((o: any) => o.CustomerOrderNumber === oo.po)
|
|
||||||
// );
|
|
||||||
let postedOrders: any = [];
|
|
||||||
const filterOrders: any = correctedOrders;
|
|
||||||
filterOrders.forEach((oo: any) => {
|
|
||||||
const isMatch = openOrders.some(
|
|
||||||
(o: any) => String(o.po).trim() === String(oo.po).trim()
|
|
||||||
);
|
|
||||||
if (!isMatch) {
|
|
||||||
//console.log(`ok to update: ${oo.po}`);
|
|
||||||
|
|
||||||
// oo = {
|
filterOrders.forEach((oo: any) => {
|
||||||
// ...oo,
|
const isMatch = openOrders.some(
|
||||||
// CustomerOrderNumber: oo.CustomerOrderNumber.replace(" ", ""),
|
(o: any) => String(o.po).trim() === String(oo.po).trim(),
|
||||||
// };
|
);
|
||||||
postedOrders.push(oo);
|
//console.log(isMatch, oo.po);
|
||||||
} else {
|
if (!isMatch) {
|
||||||
// console.log(`Not valid order to update: ${oo.po}`);
|
console.log(`ok to update: ${oo.po}`);
|
||||||
//console.log(oo)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Map Excel data to predefinedObject format
|
// oo = {
|
||||||
const orders = filterOrders.map((o: any) => {
|
// ...oo,
|
||||||
return {
|
// CustomerOrderNumber: oo.CustomerOrderNumber.replace(" ", ""),
|
||||||
customerId: customerID,
|
// };
|
||||||
invoiceAddressId: invoiceID,
|
postedOrders.push(oo);
|
||||||
customerOrderNo: o.po,
|
} else {
|
||||||
orderDate: new Date(Date.now()).toLocaleString("en-US"),
|
//console.log(`Not valid order to update: ${oo.po}`);
|
||||||
positions: [
|
//console.log(oo)
|
||||||
{
|
}
|
||||||
deliveryAddressId: 8,
|
});
|
||||||
customerArticleNo: o.customerArticlenumber,
|
|
||||||
quantity: o.qty,
|
|
||||||
deliveryDate: addHours(addDays(o.date, 1), 1), // adding this in so we can over come the constant 1 day behind thing as a work around
|
|
||||||
customerLineItemNo: 1, // this is how it is currently sent over from abbott
|
|
||||||
customerReleaseNo: 1, // same as above
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// combine it all together.
|
// Map Excel data to predefinedObject format
|
||||||
const updatedPredefinedObject = {
|
const orders = filterOrders.map((o: any) => {
|
||||||
...predefinedObject,
|
//console.log(o.po, " ", o.date, format(o.date, "M/d/yyyy HH:mm"));
|
||||||
orders: [...predefinedObject.orders, ...orders],
|
return {
|
||||||
};
|
customerId: customerID,
|
||||||
|
invoiceAddressId: invoiceID,
|
||||||
|
customerOrderNo: o.po,
|
||||||
|
orderDate: new Date(Date.now()).toLocaleString("en-US"),
|
||||||
|
positions: [
|
||||||
|
{
|
||||||
|
deliveryAddressId: 8,
|
||||||
|
customerArticleNo: o.customerArticlenumber,
|
||||||
|
quantity: o.qty,
|
||||||
|
deliveryDate: format(o.date, "M/d/yyyy HH:mm"), // addHours(format(o.date, "M/d/yyyy HH:mm"), 1), //addHours(addDays(o.date, 1), 1), // adding this in so we can over come the constant 1 day behind thing as a work around
|
||||||
|
customerLineItemNo: 1, // this is how it is currently sent over from abbott
|
||||||
|
customerReleaseNo: 1, // same as above
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
//console.log(updatedPredefinedObject);
|
//console.log(orders);
|
||||||
// post the orders to the server
|
// combine it all together.
|
||||||
const posting = await postOrders(updatedPredefinedObject, user);
|
const updatedPredefinedObject = {
|
||||||
//console.log(posting);
|
...predefinedObject,
|
||||||
|
orders: [...predefinedObject.orders, ...orders],
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
//console.log(updatedPredefinedObject);
|
||||||
success: posting?.success,
|
// post the orders to the server
|
||||||
message: posting?.message,
|
const posting = await postOrders(updatedPredefinedObject, user);
|
||||||
data: posting,
|
//console.log(posting);
|
||||||
};
|
|
||||||
|
return {
|
||||||
|
success: posting?.success,
|
||||||
|
message: posting?.message,
|
||||||
|
data: posting,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,172 +1,172 @@
|
|||||||
import XLSX from "xlsx";
|
import XLSX from "xlsx";
|
||||||
import { tryCatch } from "../../../../../../globalUtils/tryCatch.js";
|
|
||||||
import { db } from "../../../../../../../database/dbclient.js";
|
import { db } from "../../../../../../../database/dbclient.js";
|
||||||
import { settings } from "../../../../../../../database/schema/settings.js";
|
import { settings } from "../../../../../../../database/schema/settings.js";
|
||||||
|
import { tryCatch } from "../../../../../../globalUtils/tryCatch.js";
|
||||||
import { query } from "../../../../../sqlServer/prodSqlServer.js";
|
import { query } from "../../../../../sqlServer/prodSqlServer.js";
|
||||||
|
import { invoiceAddress } from "../../../../../sqlServer/querys/dm/invoiceAddress.js";
|
||||||
import { orderState } from "../../../../../sqlServer/querys/dm/orderState.js";
|
import { orderState } from "../../../../../sqlServer/querys/dm/orderState.js";
|
||||||
import { excelDateStuff } from "../../../../utils/excelDateStuff.js";
|
import { excelDateStuff } from "../../../../utils/excelDateStuff.js";
|
||||||
import { invoiceAddress } from "../../../../../sqlServer/querys/dm/invoiceAddress.js";
|
|
||||||
import { postOrders } from "../postOrders.js";
|
import { postOrders } from "../postOrders.js";
|
||||||
|
|
||||||
export const energizerOrders = async (data: any, user: any) => {
|
export const energizerOrders = async (data: any, user: any) => {
|
||||||
/**
|
/**
|
||||||
* Standard orders meaning that we get the standard file exported and fill it out and uplaod to lst.
|
* Standard orders meaning that we get the standard file exported and fill it out and uplaod to lst.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const { data: s, error: e } = await tryCatch(db.select().from(settings));
|
const { data: s, error: e } = await tryCatch(db.select().from(settings));
|
||||||
|
|
||||||
if (e) {
|
if (e) {
|
||||||
return {
|
return {
|
||||||
sucess: false,
|
sucess: false,
|
||||||
message: `Error getting settings`,
|
message: `Error getting settings`,
|
||||||
data: e,
|
data: e,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// order state
|
// order state
|
||||||
const { data: o, error: oe } = await tryCatch(
|
const { data: o, error: oe } = await tryCatch(
|
||||||
query(orderState, "Gets the next 500 orders that have not been started")
|
query(orderState, "Gets the next 500 orders that have not been started"),
|
||||||
);
|
);
|
||||||
|
|
||||||
const openOrders: any = o?.data;
|
const openOrders: any = o?.data;
|
||||||
|
|
||||||
if (oe) {
|
if (oe) {
|
||||||
return {
|
return {
|
||||||
sucess: false,
|
sucess: false,
|
||||||
message: `Error getting article data`,
|
message: `Error getting article data`,
|
||||||
data: oe,
|
data: oe,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// order state
|
// order state
|
||||||
const { data: invoice, error: ie } = await tryCatch(
|
const { data: invoice, error: ie } = await tryCatch(
|
||||||
query(invoiceAddress, "Gets invoices addresses")
|
query(invoiceAddress, "Gets invoices addresses"),
|
||||||
);
|
);
|
||||||
const i: any = invoice?.data;
|
const i: any = invoice?.data;
|
||||||
|
|
||||||
if (ie) {
|
if (ie) {
|
||||||
return {
|
return {
|
||||||
sucess: false,
|
sucess: false,
|
||||||
message: `Error getting invoice address data`,
|
message: `Error getting invoice address data`,
|
||||||
data: ie,
|
data: ie,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const plantToken = s.filter((s) => s.name === "plantToken");
|
const plantToken = s.filter((s) => s.name === "plantToken");
|
||||||
|
|
||||||
const arrayBuffer = await data.arrayBuffer();
|
const arrayBuffer = await data.arrayBuffer();
|
||||||
const buffer = Buffer.from(arrayBuffer);
|
const buffer = Buffer.from(arrayBuffer);
|
||||||
|
|
||||||
const workbook = XLSX.read(buffer, { type: "buffer" });
|
const workbook = XLSX.read(buffer, { type: "buffer" });
|
||||||
|
|
||||||
const sheetName = workbook.SheetNames[0];
|
const sheetName = workbook.SheetNames[0];
|
||||||
const sheet = workbook.Sheets[sheetName];
|
const sheet = workbook.Sheets[sheetName];
|
||||||
|
|
||||||
// define custom headers
|
// define custom headers
|
||||||
const headers = [
|
const headers = [
|
||||||
"ITEM",
|
"ITEM",
|
||||||
"PO",
|
"PO",
|
||||||
"ReleaseNo",
|
"ReleaseNo",
|
||||||
"QTY",
|
"QTY",
|
||||||
"DELDATE",
|
"DELDATE",
|
||||||
"COMMENTS",
|
"COMMENTS",
|
||||||
"What changed",
|
"What changed",
|
||||||
"CUSTOMERID",
|
"CUSTOMERID",
|
||||||
"Remark",
|
"Remark",
|
||||||
];
|
];
|
||||||
const orderData = XLSX.utils.sheet_to_json(sheet, {
|
const orderData = XLSX.utils.sheet_to_json(sheet, {
|
||||||
defval: "",
|
defval: "",
|
||||||
header: headers,
|
header: headers,
|
||||||
range: 1,
|
range: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
// the base of the import
|
// the base of the import
|
||||||
const predefinedObject = {
|
const predefinedObject = {
|
||||||
receivingPlantId: plantToken[0].value,
|
receivingPlantId: plantToken[0].value,
|
||||||
documentName: `OrdersFromLST-${new Date(Date.now()).toLocaleString(
|
documentName: `OrdersFromLST-${new Date(Date.now()).toLocaleString(
|
||||||
"en-US"
|
"en-US",
|
||||||
)}`,
|
)}`,
|
||||||
sender: user.username || "lst-system",
|
sender: user.username || "lst-system",
|
||||||
externalRefNo: `OrdersFromLST-${new Date(Date.now()).toLocaleString(
|
externalRefNo: `OrdersFromLST-${new Date(Date.now()).toLocaleString(
|
||||||
"en-US"
|
"en-US",
|
||||||
)}`,
|
)}`,
|
||||||
orders: [],
|
orders: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
let newOrders: any = orderData;
|
let newOrders: any = orderData;
|
||||||
|
|
||||||
// filter out the orders that have already been started just to reduce the risk of errors.
|
// filter out the orders that have already been started just to reduce the risk of errors.
|
||||||
newOrders.filter((oo: any) =>
|
newOrders.filter((oo: any) =>
|
||||||
openOrders.some(
|
openOrders.some(
|
||||||
(o: any) => o.CustomerOrderNumber === oo.CustomerOrderNumber
|
(o: any) => o.CustomerOrderNumber === oo.CustomerOrderNumber,
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
// filter out the blanks
|
// filter out the blanks
|
||||||
newOrders = newOrders.filter((z: any) => z.ITEM !== "");
|
newOrders = newOrders.filter((z: any) => z.ITEM !== "");
|
||||||
|
|
||||||
// let postedOrders: any = [];
|
// let postedOrders: any = [];
|
||||||
// for (const [customerID, orders] of Object.entries(orderData)) {
|
// for (const [customerID, orders] of Object.entries(orderData)) {
|
||||||
// // console.log(`Running for Customer ID: ${customerID}`);
|
// // console.log(`Running for Customer ID: ${customerID}`);
|
||||||
// const newOrders: any = orderData;
|
// const newOrders: any = orderData;
|
||||||
|
|
||||||
// // filter out the orders that have already been started just to reduce the risk of errors.
|
// // filter out the orders that have already been started just to reduce the risk of errors.
|
||||||
// newOrders.filter((oo: any) =>
|
// newOrders.filter((oo: any) =>
|
||||||
// openOrders.some(
|
// openOrders.some(
|
||||||
// (o: any) => o.CustomerOrderNumber === oo.CustomerOrderNumber
|
// (o: any) => o.CustomerOrderNumber === oo.CustomerOrderNumber
|
||||||
// )
|
// )
|
||||||
// );
|
// );
|
||||||
|
|
||||||
// // map everything out for each order
|
// // map everything out for each order
|
||||||
const nOrder = newOrders.map((o: any) => {
|
const nOrder = newOrders.map((o: any) => {
|
||||||
const invoice = i.filter(
|
const invoice = i.filter(
|
||||||
(i: any) => i.deliveryAddress === parseInt(o.CUSTOMERID)
|
(i: any) => i.deliveryAddress === parseInt(o.CUSTOMERID),
|
||||||
);
|
);
|
||||||
if (!invoice) {
|
if (!invoice) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
customerId: parseInt(o.CUSTOMERID),
|
customerId: parseInt(o.CUSTOMERID),
|
||||||
invoiceAddressId: invoice[0].invoiceAddress, // matched to the default invoice address
|
invoiceAddressId: invoice[0].invoiceAddress, // matched to the default invoice address
|
||||||
customerOrderNo: o.PO,
|
customerOrderNo: o.PO,
|
||||||
orderDate: new Date(Date.now()).toLocaleString("en-US"),
|
orderDate: new Date(Date.now()).toLocaleString("en-US"),
|
||||||
positions: [
|
positions: [
|
||||||
{
|
{
|
||||||
deliveryAddressId: parseInt(o.CUSTOMERID),
|
deliveryAddressId: parseInt(o.CUSTOMERID),
|
||||||
customerArticleNo: o.ITEM,
|
customerArticleNo: o.ITEM,
|
||||||
quantity: parseInt(o.QTY),
|
quantity: parseInt(o.QTY),
|
||||||
deliveryDate: o.DELDATE, //excelDateStuff(o.DELDATE),
|
deliveryDate: o.DELDATE, //excelDateStuff(o.DELDATE),
|
||||||
customerLineItemNo: o.ReleaseNo, // this is how it is currently sent over from abbott
|
customerLineItemNo: o.ReleaseNo, // this is how it is currently sent over from abbott
|
||||||
customerReleaseNo: o.ReleaseNo, // same as above
|
customerReleaseNo: o.ReleaseNo, // same as above
|
||||||
remark: o.remark === "" ? null : o.remark,
|
remark: o.COMMENTS === "" ? null : o.COMMENTS,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// // do that fun combining thing
|
// // do that fun combining thing
|
||||||
const updatedPredefinedObject = {
|
const updatedPredefinedObject = {
|
||||||
...predefinedObject,
|
...predefinedObject,
|
||||||
orders: [...predefinedObject.orders, ...nOrder],
|
orders: [...predefinedObject.orders, ...nOrder],
|
||||||
};
|
};
|
||||||
|
|
||||||
// //console.log(updatedPredefinedObject);
|
// //console.log(updatedPredefinedObject);
|
||||||
|
|
||||||
// // post the orders to the server
|
// // post the orders to the server
|
||||||
const posting: any = await postOrders(updatedPredefinedObject, user);
|
const posting: any = await postOrders(updatedPredefinedObject, user);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
customer: nOrder[0].CUSTOMERID,
|
customer: nOrder[0].CUSTOMERID,
|
||||||
//totalOrders: orders?.length(),
|
//totalOrders: orders?.length(),
|
||||||
success: posting.success,
|
success: posting.success,
|
||||||
message: posting.message,
|
message: posting.message,
|
||||||
data: posting.data,
|
data: posting.data,
|
||||||
};
|
};
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// return {
|
// return {
|
||||||
// success: true,
|
// success: true,
|
||||||
// message:
|
// message:
|
||||||
// "Standard Template was just processed successfully, please check AlplaProd 2.0 to confirm no errors. ",
|
// "Standard Template was just processed successfully, please check AlplaProd 2.0 to confirm no errors. ",
|
||||||
// data: nOrder,
|
// data: nOrder,
|
||||||
// };
|
// };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,166 @@
|
|||||||
|
import XLSX from "xlsx";
|
||||||
|
import { db } from "../../../../../../../database/dbclient.js";
|
||||||
|
import { settings } from "../../../../../../../database/schema/settings.js";
|
||||||
|
import { tryCatch } from "../../../../../../globalUtils/tryCatch.js";
|
||||||
|
import { query } from "../../../../../sqlServer/prodSqlServer.js";
|
||||||
|
import { invoiceAddress } from "../../../../../sqlServer/querys/dm/invoiceAddress.js";
|
||||||
|
import { orderState } from "../../../../../sqlServer/querys/dm/orderState.js";
|
||||||
|
import { excelDateStuff } from "../../../../utils/excelDateStuff.js";
|
||||||
|
import { postOrders } from "../postOrders.js";
|
||||||
|
|
||||||
|
export const scjOrders = async (data: any, user: any) => {
|
||||||
|
/**
|
||||||
|
* Standard orders meaning that we get the standard file exported and fill it out and uplaod to lst.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const customerID = 48;
|
||||||
|
|
||||||
|
const { data: s, error: e } = await tryCatch(db.select().from(settings));
|
||||||
|
|
||||||
|
if (e) {
|
||||||
|
return {
|
||||||
|
sucess: false,
|
||||||
|
message: `Error getting settings`,
|
||||||
|
data: e,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// order state
|
||||||
|
const { data: o, error: oe } = await tryCatch(
|
||||||
|
query(orderState, "Gets the next 500 orders that have not been started"),
|
||||||
|
);
|
||||||
|
|
||||||
|
const openOrders: any = o?.data;
|
||||||
|
|
||||||
|
if (oe) {
|
||||||
|
return {
|
||||||
|
sucess: false,
|
||||||
|
message: `Error getting article data`,
|
||||||
|
data: oe,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// order state
|
||||||
|
const { data: invoice, error: ie } = await tryCatch(
|
||||||
|
query(invoiceAddress, "Gets invoices addresses"),
|
||||||
|
);
|
||||||
|
const i: any = invoice?.data;
|
||||||
|
|
||||||
|
if (ie) {
|
||||||
|
return {
|
||||||
|
sucess: false,
|
||||||
|
message: `Error getting invoice address data`,
|
||||||
|
data: ie,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const plantToken = s.filter((s) => s.name === "plantToken");
|
||||||
|
|
||||||
|
const arrayBuffer = await data.arrayBuffer();
|
||||||
|
const buffer = Buffer.from(arrayBuffer);
|
||||||
|
|
||||||
|
const workbook = XLSX.read(buffer, { type: "buffer" });
|
||||||
|
|
||||||
|
const sheetName: any = workbook.Sheets["Sheet1"];
|
||||||
|
const sheet = XLSX.utils.decode_range(sheetName["!ref"]);
|
||||||
|
|
||||||
|
// define custom headers
|
||||||
|
const headers = [
|
||||||
|
"ItemNo",
|
||||||
|
"Description",
|
||||||
|
"DeliveryDate",
|
||||||
|
"Quantity",
|
||||||
|
"PO",
|
||||||
|
"Releases",
|
||||||
|
"remarks",
|
||||||
|
];
|
||||||
|
const orderData = XLSX.utils.sheet_to_json(sheetName, {
|
||||||
|
defval: "",
|
||||||
|
header: headers,
|
||||||
|
range: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
// the base of the import
|
||||||
|
const predefinedObject = {
|
||||||
|
receivingPlantId: plantToken[0].value,
|
||||||
|
documentName: `OrdersFromLST-${new Date(Date.now()).toLocaleString(
|
||||||
|
"en-US",
|
||||||
|
)}`,
|
||||||
|
sender: user.username || "lst-system",
|
||||||
|
externalRefNo: `OrdersFromLST-${new Date(Date.now()).toLocaleString(
|
||||||
|
"en-US",
|
||||||
|
)}`,
|
||||||
|
orders: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
let newOrders: any = orderData;
|
||||||
|
|
||||||
|
// filter out the orders that have already been started just to reduce the risk of errors.
|
||||||
|
newOrders.filter((oo: any) =>
|
||||||
|
openOrders.some(
|
||||||
|
(o: any) => o.CustomerOrderNumber === oo.CustomerOrderNumber,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// filter out the blanks
|
||||||
|
newOrders = newOrders.filter((z: any) => z.ItemNo !== "");
|
||||||
|
|
||||||
|
const nOrder = newOrders.map((o: any) => {
|
||||||
|
const invoice = i.filter((i: any) => i.deliveryAddress === customerID);
|
||||||
|
if (!invoice) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (o.Releases === "") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (o.PO === "") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const date = isNaN(o.DeliveryDate)
|
||||||
|
? new Date(o.DeliveryDate)
|
||||||
|
: excelDateStuff(o.DeliveryDate);
|
||||||
|
return {
|
||||||
|
customerId: customerID,
|
||||||
|
invoiceAddressId: invoice[0].invoiceAddress, // matched to the default invoice address
|
||||||
|
customerOrderNo: o.PO,
|
||||||
|
orderDate: new Date(Date.now()).toLocaleString("en-US"),
|
||||||
|
positions: [
|
||||||
|
{
|
||||||
|
deliveryAddressId: customerID,
|
||||||
|
customerArticleNo: o.ItemNo,
|
||||||
|
quantity: parseInt(o.Quantity),
|
||||||
|
deliveryDate: date, //excelDateStuff(o.DELDATE),
|
||||||
|
customerLineItemNo: o.PO, // this is how it is currently sent over from abbott
|
||||||
|
customerReleaseNo: o.Releases, // same as above
|
||||||
|
remark: o.remarks === "" ? null : o.remarks,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
//console.log(nOrder.filter((o: any) => o !== undefined));
|
||||||
|
|
||||||
|
// // do that fun combining thing
|
||||||
|
const updatedPredefinedObject = {
|
||||||
|
...predefinedObject,
|
||||||
|
orders: [
|
||||||
|
...predefinedObject.orders,
|
||||||
|
...nOrder.filter((o: any) => o !== undefined),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
//console.log(updatedPredefinedObject.orders[0]);
|
||||||
|
|
||||||
|
// // post the orders to the server
|
||||||
|
const posting: any = await postOrders(updatedPredefinedObject, user);
|
||||||
|
|
||||||
|
return {
|
||||||
|
customer: customerID,
|
||||||
|
//totalOrders: orders?.length(),
|
||||||
|
success: posting.success,
|
||||||
|
message: posting.message,
|
||||||
|
data: posting.data,
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -1,61 +1,70 @@
|
|||||||
import { abbottOrders } from "./mappings/abbottTruckList.js";
|
import { abbottOrders } from "./mappings/abbottTruckList.js";
|
||||||
import { energizerOrders } from "./mappings/energizerOrdersIn.js";
|
import { energizerOrders } from "./mappings/energizerOrdersIn.js";
|
||||||
import { macroImportOrders } from "./mappings/macroImport.js";
|
import { macroImportOrders } from "./mappings/macroImport.js";
|
||||||
|
import { scjOrders } from "./mappings/scj.js";
|
||||||
import { standardOrders } from "./mappings/standardOrders.js";
|
import { standardOrders } from "./mappings/standardOrders.js";
|
||||||
|
|
||||||
export const ordersIn = async (data: any, user: any) => {
|
export const ordersIn = async (data: any, user: any) => {
|
||||||
/**
|
/**
|
||||||
* Bulk orders in, and custom file parsing.
|
* Bulk orders in, and custom file parsing.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let success = true;
|
let success = true;
|
||||||
let message = "";
|
let message = "";
|
||||||
let orderData: any = [];
|
let orderData: any = [];
|
||||||
|
|
||||||
// what type of order are we dealing with?
|
// what type of order are we dealing with?
|
||||||
if (data["fileType"] === "standard") {
|
if (data["fileType"] === "standard") {
|
||||||
// run the standard orders in
|
// run the standard orders in
|
||||||
const standard = await standardOrders(data["postOrders"], user);
|
const standard = await standardOrders(data["postOrders"], user);
|
||||||
success = standard.success ?? false;
|
success = standard.success ?? false;
|
||||||
message = standard.message ?? "Error posting Standard Orders";
|
message = standard.message ?? "Error posting Standard Orders";
|
||||||
orderData = standard.data;
|
orderData = standard.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data["fileType"] === "abbott") {
|
if (data["fileType"] === "abbott") {
|
||||||
// orders in
|
// orders in
|
||||||
const abbott = await abbottOrders(data["postOrders"], user);
|
const abbott = await abbottOrders(data["postOrders"], user);
|
||||||
success = abbott.success ?? false;
|
success = abbott.success ?? false;
|
||||||
message = abbott.message ?? "Error posting Abbott Orders";
|
message = abbott.message ?? "Error posting Abbott Orders";
|
||||||
orderData = abbott.data;
|
orderData = abbott.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data["fileType"] === "energizer") {
|
if (data["fileType"] === "energizer") {
|
||||||
// orders in
|
// orders in
|
||||||
const energizer = await energizerOrders(data["postOrders"], user);
|
const energizer = await energizerOrders(data["postOrders"], user);
|
||||||
success = energizer.success ?? false;
|
success = energizer.success ?? false;
|
||||||
message = energizer.message ?? "Error posting Energizer Orders";
|
message = energizer.message ?? "Error posting Energizer Orders";
|
||||||
orderData = energizer.data;
|
orderData = energizer.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data["fileType"] === "loreal") {
|
if (data["fileType"] === "loreal") {
|
||||||
// orders in
|
// orders in
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data["fileType"] === "pg") {
|
if (data["fileType"] === "pg") {
|
||||||
// orders in
|
// orders in
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data["fileType"] === "macro") {
|
if (data["fileType"] === "macro") {
|
||||||
// orders in
|
// orders in
|
||||||
const macro = await macroImportOrders(data["postOrders"], user);
|
const macro = await macroImportOrders(data["postOrders"], user);
|
||||||
success = macro.success ?? false;
|
success = macro.success ?? false;
|
||||||
message = macro.message ?? "Error posting Macro Orders";
|
message = macro.message ?? "Error posting Macro Orders";
|
||||||
orderData = macro.data;
|
orderData = macro.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
if (data["fileType"] === "scj") {
|
||||||
success,
|
// orders in
|
||||||
message,
|
const macro = await scjOrders(data["postOrders"], user);
|
||||||
data: orderData,
|
success = macro.success ?? false;
|
||||||
};
|
message = macro.message ?? "Error posting Macro Orders";
|
||||||
|
orderData = macro.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success,
|
||||||
|
message,
|
||||||
|
data: orderData,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,78 +1,78 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { labelData } from "../../../sqlServer/querys/materialHelpers/labelInfo.js";
|
|
||||||
|
|
||||||
import { query } from "../../../sqlServer/prodSqlServer.js";
|
|
||||||
import { createLog } from "../../../logger/logger.js";
|
|
||||||
|
|
||||||
import { prodEndpointCreation } from "../../../../globalUtils/createUrl.js";
|
|
||||||
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
|
|
||||||
import { db } from "../../../../../database/dbclient.js";
|
import { db } from "../../../../../database/dbclient.js";
|
||||||
import { commandLog } from "../../../../../database/schema/commandLog.js";
|
import { commandLog } from "../../../../../database/schema/commandLog.js";
|
||||||
|
import { prodEndpointCreation } from "../../../../globalUtils/createUrl.js";
|
||||||
|
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
|
||||||
|
import { createLog } from "../../../logger/logger.js";
|
||||||
|
import { query } from "../../../sqlServer/prodSqlServer.js";
|
||||||
|
import { labelData } from "../../../sqlServer/querys/materialHelpers/labelInfo.js";
|
||||||
|
import { labelInfo } from "../../../sqlServer/querys/warehouse/labelInfo.js";
|
||||||
|
|
||||||
type Data = {
|
type Data = {
|
||||||
runningNr: string;
|
runningNr: string;
|
||||||
lotNum: number;
|
lotNum: number;
|
||||||
};
|
};
|
||||||
export const consumeMaterial = async (data: Data) => {
|
export const consumeMaterial = async (data: Data) => {
|
||||||
const { runningNr, lotNum } = data;
|
const { runningNr, lotNum } = data;
|
||||||
// replace the rn
|
// replace the rn
|
||||||
|
|
||||||
console.log(data);
|
// console.log(data);
|
||||||
|
|
||||||
const rnReplace = labelData.replaceAll("[rn]", runningNr);
|
const rnReplace = labelInfo.replaceAll("[runningNr]", runningNr);
|
||||||
|
|
||||||
let barcode;
|
let barcode;
|
||||||
// get the barcode from the running number
|
// get the barcode from the running number
|
||||||
try {
|
try {
|
||||||
const r: any = await query(rnReplace, "labelData");
|
const r: any = await query(rnReplace, "labelData");
|
||||||
barcode = r?.data;
|
//console.log(r);
|
||||||
} catch (error) {
|
barcode = r?.data;
|
||||||
console.log(error);
|
} catch (error) {
|
||||||
createLog("error", "", "logistics", `Error getting barcode: ${error}`);
|
console.log(error);
|
||||||
}
|
createLog("error", "", "logistics", `Error getting barcode: ${error}`);
|
||||||
|
}
|
||||||
|
|
||||||
if (barcode.length === 0) {
|
if (barcode.length === 0) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
message: "The running number you've entered not on stock.",
|
message: "The running number you've entered not on stock.",
|
||||||
};
|
};
|
||||||
//throw Error("The provided runningNr is not in stock");
|
//throw Error("The provided runningNr is not in stock");
|
||||||
}
|
}
|
||||||
// create the url to post
|
// create the url to post
|
||||||
const url = await prodEndpointCreation(
|
const url = await prodEndpointCreation(
|
||||||
"/public/v1.0/IssueMaterial/ConsumeNonPreparedManualMaterial"
|
"/public/v1.0/IssueMaterial/ConsumeNonPreparedManualMaterial",
|
||||||
);
|
);
|
||||||
|
|
||||||
const consumeSomething = {
|
const consumeSomething = {
|
||||||
productionLot: lotNum,
|
productionLot: lotNum,
|
||||||
barcode: barcode[0]?.barcode,
|
barcode: barcode[0]?.barcode,
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const results = await axios.post(url, consumeSomething, {
|
const results = await axios.post(url, consumeSomething, {
|
||||||
headers: {
|
headers: {
|
||||||
"X-API-Key": process.env.TEC_API_KEY || "",
|
"X-API-Key": process.env.TEC_API_KEY || "",
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data: commandL, error: ce } = await tryCatch(
|
const { data: commandL, error: ce } = await tryCatch(
|
||||||
db.insert(commandLog).values({
|
db.insert(commandLog).values({
|
||||||
commandUsed: "consumeMaterial",
|
commandUsed: "consumeMaterial",
|
||||||
bodySent: data,
|
bodySent: data,
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
message: "Material was consumed",
|
message: "Material was consumed",
|
||||||
status: results.status,
|
status: results.status,
|
||||||
};
|
};
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
status: 200,
|
status: 200,
|
||||||
message: error.response?.data.errors[0].message,
|
message: error.response?.data.errors[0].message,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { prodEndpointCreation } from "../../../../globalUtils/createUrl.js";
|
import { prodEndpointCreation } from "../../../../globalUtils/createUrl.js";
|
||||||
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
|
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
|
||||||
|
import { query } from "../../../sqlServer/prodSqlServer.js";
|
||||||
|
|
||||||
export const postAdjustment = async (data: any) => {
|
export const postAdjustment = async (data: any) => {
|
||||||
if (data.warehouseId === undefined) {
|
if (data.warehouseId === undefined) {
|
||||||
@@ -35,9 +36,30 @@ export const postAdjustment = async (data: any) => {
|
|||||||
quantity: data.quantity,
|
quantity: data.quantity,
|
||||||
};
|
};
|
||||||
|
|
||||||
let url = await prodEndpointCreation(
|
// do we have warehousing turned on?
|
||||||
"/public/v1.0/Warehousing/AdjustSiloStockLevel",
|
const { data: feature, error: featureError } = (await tryCatch(
|
||||||
);
|
query(
|
||||||
|
`SELECT [Id]
|
||||||
|
,[Feature]
|
||||||
|
,[Enabled]
|
||||||
|
,[ActivationDate]
|
||||||
|
FROM [test1_AlplaPROD2.0_Read].[support].[FeatureActivation] where [Feature] = 7`,
|
||||||
|
"feature switch check",
|
||||||
|
),
|
||||||
|
)) as any;
|
||||||
|
|
||||||
|
let prodUrl = "/public/v1.0/Warehousing/AdjustSiloStockLevel";
|
||||||
|
if (featureError) {
|
||||||
|
prodUrl = "/public/v1.0/Warehousing/AdjustSiloStockLevel";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (feature?.data.length > 0) {
|
||||||
|
prodUrl = "/public/v1.1/Warehousing/Lane/AdjustSiloStockLevel";
|
||||||
|
}
|
||||||
|
// 1.0 "/public/v1.0/Warehousing/AdjustSiloStockLevel","
|
||||||
|
// 1.1 "/public/v1.1/Warehousing/Lane/AdjustSiloStockLevel"
|
||||||
|
|
||||||
|
let url = await prodEndpointCreation(prodUrl);
|
||||||
|
|
||||||
const { data: silo, error } = await tryCatch(
|
const { data: silo, error } = await tryCatch(
|
||||||
axios.post(url, siloAdjustment, {
|
axios.post(url, siloAdjustment, {
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { OpenAPIHono } from "@hono/zod-openapi";
|
import { OpenAPIHono } from "@hono/zod-openapi";
|
||||||
|
|
||||||
import { migrateAdjustments } from "./controller/siloAdjustments/migrateAdjustments.js";
|
import { migrateAdjustments } from "./controller/siloAdjustments/migrateAdjustments.js";
|
||||||
import { getLanesToCycleCount } from "./controller/warehouse/cycleCountChecks/cyclecountCheck.js";
|
import { getLanesToCycleCount } from "./controller/warehouse/cycleCountChecks/cyclecountCheck.js";
|
||||||
import attachSilo from "./route/attachSilo.js";
|
import attachSilo from "./route/attachSilo.js";
|
||||||
|
import bookOutPallet from "./route/bookout.js";
|
||||||
import comsumeMaterial from "./route/consumeMaterial.js";
|
import comsumeMaterial from "./route/consumeMaterial.js";
|
||||||
import detachSilo from "./route/detachSilo.js";
|
import detachSilo from "./route/detachSilo.js";
|
||||||
import postBulkOrders from "./route/dm/bulkOrdersIn.js";
|
import postBulkOrders from "./route/dm/bulkOrdersIn.js";
|
||||||
@@ -16,6 +18,7 @@ import outbound from "./route/getOutbound.js";
|
|||||||
import getPPOO from "./route/getPPOO.js";
|
import getPPOO from "./route/getPPOO.js";
|
||||||
import getConnectionType from "./route/getSiloConnectionData.js";
|
import getConnectionType from "./route/getSiloConnectionData.js";
|
||||||
import getSSCC from "./route/getSSCCNumber.js";
|
import getSSCC from "./route/getSSCCNumber.js";
|
||||||
|
import relocate from "./route/relocate.js";
|
||||||
import removeAsNonReable from "./route/removeAsNonReusable.js";
|
import removeAsNonReable from "./route/removeAsNonReusable.js";
|
||||||
import returnMat from "./route/returnMaterial.js";
|
import returnMat from "./route/returnMaterial.js";
|
||||||
import createSiloAdjustment from "./route/siloAdjustments/createSiloAdjustment.js";
|
import createSiloAdjustment from "./route/siloAdjustments/createSiloAdjustment.js";
|
||||||
@@ -28,7 +31,7 @@ const app = new OpenAPIHono();
|
|||||||
const routes = [
|
const routes = [
|
||||||
comsumeMaterial,
|
comsumeMaterial,
|
||||||
returnMat,
|
returnMat,
|
||||||
|
relocate,
|
||||||
// silo
|
// silo
|
||||||
createSiloAdjustment,
|
createSiloAdjustment,
|
||||||
postComment,
|
postComment,
|
||||||
@@ -55,6 +58,7 @@ const routes = [
|
|||||||
// logisitcs
|
// logisitcs
|
||||||
removeAsNonReable,
|
removeAsNonReable,
|
||||||
getSSCC,
|
getSSCC,
|
||||||
|
bookOutPallet,
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
// app.route("/server", modules);
|
// app.route("/server", modules);
|
||||||
|
|||||||
87
lstV2/server/services/logistics/route/bookout.ts
Normal file
87
lstV2/server/services/logistics/route/bookout.ts
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
|
||||||
|
import { verify } from "hono/jwt";
|
||||||
|
import { apiHit } from "../../../globalUtils/apiHits.js";
|
||||||
|
import { tryCatch } from "../../../globalUtils/tryCatch.js";
|
||||||
|
//import { authMiddleware } from "../../auth/middleware/authMiddleware.js";
|
||||||
|
import { bookOutPallet } from "../controller/commands/bookout.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: "Consumes material based on its running number",
|
||||||
|
method: "post",
|
||||||
|
path: "/bookout",
|
||||||
|
//middleware: authMiddleware,
|
||||||
|
description:
|
||||||
|
"Provided a running number and lot number you can consume 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) => {
|
||||||
|
const { data, error } = await tryCatch(c.req.json());
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return c.json(
|
||||||
|
{
|
||||||
|
success: false,
|
||||||
|
message: "Missing data please try again",
|
||||||
|
error,
|
||||||
|
},
|
||||||
|
400,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
apiHit(c, { endpoint: "/bookout", lastBody: data });
|
||||||
|
//const authHeader = c.req.header("Authorization");
|
||||||
|
//const token = authHeader?.split("Bearer ")[1] || "";
|
||||||
|
|
||||||
|
//const payload = await verify(token, process.env.JWT_SECRET!);
|
||||||
|
try {
|
||||||
|
//return apiReturn(c, true, access?.message, access?.data, 200);
|
||||||
|
|
||||||
|
//const pointData = { ...data, user: payload.user };
|
||||||
|
|
||||||
|
const bookout = await bookOutPallet(data);
|
||||||
|
|
||||||
|
console.log("from booout:", bookout);
|
||||||
|
return c.json(
|
||||||
|
{
|
||||||
|
success: bookout?.success,
|
||||||
|
message: bookout?.message,
|
||||||
|
data: bookout.data,
|
||||||
|
},
|
||||||
|
200,
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.log("from error:", 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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
export default app;
|
||||||
80
lstV2/server/services/logistics/route/relocate.ts
Normal file
80
lstV2/server/services/logistics/route/relocate.ts
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
|
||||||
|
import { apiHit } from "../../../globalUtils/apiHits.js";
|
||||||
|
import { tryCatch } from "../../../globalUtils/tryCatch.js";
|
||||||
|
import { authMiddleware } from "../../auth/middleware/authMiddleware.js";
|
||||||
|
import { relatePallet } from "../controller/commands/relocated.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: "Consumes material based on its running number",
|
||||||
|
method: "post",
|
||||||
|
path: "/relocate",
|
||||||
|
//middleware: authMiddleware,
|
||||||
|
description:
|
||||||
|
"Provided a running number and lot number you can consume 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) => {
|
||||||
|
const { data, error } = await tryCatch(c.req.json());
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return c.json(
|
||||||
|
{
|
||||||
|
success: false,
|
||||||
|
message: "Missing data please try again",
|
||||||
|
error,
|
||||||
|
},
|
||||||
|
400,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
apiHit(c, { endpoint: "/relocate", lastBody: data });
|
||||||
|
//const authHeader = c.req.header("Authorization");
|
||||||
|
//const token = authHeader?.split("Bearer ")[1] || "";
|
||||||
|
|
||||||
|
//const payload = await verify(token, process.env.JWT_SECRET!);
|
||||||
|
try {
|
||||||
|
//return apiReturn(c, true, access?.message, access?.data, 200);
|
||||||
|
|
||||||
|
const consume = await relatePallet(data);
|
||||||
|
|
||||||
|
console.log(consume);
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
export default app;
|
||||||
@@ -1,34 +1,60 @@
|
|||||||
import { getJsDateFromExcel } from "excel-date-to-js";
|
import { getJsDateFromExcel } from "excel-date-to-js";
|
||||||
|
|
||||||
export const excelDateStuff = (serial: number, time: any = 0) => {
|
// export const excelDateStuff = (serial: number, time?: any) => {
|
||||||
// console.log(serial);
|
// // add 5 hours or the offset to utc
|
||||||
// add 5 hours or the offset to utc
|
|
||||||
|
|
||||||
// get the local timezone
|
// // get the local timezone
|
||||||
const localoffset = new Date().getTimezoneOffset() / 60; // then divide by 60 to get the true number;
|
// const localoffset = new Date().getTimezoneOffset() / 60; // then divide by 60 to get the true number;
|
||||||
|
|
||||||
if (serial % 1 === 0) {
|
// if (!time) {
|
||||||
time = 800;
|
// time = 800;
|
||||||
}
|
// }
|
||||||
|
|
||||||
const addHours = serial + localoffset / 24;
|
// const addHours = serial + localoffset / 24;
|
||||||
//console.log(getJsDateFromExcel(addHours));
|
// //console.log(getJsDateFromExcel(addHours));
|
||||||
if (typeof serial !== "number" || serial <= 0) {
|
// if (typeof serial !== "number" || serial <= 0) {
|
||||||
return "invalid Date";
|
// return "invalid Date";
|
||||||
}
|
// }
|
||||||
|
|
||||||
const date = getJsDateFromExcel(addHours); // base date from Excel serial
|
// const date = getJsDateFromExcel(addHours); // base date from Excel serial
|
||||||
|
|
||||||
if (time != 0) {
|
// if (time != 0) {
|
||||||
// convert the time over to hour and min
|
// // convert the time over to hour and min
|
||||||
const hours = Math.floor(time / 100);
|
// const hours = Math.floor(time / 100);
|
||||||
const minutes = time % 100;
|
// const minutes = time % 100;
|
||||||
date.setHours(hours);
|
// date.setHours(hours);
|
||||||
date.setMinutes(minutes);
|
// date.setMinutes(minutes);
|
||||||
}
|
// }
|
||||||
//console.log(date.toLocaleString("en-US"), getJsDateFromExcel(addHours));
|
// //console.log(date.toLocaleString("en-US"), getJsDateFromExcel(addHours));
|
||||||
|
|
||||||
//console.log(serial);
|
// //console.log(serial);
|
||||||
//console.log(date.toISOString());
|
// console.log(date.toISOString(), serial, time);
|
||||||
return date.toISOString(); //.toLocaleString("en-US"); // or .toISOString() if preferred
|
// return date.toISOString(); //.toLocaleString("en-US"); // or .toISOString() if preferred
|
||||||
|
// };
|
||||||
|
|
||||||
|
export const excelDateStuff = (serial: number, time?: any) => {
|
||||||
|
if (typeof serial !== "number" || serial <= 0) {
|
||||||
|
return "invalid Date";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default time to 8:00 AM if not provided
|
||||||
|
if (!time) {
|
||||||
|
time = 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get base date from Excel serial (this gives you UTC midnight)
|
||||||
|
const date = getJsDateFromExcel(serial);
|
||||||
|
|
||||||
|
const localOffset = new Date().getTimezoneOffset() / 60;
|
||||||
|
const hours = Math.floor(time / 100);
|
||||||
|
const minutes = time % 100;
|
||||||
|
|
||||||
|
// Set the time in UTC
|
||||||
|
date.setUTCHours(hours + localOffset);
|
||||||
|
date.setUTCMinutes(minutes);
|
||||||
|
date.setUTCSeconds(0);
|
||||||
|
date.setUTCMilliseconds(0);
|
||||||
|
|
||||||
|
//console.log(date.toISOString(), serial, time);
|
||||||
|
return date.toISOString();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,95 +4,92 @@ import { notifications } from "../../../../../database/schema/notifications.js";
|
|||||||
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
|
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
|
||||||
import { createLog } from "../../../logger/logger.js";
|
import { createLog } from "../../../logger/logger.js";
|
||||||
import { query } from "../../../sqlServer/prodSqlServer.js";
|
import { query } from "../../../sqlServer/prodSqlServer.js";
|
||||||
import { sendEmail } from "../sendMail.js";
|
|
||||||
import { bow2incoming } from "../../../sqlServer/querys/notifications/bow2henkel.js";
|
import { bow2incoming } from "../../../sqlServer/querys/notifications/bow2henkel.js";
|
||||||
|
import { sendEmail } from "../sendMail.js";
|
||||||
|
|
||||||
const notification = async (notifyData: any) => {
|
const notification = async (notifyData: any) => {
|
||||||
/**
|
/**
|
||||||
* Pass the entire notification over
|
* Pass the entire notification over
|
||||||
*/
|
*/
|
||||||
createLog("debug", "reprinting", "notify", `monitoring ${notifyData.name}`);
|
createLog("debug", "reprinting", "notify", `monitoring ${notifyData.name}`);
|
||||||
|
|
||||||
// validate if there are any emails.
|
// validate if there are any emails.
|
||||||
if (notifyData.emails === "") {
|
if (notifyData.emails === "") {
|
||||||
createLog(
|
createLog(
|
||||||
"error",
|
"error",
|
||||||
"reprinting",
|
"reprinting",
|
||||||
"notify",
|
"notify",
|
||||||
`There are no emails set for ${notifyData.name}`
|
`There are no emails set for ${notifyData.name}`,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//let labels: Labels[];
|
//let labels: Labels[];
|
||||||
|
|
||||||
const { data: l, error: labelError } = await tryCatch(
|
const { data: l, error: labelError } = await tryCatch(
|
||||||
query(
|
query(
|
||||||
bow2incoming.replace(
|
bow2incoming.replace("[time]", notifyData.notifiySettings.processTime),
|
||||||
"[time]",
|
"Label Reprints",
|
||||||
notifyData.notifiySettings.processTime
|
),
|
||||||
),
|
);
|
||||||
"Label Reprints"
|
const labels: any = l?.data as any;
|
||||||
)
|
if (labelError) {
|
||||||
);
|
createLog(
|
||||||
const labels: any = l?.data as any;
|
"error",
|
||||||
if (labelError) {
|
"reprinting",
|
||||||
createLog(
|
"notify",
|
||||||
"error",
|
`Failed to get the labels: ${labelError}`,
|
||||||
"reprinting",
|
);
|
||||||
"notify",
|
return;
|
||||||
`Failed to get the labels: ${labelError}`
|
}
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (labels.length > 0) {
|
if (labels.length > 0) {
|
||||||
//send the email :D
|
//send the email :D
|
||||||
const emailSetup = {
|
const emailSetup = {
|
||||||
email: notifyData.emails,
|
email: notifyData.emails,
|
||||||
subject: "Alert! New incoming goods has been received",
|
subject: "Alert! New incoming goods has been received",
|
||||||
template: "bow2IncomingGoods",
|
template: "bow2IncomingGoods",
|
||||||
context: {
|
context: {
|
||||||
items: labels,
|
items: labels,
|
||||||
time: notifyData.notifiySettings.processTime,
|
time: notifyData.notifiySettings.processTime,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const sentEmail = await sendEmail(emailSetup);
|
const sentEmail = await sendEmail(emailSetup);
|
||||||
|
|
||||||
if (!sentEmail.success) {
|
if (!sentEmail.success) {
|
||||||
createLog(
|
createLog(
|
||||||
"error",
|
"error",
|
||||||
"reprinting",
|
"reprinting",
|
||||||
"notify",
|
"notify",
|
||||||
"Failed to send email, will try again on next interval"
|
"Failed to send email, will try again on next interval",
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// // update the last time we ran and the prod id
|
// // update the last time we ran and the prod id
|
||||||
// const notifUpdate = {
|
// const notifUpdate = {
|
||||||
// prodID: labels[0].IdEtikettenHistorie,
|
// prodID: labels[0].IdEtikettenHistorie,
|
||||||
// lastRan: nowDate(),
|
// lastRan: nowDate(),
|
||||||
// };
|
// };
|
||||||
|
|
||||||
// update the last time ran
|
// update the last time ran
|
||||||
|
|
||||||
const { data, error } = await tryCatch(
|
const { data, error } = await tryCatch(
|
||||||
db
|
db
|
||||||
.update(notifications)
|
.update(notifications)
|
||||||
.set({
|
.set({
|
||||||
lastRan: sql`NOW()`,
|
lastRan: sql`NOW()`,
|
||||||
notifiySettings: {
|
notifiySettings: {
|
||||||
...notifyData.notifiySettings,
|
...notifyData.notifiySettings,
|
||||||
prodID: labels[0].IdEtikettenHistorie,
|
prodID: labels[0].IdEtikettenHistorie,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.where(eq(notifications.name, notifyData.name))
|
.where(eq(notifications.name, notifyData.name)),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default notification;
|
export default notification;
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
import { eq, sql } from "drizzle-orm";
|
||||||
|
import { db } from "../../../../../database/dbclient.js";
|
||||||
|
import { notifications } from "../../../../../database/schema/notifications.js";
|
||||||
|
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
|
||||||
|
import { createLog } from "../../../logger/logger.js";
|
||||||
|
import { query } from "../../../sqlServer/prodSqlServer.js";
|
||||||
|
import {
|
||||||
|
type SqlQuery,
|
||||||
|
sqlQuerySelector,
|
||||||
|
} from "../../../sqlServer/utils/querySelector.utils.js";
|
||||||
|
import { sendEmail } from "../sendMail.js";
|
||||||
|
|
||||||
|
export interface Labels {
|
||||||
|
IdEtikettenHistorie?: number;
|
||||||
|
}
|
||||||
|
const notification = async (notifyData: any) => {
|
||||||
|
/**
|
||||||
|
* Pass the entire notification over
|
||||||
|
*/
|
||||||
|
createLog("debug", "reprinting", "notify", `monitoring ${notifyData.name}`);
|
||||||
|
|
||||||
|
// validate if there are any emails.
|
||||||
|
if (notifyData.emails === "") {
|
||||||
|
createLog(
|
||||||
|
"error",
|
||||||
|
"reprinting",
|
||||||
|
"notify",
|
||||||
|
`There are no emails set for ${notifyData.name}`,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const cycleCountCheck = sqlQuerySelector("cycleCountCheck.query") as SqlQuery;
|
||||||
|
|
||||||
|
if (!cycleCountCheck.success) {
|
||||||
|
console.log("Failed to load the query: ", cycleCountCheck.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data: c, error: cError } = await tryCatch(
|
||||||
|
query(
|
||||||
|
cycleCountCheck.query.replace("[timeTest]", notifyData.checkInterval),
|
||||||
|
"Cycle count check",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
const cycle: any = c?.data ?? ([] as any);
|
||||||
|
|
||||||
|
//console.log(cycle);
|
||||||
|
|
||||||
|
if (cError) {
|
||||||
|
createLog(
|
||||||
|
"error",
|
||||||
|
"reprinting",
|
||||||
|
"notify",
|
||||||
|
`Failed to get the labels: ${cError}`,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cycle.length > 0) {
|
||||||
|
//send the email :D
|
||||||
|
const emailSetup = {
|
||||||
|
email: notifyData.emails,
|
||||||
|
subject: `Alert! RowBlocked for more than ${notifyData.checkInterval} min(s)`,
|
||||||
|
template: "cycleCountCheck",
|
||||||
|
context: {
|
||||||
|
checkTime: notifyData.checkInterval,
|
||||||
|
items: cycle,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const sentEmail = await sendEmail(emailSetup);
|
||||||
|
|
||||||
|
if (!sentEmail.success) {
|
||||||
|
createLog(
|
||||||
|
"error",
|
||||||
|
"reprinting",
|
||||||
|
"notify",
|
||||||
|
"Failed to send email, will try again on next interval",
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// // update the last time we ran and the prod id
|
||||||
|
// const notifUpdate = {
|
||||||
|
// prodID: labels[0].IdEtikettenHistorie,
|
||||||
|
// lastRan: nowDate(),
|
||||||
|
// };
|
||||||
|
|
||||||
|
// update the last time ran
|
||||||
|
|
||||||
|
const { data, error } = await tryCatch(
|
||||||
|
db
|
||||||
|
.update(notifications)
|
||||||
|
.set({
|
||||||
|
lastRan: sql`NOW()`,
|
||||||
|
// notifiySettings: {
|
||||||
|
// ...notifyData.notifiySettings,
|
||||||
|
// prodID: labels[0].IdEtikettenHistorie,
|
||||||
|
// },
|
||||||
|
})
|
||||||
|
.where(eq(notifications.name, notifyData.name)),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default notification;
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user