Compare commits
78 Commits
7311372ba8
...
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 |
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",
|
||||||
|
|||||||
32
CHANGELOG.md
32
CHANGELOG.md
@@ -1,5 +1,37 @@
|
|||||||
# 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)
|
## [1.8.0](https://git.tuffraid.net/cowch/lst/compare/v1.7.0...v1.8.0) (2025-11-25)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
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
|
||||||
|
}
|
||||||
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
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ post {
|
|||||||
}
|
}
|
||||||
|
|
||||||
params:path {
|
params:path {
|
||||||
token:
|
token: test3
|
||||||
}
|
}
|
||||||
|
|
||||||
settings {
|
settings {
|
||||||
|
|||||||
@@ -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,5 +1,5 @@
|
|||||||
vars {
|
vars {
|
||||||
url: https://usflo1prod.alpla.net
|
url: http://localhost:5500
|
||||||
session_cookie:
|
session_cookie:
|
||||||
urlv2: http://usbow1vms006:3000
|
urlv2: http://usbow1vms006:3000
|
||||||
jwtV2:
|
jwtV2:
|
||||||
|
|||||||
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
|
||||||
|
}
|
||||||
22
app/main.ts
22
app/main.ts
@@ -20,9 +20,7 @@ import { baseSettings } from "./src/internal/system/controller/settings/baseSett
|
|||||||
import {
|
import {
|
||||||
addListeners,
|
addListeners,
|
||||||
manualFixes,
|
manualFixes,
|
||||||
settingsMigrate,
|
|
||||||
} 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";
|
||||||
@@ -35,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 +78,7 @@ const main = async () => {
|
|||||||
|
|
||||||
// connect to the prod sql
|
// connect to the prod sql
|
||||||
console.log("Connecting to the sql server");
|
console.log("Connecting to the sql server");
|
||||||
await initializeProdPool();
|
|
||||||
|
|
||||||
// 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",
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
};
|
||||||
@@ -35,20 +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[0].Bezeichnung, // change this later once we migrate more items
|
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');
|
||||||
|
}
|
||||||
@@ -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,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"],
|
|
||||||
};
|
|
||||||
@@ -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 };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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);
|
||||||
|
// });
|
||||||
@@ -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;
|
||||||
@@ -1,112 +1,112 @@
|
|||||||
import { isBefore } from "date-fns";
|
import { isBefore } from "date-fns";
|
||||||
|
import { db } from "../../../../../database/dbclient.js";
|
||||||
|
import { fifoIndex } from "../../../../../database/schema/fifoIndex.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 { currentInv } from "../../../sqlServer/querys/notifications/fifoIndex/currentInv.js";
|
import { currentInv } from "../../../sqlServer/querys/notifications/fifoIndex/currentInv.js";
|
||||||
import { shippedPallets } from "../../../sqlServer/querys/notifications/fifoIndex/shippedPallets.js";
|
import { shippedPallets } from "../../../sqlServer/querys/notifications/fifoIndex/shippedPallets.js";
|
||||||
import { db } from "../../../../../database/dbclient.js";
|
|
||||||
import { fifoIndex } from "../../../../../database/schema/fifoIndex.js";
|
|
||||||
|
|
||||||
export default async function fifoIndexCheck() {
|
export default async function fifoIndexCheck() {
|
||||||
/**
|
/**
|
||||||
* getting the shipped pallets
|
* getting the shipped pallets
|
||||||
*/
|
*/
|
||||||
const { data: shipped, error: eShipped } = await tryCatch(
|
const { data: shipped, error: eShipped } = await tryCatch(
|
||||||
query(shippedPallets, "notify shipped pallets")
|
query(shippedPallets, "notify shipped pallets"),
|
||||||
);
|
);
|
||||||
|
|
||||||
const { data: currentStuff, error: eCurrentInv } = await tryCatch(
|
const { data: currentStuff, error: eCurrentInv } = await tryCatch(
|
||||||
query(currentInv, "notify shipped pallets")
|
query(currentInv, "notify shipped pallets"),
|
||||||
);
|
);
|
||||||
|
|
||||||
// console.log(shipped?.data[2]);
|
// console.log(shipped?.data[2]);
|
||||||
// console.log(currentStuff?.data[2]);
|
// console.log(currentStuff?.data[2]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We want to check if the each shippened pallet is out of fifo
|
* We want to check if the each shippened pallet is out of fifo
|
||||||
*/
|
*/
|
||||||
const check = shipped?.data.map((n: any) => {
|
const check: any = shipped?.data.map((n: any) => {
|
||||||
/**
|
/**
|
||||||
* Returns all data so we know if we are in or out.
|
* Returns all data so we know if we are in or out.
|
||||||
*/
|
*/
|
||||||
//check if there are pallets older than the current one we are mapped on.
|
//check if there are pallets older than the current one we are mapped on.
|
||||||
const fifoCheck = currentStuff?.data.filter(
|
const fifoCheck = currentStuff?.data.filter(
|
||||||
(i: any) => isBefore(i.prodDate, n.prodDate) && i.av === n.av
|
(i: any) => isBefore(i.prodDate, n.prodDate) && i.av === n.av,
|
||||||
);
|
) as any;
|
||||||
//console.log(fifoCheck.length);
|
//console.log(fifoCheck.length);
|
||||||
if (fifoCheck.length > 0) {
|
if (fifoCheck.length > 0) {
|
||||||
// console.log("Out of fifo", {
|
// console.log("Out of fifo", {
|
||||||
// av: n.av,
|
// av: n.av,
|
||||||
// rn: n.runningNr,
|
// rn: n.runningNr,
|
||||||
// fRn: fifoCheck[0].runningNr,
|
// fRn: fifoCheck[0].runningNr,
|
||||||
// dates: [fifoCheck[0].prodDate, n.prodDate],
|
// dates: [fifoCheck[0].prodDate, n.prodDate],
|
||||||
// });
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...n,
|
...n,
|
||||||
// currentInv: fifoCheck[0],
|
// currentInv: fifoCheck[0],
|
||||||
fifoFollowed: fifoCheck.length === 0 ? true : false,
|
fifoFollowed: fifoCheck.length === 0 ? true : false,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* lets see just the av that is our or in
|
* lets see just the av that is our or in
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const avCheck = (check: any) => {
|
const avCheck = (check: any) => {
|
||||||
/**
|
/**
|
||||||
* This will only return the data based on out of fifo.
|
* This will only return the data based on out of fifo.
|
||||||
*/
|
*/
|
||||||
// check how many times each av showed up
|
// check how many times each av showed up
|
||||||
const avCounts = check.reduce((a: any, c: any) => {
|
const avCounts = check.reduce((a: any, c: any) => {
|
||||||
if (c.fifoFollowed === false) {
|
if (c.fifoFollowed === false) {
|
||||||
const avValue = c.av;
|
const avValue = c.av;
|
||||||
a[avValue] = (a[avValue] || 0) + 1;
|
a[avValue] = (a[avValue] || 0) + 1;
|
||||||
}
|
}
|
||||||
return a;
|
return a;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
// transform them back to an avCount Object
|
// transform them back to an avCount Object
|
||||||
const result = Object.keys(avCounts).map((av) => ({
|
const result = Object.keys(avCounts).map((av) => ({
|
||||||
av: parseInt(av, 10),
|
av: parseInt(av, 10),
|
||||||
count: avCounts[av],
|
count: avCounts[av],
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
const outOfFifo: any = avCheck(check);
|
const outOfFifo: any = avCheck(check);
|
||||||
const totalOut = outOfFifo.reduce((sum: any, c: any) => {
|
const totalOut = outOfFifo.reduce((sum: any, c: any) => {
|
||||||
return sum + c.count;
|
return sum + c.count;
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* add the data to the db
|
* add the data to the db
|
||||||
*/
|
*/
|
||||||
for (let i = 0; i < check.length; i++) {
|
for (let i = 0; i < check!.length; i++) {
|
||||||
const { data: dbInsert, error: dbE } = await tryCatch(
|
const { data: dbInsert, error: dbE } = await tryCatch(
|
||||||
db
|
db
|
||||||
.insert(fifoIndex)
|
.insert(fifoIndex)
|
||||||
.values({
|
.values({
|
||||||
lot: check[i].lot,
|
lot: check[i].lot,
|
||||||
av: check[i].av,
|
av: check[i].av,
|
||||||
runningNr: check[i].runningNr,
|
runningNr: check[i].runningNr,
|
||||||
prodDate: check[i].prodDate,
|
prodDate: check[i].prodDate,
|
||||||
fifoFollowed: check[i].fifoFollowed,
|
fifoFollowed: check[i].fifoFollowed,
|
||||||
add_Date: check[i].add_Date,
|
add_Date: check[i].add_Date,
|
||||||
})
|
})
|
||||||
.onConflictDoNothing()
|
.onConflictDoNothing(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
message: "Fifo index data",
|
message: "Fifo index data",
|
||||||
data: {
|
data: {
|
||||||
palletsOut: check,
|
palletsOut: check,
|
||||||
totalShipped: shipped?.data.length,
|
totalShipped: shipped?.data.length,
|
||||||
inFifo: shipped?.data.length - totalOut,
|
inFifo: shipped!.data.length - totalOut,
|
||||||
outOfFifoData: outOfFifo,
|
outOfFifoData: outOfFifo,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,183 @@
|
|||||||
|
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 { sqlQuerySelector } from "../../../sqlServer/utils/querySelector.utils.js";
|
||||||
|
import { sendEmail } from "../sendMail.js";
|
||||||
|
|
||||||
|
let running = false;
|
||||||
|
export default async function platToPlantEdi(notifyData: any) {
|
||||||
|
createLog("info", "plantToPlant", "notify", `monitoring ${notifyData.name}`);
|
||||||
|
if (running) {
|
||||||
|
createLog(
|
||||||
|
"info",
|
||||||
|
"plantToPlant",
|
||||||
|
"notify",
|
||||||
|
`Notifcation ${notifyData.name} is already running skipping`,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
running = true;
|
||||||
|
|
||||||
|
const { data: noti, error: notiError } = (await tryCatch(
|
||||||
|
db
|
||||||
|
.select()
|
||||||
|
.from(notifications)
|
||||||
|
.where(eq(notifications.name, notifyData.name)),
|
||||||
|
)) as any;
|
||||||
|
|
||||||
|
if (notiError) {
|
||||||
|
createLog(
|
||||||
|
"error",
|
||||||
|
"edi",
|
||||||
|
"notify",
|
||||||
|
"Error in getting the notification data",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the default emails they can be blank if as we will only add these to the end of the email from the full flow
|
||||||
|
let emails = noti[0]?.email ?? "";
|
||||||
|
|
||||||
|
const checkBol = sqlQuerySelector("checkBol.query");
|
||||||
|
|
||||||
|
if (!checkBol.success) {
|
||||||
|
createLog("error", "edi", "notify", "Error in getting the bol query data");
|
||||||
|
}
|
||||||
|
|
||||||
|
const pLinkedB = sqlQuerySelector("palletsLinkedToBol.query");
|
||||||
|
|
||||||
|
if (!pLinkedB.success) {
|
||||||
|
createLog("error", "edi", "notify", "Error in getting the bol query data");
|
||||||
|
}
|
||||||
|
|
||||||
|
let ignoreBols: string[] = noti[0]?.notifiySettings?.processedBol ?? [];
|
||||||
|
|
||||||
|
const joinBols = ignoreBols.join(",");
|
||||||
|
|
||||||
|
let updateQuery = noti[0]?.notifiySettings?.includeAll
|
||||||
|
? checkBol?.query?.replace(
|
||||||
|
"and a.bezeichnung like '%Alpla%'",
|
||||||
|
"--and a.bezeichnung like '%Alpla%'",
|
||||||
|
)
|
||||||
|
: checkBol?.query;
|
||||||
|
|
||||||
|
const { data: b, error: bError } = (await tryCatch(
|
||||||
|
query(
|
||||||
|
updateQuery
|
||||||
|
?.replace("[timeCheck]", noti[0]?.checkInterval ?? "30")
|
||||||
|
.replace("[ignoreBols]", joinBols ?? 500) ?? "",
|
||||||
|
"Check bol",
|
||||||
|
),
|
||||||
|
)) as any;
|
||||||
|
|
||||||
|
if (bError) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: "Error getting newly created bols",
|
||||||
|
data: bError,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const planedByBol = new Map<string, string[]>();
|
||||||
|
|
||||||
|
for (const row of b.data) {
|
||||||
|
if (!planedByBol.has(row.bol)) {
|
||||||
|
planedByBol.set(row.bol, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
planedByBol.get(row.bol)!.push(String(row.idladeplanung));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b.data.length > 0) {
|
||||||
|
// loop each bol in the system and get the bols only
|
||||||
|
for (const [bolNumber, idList] of planedByBol.entries()) {
|
||||||
|
//for (const bol of b.data) {
|
||||||
|
// run the process to get the the pallet numbers
|
||||||
|
|
||||||
|
const joinedIdLadeplanung = idList.join(",");
|
||||||
|
|
||||||
|
//console.log("BOL:", bolNumber);
|
||||||
|
//console.log("IDLadeplanung string:", joinedIdLadeplanung);
|
||||||
|
//console.log("IgnoreBols: ", joinBols);
|
||||||
|
|
||||||
|
// now get the pallets that are witing the ladeplanning
|
||||||
|
const { data: pallets, error: pError } = await tryCatch(
|
||||||
|
query(
|
||||||
|
pLinkedB?.query?.replace(
|
||||||
|
"[palLinkedToBol]",
|
||||||
|
joinedIdLadeplanung ?? "0",
|
||||||
|
) ?? "",
|
||||||
|
"Get Pallets linked in the bol",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
//console.log(pallets);
|
||||||
|
|
||||||
|
// console.log("Address: ", b.data[0].addressId ?? "0");
|
||||||
|
|
||||||
|
if (b.data[0].addressId === "") return;
|
||||||
|
|
||||||
|
ignoreBols.push(bolNumber);
|
||||||
|
if (ignoreBols.length > 15) {
|
||||||
|
ignoreBols.splice(0, ignoreBols.length - 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the email address.
|
||||||
|
const checkBol = sqlQuerySelector("addressInfo.query");
|
||||||
|
|
||||||
|
const { data: address, error: aError } = (await tryCatch(
|
||||||
|
query(
|
||||||
|
checkBol?.query?.replace(
|
||||||
|
"[customerAddress]",
|
||||||
|
b.data[0].addressId ?? "0",
|
||||||
|
) ?? "",
|
||||||
|
"Get Pallets linked in the bol",
|
||||||
|
),
|
||||||
|
)) as any;
|
||||||
|
|
||||||
|
if (noti[0]?.emails === "") return; // no default emails
|
||||||
|
// setup the email to be sent :D
|
||||||
|
const emailSetup = {
|
||||||
|
email: `${noti[0]?.emails};${address.data[0].email ?? ""}`,
|
||||||
|
subject: `New EDI transfer Created for BOL: ${bolNumber}`,
|
||||||
|
template: "plantToPlantEdi",
|
||||||
|
context: {
|
||||||
|
items: pallets?.data ?? [],
|
||||||
|
bol: bolNumber,
|
||||||
|
//secondarySetting: notifyData.notifiySettings,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// send the email
|
||||||
|
await sendEmail(emailSetup);
|
||||||
|
|
||||||
|
// add the bols to be ignored
|
||||||
|
await db
|
||||||
|
.update(notifications)
|
||||||
|
.set({
|
||||||
|
lastRan: sql`NOW()`,
|
||||||
|
notifiySettings: {
|
||||||
|
...noti[0]?.notifiySettings,
|
||||||
|
processedBol: ignoreBols,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.where(eq(notifications.name, notifyData.name));
|
||||||
|
}
|
||||||
|
|
||||||
|
running = false;
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: "All bols have been processed",
|
||||||
|
data: [ignoreBols],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
running = false;
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: "No new bols have been created",
|
||||||
|
data: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
// SELECT count(*) FROM V_EtikettenGedruckt where AnzahlGedruckterKopien > 2 and CONVERT(varchar(5), Add_Date,108) not like CONVERT(varchar(5), Upd_Date,108) and Upd_Date > DATEADD(SECOND, -30,getdate()) and VpkVorschriftBez not like '%$%'
|
||||||
|
|
||||||
|
import { errorMonitor } from "node:events";
|
||||||
|
import { eq, sql } from "drizzle-orm";
|
||||||
|
import { db } from "../../../../../database/dbclient.js";
|
||||||
|
import { notifications } from "../../../../../database/schema/notifications.js";
|
||||||
|
import { settings } from "../../../../../database/schema/settings.js";
|
||||||
|
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
|
||||||
|
import { createLog } from "../../../logger/logger.js";
|
||||||
|
import { sendEmail } from "../sendMail.js";
|
||||||
|
|
||||||
|
export interface DownTime {
|
||||||
|
downTimeId?: number;
|
||||||
|
machineAlias?: string;
|
||||||
|
}
|
||||||
|
export default async function tooManyErrors(notifyData: any) {
|
||||||
|
// we will over ride this with users that want to sub to this
|
||||||
|
// a new table will be called subalerts and link to the do a kinda linkn where the user wants it then it dose subId: 1, userID: x, notificationId: y. then in here we look up the userid to get the email :D
|
||||||
|
// this could then leave the emails in the notificaion blank and let users sub to it.
|
||||||
|
//console.log(notifyData);
|
||||||
|
if (notifyData.emails === "") {
|
||||||
|
createLog(
|
||||||
|
"error",
|
||||||
|
"notify",
|
||||||
|
"notify",
|
||||||
|
`There are no emails set for ${notifyData.name}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// console.log(data.secondarySetting[0].duration);
|
||||||
|
|
||||||
|
const plant = await db
|
||||||
|
.select()
|
||||||
|
.from(settings)
|
||||||
|
.where(eq(settings.name, "plantToken"));
|
||||||
|
console.log(plant[0].value);
|
||||||
|
// console.log(
|
||||||
|
// errorQuery
|
||||||
|
// .replace("[time]", notifyData.checkInterval)
|
||||||
|
// .replace("[errorCount]", notifyData.notifiySettings.errorCount),
|
||||||
|
// errorLogQuery.replace("[time]", notifyData.checkInterval),
|
||||||
|
// );
|
||||||
|
|
||||||
|
let errorLogData: any = [];
|
||||||
|
try {
|
||||||
|
const errorData = await db.execute(sql`
|
||||||
|
SELECT 'error' AS level, COUNT(*) AS error_count
|
||||||
|
FROM public.logs
|
||||||
|
WHERE level = 'error'
|
||||||
|
AND "add_Date" > now() - INTERVAL ${sql.raw(`'${notifyData.checkInterval} minutes'`)}
|
||||||
|
GROUP BY level
|
||||||
|
HAVING COUNT(*) >= ${notifyData.notifiySettings.errorCount}
|
||||||
|
`);
|
||||||
|
if (
|
||||||
|
errorData.length > 0
|
||||||
|
// && downTime[0]?.downTimeId > notifyData.notifiySettings.prodID
|
||||||
|
) {
|
||||||
|
const errorLogs = await db.execute(sql`
|
||||||
|
select* from public.logs where level = 'error' and "add_Date" > now() - INTERVAL ${sql.raw(`'${notifyData.checkInterval} minutes'`)} order by "add_Date" desc;
|
||||||
|
`);
|
||||||
|
|
||||||
|
errorLogData = errorLogs;
|
||||||
|
//send the email :D
|
||||||
|
const emailSetup = {
|
||||||
|
email: notifyData.emails,
|
||||||
|
subject: `Alert! ${plant[0].value} has encountered ${
|
||||||
|
errorLogData.length
|
||||||
|
} ${errorLogData.length > 1 ? "errors" : "error"} in the last ${notifyData.checkInterval} min`,
|
||||||
|
template: "tooManyErrors",
|
||||||
|
context: {
|
||||||
|
data: errorLogData.slice(0, 100),
|
||||||
|
count: notifyData.notifiySettings.errorCount,
|
||||||
|
time: notifyData.checkInterval,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
//console.log(emailSetup);
|
||||||
|
|
||||||
|
const sentEmail = await sendEmail(emailSetup);
|
||||||
|
|
||||||
|
if (!sentEmail.success) {
|
||||||
|
createLog(
|
||||||
|
"error",
|
||||||
|
"notify",
|
||||||
|
"notify",
|
||||||
|
"Failed to send email, will try again on next interval",
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: "Failed to send email, will try again on next interval",
|
||||||
|
data: sentEmail,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
createLog(
|
||||||
|
"error",
|
||||||
|
"notify",
|
||||||
|
"notify",
|
||||||
|
`Error from running the downtimeCheck query: ${err}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: "Error running error data",
|
||||||
|
data: err,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: "Error log checking ran",
|
||||||
|
data: errorLogData ?? [],
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -45,57 +45,57 @@ export const sendEmail = async (data: any): Promise<any> => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
// get the plantToken
|
// get the plantToken
|
||||||
const server = settingData.filter((n) => n.name === "server");
|
//const server = settingData.filter((n) => n.name === "server");
|
||||||
|
|
||||||
if (
|
// if (
|
||||||
server[0].value === "localhostx" &&
|
// server[0].value === "localhostx" &&
|
||||||
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",
|
||||||
host: "smtp.gmail.com",
|
// host: "smtp.gmail.com",
|
||||||
port: 465,
|
// port: 465,
|
||||||
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.
|
||||||
const plantToken = settingData.filter((s) => s.name === "plantToken");
|
//const plantToken = settingData.filter((s) => s.name === "plantToken");
|
||||||
|
|
||||||
let host = `${plantToken[0].value}-smtp.alpla.net`;
|
// let host = `${plantToken[0].value}-smtp.alpla.net`;
|
||||||
|
|
||||||
const testServers = ["test1", "test2", "test3"];
|
// const testServers = ["test1", "test2", "test3"];
|
||||||
|
|
||||||
if (testServers.includes(plantToken[0].value)) {
|
// if (testServers.includes(plantToken[0].value)) {
|
||||||
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,
|
||||||
// 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(
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ import tiTrigger from "./routes/manualTiggerTi.js";
|
|||||||
import materialCheck from "./routes/materialPerDay.js";
|
import materialCheck from "./routes/materialPerDay.js";
|
||||||
import blocking from "./routes/qualityBlocking.js";
|
import blocking from "./routes/qualityBlocking.js";
|
||||||
import sendemail from "./routes/sendMail.js";
|
import sendemail from "./routes/sendMail.js";
|
||||||
|
import errorHandling from "./routes/tooManyErrors.js";
|
||||||
import { note, notificationCreate } from "./utils/masterNotifications.js";
|
import { note, notificationCreate } from "./utils/masterNotifications.js";
|
||||||
|
import { sqlJobCleanUp } from "./utils/notificationSqlCleanup.js";
|
||||||
import { startNotificationMonitor } from "./utils/processNotifications.js";
|
import { startNotificationMonitor } from "./utils/processNotifications.js";
|
||||||
|
|
||||||
const app = new OpenAPIHono();
|
const app = new OpenAPIHono();
|
||||||
@@ -23,6 +25,7 @@ const routes = [
|
|||||||
notify,
|
notify,
|
||||||
fifoIndex,
|
fifoIndex,
|
||||||
materialCheck,
|
materialCheck,
|
||||||
|
errorHandling,
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
const appRoutes = routes.forEach((route) => {
|
const appRoutes = routes.forEach((route) => {
|
||||||
@@ -55,6 +58,7 @@ if (notesError) {
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
notificationCreate();
|
notificationCreate();
|
||||||
startNotificationMonitor();
|
startNotificationMonitor();
|
||||||
|
sqlJobCleanUp();
|
||||||
}, 5 * 1000);
|
}, 5 * 1000);
|
||||||
|
|
||||||
export default app;
|
export default app;
|
||||||
|
|||||||
50
lstV2/server/services/notifications/routes/tooManyErrors.ts
Normal file
50
lstV2/server/services/notifications/routes/tooManyErrors.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
// an external way to creating logs
|
||||||
|
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
|
||||||
|
import { eq } from "drizzle-orm";
|
||||||
|
import { db } from "../../../../database/dbclient.js";
|
||||||
|
import { notifications } from "../../../../database/schema/notifications.js";
|
||||||
|
import { apiHit } from "../../../globalUtils/apiHits.js";
|
||||||
|
import { responses } from "../../../globalUtils/routeDefs/responses.js";
|
||||||
|
import { tryCatch } from "../../../globalUtils/tryCatch.js";
|
||||||
|
import { authMiddleware } from "../../auth/middleware/authMiddleware.js";
|
||||||
|
import hasCorrectRole from "../../auth/middleware/roleCheck.js";
|
||||||
|
import tooManyErrors from "../controller/notifications/tooManyErrors.js";
|
||||||
|
import { getAllJobs } from "../utils/processNotifications.js";
|
||||||
|
|
||||||
|
const app = new OpenAPIHono({ strict: false });
|
||||||
|
|
||||||
|
app.openapi(
|
||||||
|
createRoute({
|
||||||
|
tags: ["server"],
|
||||||
|
summary: "Returns current active notifications.",
|
||||||
|
method: "get",
|
||||||
|
path: "/toomanyerrors",
|
||||||
|
middleware: [authMiddleware, hasCorrectRole(["systemAdmin"], "admin")],
|
||||||
|
responses: responses(),
|
||||||
|
}),
|
||||||
|
async (c) => {
|
||||||
|
apiHit(c, { endpoint: "/toomanyerrors" });
|
||||||
|
|
||||||
|
const { data, error } = await tryCatch(
|
||||||
|
db
|
||||||
|
.select()
|
||||||
|
.from(notifications)
|
||||||
|
.where(eq(notifications.name, "tooManyErrors")),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return c.json({
|
||||||
|
success: false,
|
||||||
|
message: "Error Getting Notification Settings.",
|
||||||
|
data: error,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const errorData = await tooManyErrors(data[0]);
|
||||||
|
return c.json({
|
||||||
|
success: true,
|
||||||
|
message: "Current Error log data",
|
||||||
|
data: errorData?.data,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
export default app;
|
||||||
@@ -3,175 +3,208 @@ import { notifications } from "../../../../database/schema/notifications.js";
|
|||||||
import { createLog } from "../../logger/logger.js";
|
import { createLog } from "../../logger/logger.js";
|
||||||
|
|
||||||
export const note: any = [
|
export const note: any = [
|
||||||
{
|
{
|
||||||
name: "reprintLabels",
|
name: "reprintLabels",
|
||||||
description:
|
description:
|
||||||
"Monitors the labels that are printed and returns a value if one falls withing the time frame defined below.",
|
"Monitors the labels that are printed and returns a value if one falls withing the time frame defined below.",
|
||||||
checkInterval: 1,
|
checkInterval: 1,
|
||||||
timeType: "min",
|
timeType: "min",
|
||||||
emails: "",
|
emails: "",
|
||||||
active: false,
|
active: false,
|
||||||
notifiySettings: { prodID: 1 },
|
notifiySettings: { prodID: 1 },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "downTimeCheck",
|
name: "downTimeCheck",
|
||||||
description:
|
description: "Checks for specific downtimes that are greater than 105 min.",
|
||||||
"Checks for specific downtimes that are greater than 105 min.",
|
checkInterval: 30,
|
||||||
checkInterval: 30,
|
timeType: "min",
|
||||||
timeType: "min",
|
emails: "",
|
||||||
emails: "",
|
active: false,
|
||||||
active: false,
|
notifiySettings: { prodID: 1, daysInPast: 5, duration: 105 },
|
||||||
notifiySettings: { prodID: 1, daysInPast: 5, duration: 105 },
|
},
|
||||||
},
|
{
|
||||||
{
|
name: "qualityBlocking",
|
||||||
name: "qualityBlocking",
|
description:
|
||||||
description:
|
"Checks for new blocking orders that have been entered, recommened to get the most recent order in here before activating.",
|
||||||
"Checks for new blocking orders that have been entered, recommened to get the most recent order in here before activating.",
|
checkInterval: 30,
|
||||||
checkInterval: 30,
|
timeType: "min",
|
||||||
timeType: "min",
|
emails: "",
|
||||||
emails: "",
|
active: false,
|
||||||
active: false,
|
notifiySettings: {
|
||||||
notifiySettings: {
|
prodID: 1,
|
||||||
prodID: 1,
|
sentBlockingOrders: [{ timeStamp: "0", blockingOrder: 1 }],
|
||||||
sentBlockingOrders: [{ timeStamp: "0", blockingOrder: 1 }],
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
name: "productionCheck",
|
||||||
name: "productionCheck",
|
description: "Checks ppoo",
|
||||||
description: "Checks ppoo",
|
checkInterval: 2,
|
||||||
checkInterval: 2,
|
timeType: "hour",
|
||||||
timeType: "hour",
|
emails: "",
|
||||||
emails: "",
|
active: false,
|
||||||
active: false,
|
notifiySettings: {
|
||||||
notifiySettings: {
|
prodID: 1,
|
||||||
prodID: 1,
|
count: 0,
|
||||||
count: 0,
|
weekend: false,
|
||||||
weekend: false,
|
locations: "0",
|
||||||
locations: "0",
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
name: "stagingCheck",
|
||||||
name: "stagingCheck",
|
description:
|
||||||
description:
|
"Checks staging based on locations, locations need to be seperated by a ,",
|
||||||
"Checks staging based on locations, locations need to be seperated by a ,",
|
checkInterval: 2,
|
||||||
checkInterval: 2,
|
timeType: "hour",
|
||||||
timeType: "hour",
|
emails: "",
|
||||||
emails: "",
|
active: false,
|
||||||
active: false,
|
notifiySettings: {
|
||||||
notifiySettings: {
|
prodID: 1,
|
||||||
prodID: 1,
|
count: 0,
|
||||||
count: 0,
|
weekend: false,
|
||||||
weekend: false,
|
locations: "0",
|
||||||
locations: "0",
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
name: "tiIntergration",
|
||||||
name: "tiIntergration",
|
description: "Checks for new releases to be put into ti",
|
||||||
description: "Checks for new releases to be put into ti",
|
checkInterval: 60,
|
||||||
checkInterval: 60,
|
timeType: "min",
|
||||||
timeType: "min",
|
emails: "",
|
||||||
emails: "",
|
active: false,
|
||||||
active: false,
|
notifiySettings: {
|
||||||
notifiySettings: {
|
prodID: 1,
|
||||||
prodID: 1,
|
start: 36,
|
||||||
start: 36,
|
end: 36,
|
||||||
end: 36,
|
releases: [{ timeStamp: "0", releaseNumber: 1 }],
|
||||||
releases: [{ timeStamp: "0", releaseNumber: 1 }],
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
name: "exampleNotification",
|
||||||
name: "exampleNotification",
|
description: "Checks for new releases to be put into ti",
|
||||||
description: "Checks for new releases to be put into ti",
|
checkInterval: 2,
|
||||||
checkInterval: 2,
|
timeType: "min",
|
||||||
timeType: "min",
|
emails: "",
|
||||||
emails: "",
|
active: true,
|
||||||
active: true,
|
notifiySettings: {
|
||||||
notifiySettings: {
|
prodID: 1,
|
||||||
prodID: 1,
|
start: 36,
|
||||||
start: 36,
|
end: 36,
|
||||||
end: 36,
|
releases: [1, 2, 3],
|
||||||
releases: [1, 2, 3],
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
name: "fifoIndex",
|
||||||
name: "fifoIndex",
|
description: "Checks for pallets that were shipped out of fifo",
|
||||||
description: "Checks for pallets that were shipped out of fifo",
|
checkInterval: 1,
|
||||||
checkInterval: 1,
|
timeType: "hour",
|
||||||
timeType: "hour",
|
emails: "blake.matthes@alpla.com",
|
||||||
emails: "blake.matthes@alpla.com",
|
active: false,
|
||||||
active: false,
|
notifiySettings: {
|
||||||
notifiySettings: {
|
prodID: 1,
|
||||||
prodID: 1,
|
start: 36,
|
||||||
start: 36,
|
end: 36,
|
||||||
end: 36,
|
releases: [1, 2, 3],
|
||||||
releases: [1, 2, 3],
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
name: "bow2henkelincoming",
|
||||||
name: "bow2henkelincoming",
|
description:
|
||||||
description:
|
"Checks for new incoming goods orders to be completed and sends an email for what truck and carrier it was",
|
||||||
"Checks for new incoming goods orders to be completed and sends an email for what truck and carrier it was",
|
checkInterval: 15,
|
||||||
checkInterval: 15,
|
timeType: "min",
|
||||||
timeType: "min",
|
emails: "blake.matthes@alpla.com",
|
||||||
emails: "blake.matthes@alpla.com",
|
active: false,
|
||||||
active: false,
|
notifiySettings: { processTime: 15 },
|
||||||
notifiySettings: { processTime: 15 },
|
},
|
||||||
},
|
{
|
||||||
{
|
name: "palletsRemovedAsWaste",
|
||||||
name: "palletsRemovedAsWaste",
|
description:
|
||||||
description:
|
"Validates stock to make sure, there are no pallets released that have been removed as waste already ",
|
||||||
"Validates stock to make sure, there are no pallets released that have been removed as waste already ",
|
checkInterval: 15,
|
||||||
checkInterval: 15,
|
timeType: "min",
|
||||||
timeType: "min",
|
emails: "blake.matthes@alpla.com",
|
||||||
emails: "blake.matthes@alpla.com",
|
active: false,
|
||||||
active: false,
|
notifiySettings: { prodID: 1 },
|
||||||
notifiySettings: { prodID: 1 },
|
},
|
||||||
},
|
{
|
||||||
{
|
name: "shortageBookings",
|
||||||
name: "shortageBookings",
|
description:
|
||||||
description:
|
"Checks for material shortage bookings by single av type or all types ",
|
||||||
"Checks for material shortage bookings by single av type or all types ",
|
checkInterval: 15,
|
||||||
checkInterval: 15,
|
timeType: "min",
|
||||||
timeType: "min",
|
emails: "blake.matthes@alpla.com",
|
||||||
emails: "blake.matthes@alpla.com",
|
active: false,
|
||||||
active: false,
|
notifiySettings: {
|
||||||
notifiySettings: {
|
time: 15,
|
||||||
time: 15,
|
type: "all", // change this to something else or leave blank to use the av type
|
||||||
type: "all", // change this to something else or leave blank to use the av type
|
avType: 1,
|
||||||
avType: 1,
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
|
name: "tooManyErrors",
|
||||||
|
description:
|
||||||
|
"Checks to see how many errors in the last x time and sends an email based on this.",
|
||||||
|
checkInterval: 15,
|
||||||
|
timeType: "min",
|
||||||
|
emails: "blake.matthes@alpla.com",
|
||||||
|
active: true,
|
||||||
|
notifiySettings: {
|
||||||
|
errorCount: 10, // change this to something else or leave blank to use the av type
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "cycleCountCheck",
|
||||||
|
description:
|
||||||
|
"Checks if a cycle count has been active for longer than the defined time.",
|
||||||
|
checkInterval: 60,
|
||||||
|
timeType: "min",
|
||||||
|
emails: "",
|
||||||
|
active: false,
|
||||||
|
notifiySettings: {
|
||||||
|
errorCount: 10, // change this to something else or leave blank to use the av type
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "platToPlantEdi",
|
||||||
|
description:
|
||||||
|
"This is the plant to plant edi that will send an edi to the email once it ships, the emails will be for the receiving plants",
|
||||||
|
checkInterval: 15,
|
||||||
|
timeType: "min",
|
||||||
|
emails: "blake.matthes@alpla.com;Maritza.Hernandez@alpla.com",
|
||||||
|
active: false,
|
||||||
|
notifiySettings: { processedBol: [500], includeAll: false },
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const notificationCreate = async () => {
|
export const notificationCreate = async () => {
|
||||||
for (let i = 0; i < note.length; i++) {
|
for (let i = 0; i < note.length; i++) {
|
||||||
try {
|
try {
|
||||||
const notify = await db
|
const notify = await db
|
||||||
.insert(notifications)
|
.insert(notifications)
|
||||||
.values(note[i])
|
.values(note[i])
|
||||||
.onConflictDoUpdate({
|
.onConflictDoUpdate({
|
||||||
target: notifications.name,
|
target: notifications.name,
|
||||||
set: {
|
set: {
|
||||||
name: note[i].name,
|
name: note[i].name,
|
||||||
description: note[i].description,
|
description: note[i].description,
|
||||||
//notifiySettings: note[i].notifiySettings,
|
//notifiySettings: note[i].notifiySettings,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
createLog(
|
createLog(
|
||||||
"error",
|
"error",
|
||||||
"notify",
|
"notify",
|
||||||
"notify",
|
"notify",
|
||||||
`There was an error getting the notifications: ${JSON.stringify(
|
`There was an error getting the notifications: ${JSON.stringify(
|
||||||
error
|
error,
|
||||||
)}`
|
)}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
createLog(
|
createLog(
|
||||||
"info",
|
"info",
|
||||||
"lst",
|
"lst",
|
||||||
"nofity",
|
"nofity",
|
||||||
"notifications were just added/updated due to server startup"
|
"notifications were just added/updated due to server startup",
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
import { tryCatch } from "../../../globalUtils/tryCatch.js";
|
||||||
|
import { query } from "../../sqlServer/prodSqlServer.js";
|
||||||
|
import {
|
||||||
|
type SqlQuery,
|
||||||
|
sqlQuerySelector,
|
||||||
|
} from "../../sqlServer/utils/querySelector.utils.js";
|
||||||
|
|
||||||
|
const cleanUpQuery = `
|
||||||
|
DECLARE @JobName varchar(max) = '[jobName]'
|
||||||
|
UPDATE msdb.dbo.sysjobs
|
||||||
|
SET enabled = 0
|
||||||
|
WHERE name = @JobName;
|
||||||
|
`;
|
||||||
|
|
||||||
|
// disable the jobs
|
||||||
|
const jobNames: string[] = [
|
||||||
|
"monitor_$_lots",
|
||||||
|
"monitor_$_lots_2",
|
||||||
|
"monitor$lots",
|
||||||
|
"Monitor_APO", //listen for people to cry this is no longer a thing
|
||||||
|
"Monitor_APO2",
|
||||||
|
"Monitor_AutoConsumeMaterials", // TODO: migrate to lst
|
||||||
|
"Monitor_AutoConsumeMaterials_iow1",
|
||||||
|
"Monitor_AutoConsumeMaterials_iow2",
|
||||||
|
"Monitor_BlockedINV_Loc",
|
||||||
|
"monitor_inv_cycle",
|
||||||
|
"monitor_inv_cycle_1",
|
||||||
|
"monitor_inv_cycle_2",
|
||||||
|
"monitor_edi_import", // TODO: migrate to lst -- for the query select count(*) from AlplaPROD_test3.dbo.T_EDIDokumente (nolock) where /* IdLieferant > 1 and */ add_date > DATEADD(MINUTE, -30, getdate())
|
||||||
|
"Monitor_Lot_Progression",
|
||||||
|
"Monitor_Lots", // TODO: migrate to lst -- this should be the one where we monitor the when a lot is assigned if its missing some data.
|
||||||
|
"Monitor_MinMax", // TODO:Migrate to lst
|
||||||
|
"Monitor_MinMax_iow2",
|
||||||
|
"Monitor_PM",
|
||||||
|
"Monitor_Purity",
|
||||||
|
"monitor_wastebookings", // TODO: Migrate
|
||||||
|
"LastPriceUpdate", // not even sure what this is
|
||||||
|
"GETLabelsCount", // seems like an old jc job
|
||||||
|
"jobforpuritycount", // was not even working correctly
|
||||||
|
"Monitor_EmptyAutoConsumLocations", // not sure who uses this one
|
||||||
|
"monitor_labelreprint", // Migrated but need to find out who really wants this
|
||||||
|
"test", // not even sure why this is active
|
||||||
|
"UpdateLastMoldUsed", // old jc inserts data into a table but not sure what its used for not linked to any other alert
|
||||||
|
"UpdateWhsePositions3", // old jc inserts data into a table but not sure what its used for not linked to any other alert
|
||||||
|
"UpdateWhsePositions4",
|
||||||
|
"delete_print", // i think this was in here for when we was having lag prints in iowa1
|
||||||
|
"INV_WHSE_1", // something random i wrote long time ago looks like an inv thing to see aged stuff
|
||||||
|
"INV_WHSE_2",
|
||||||
|
"laneAgeCheck", // another strange one thats been since moved to lst
|
||||||
|
"monitor_blocking_2",
|
||||||
|
"monitor_blocking", // already in lst
|
||||||
|
"monitor_min_inv", // do we still want this one? it has a description of: this checks m-f the min inventory of materials based on the min level set in stock
|
||||||
|
"Monitor_MixedLocations",
|
||||||
|
"Monitor_PM",
|
||||||
|
"Monitor_PM2",
|
||||||
|
"wrong_lots_1",
|
||||||
|
"wrong_lots_2",
|
||||||
|
"invenotry check", // spelling error one of my stupids
|
||||||
|
"monitor_hold_monitor",
|
||||||
|
"Monitor_Silo_adjustments",
|
||||||
|
"monitor_qualityLocMonitor", // validating with lima this is still needed
|
||||||
|
];
|
||||||
|
|
||||||
|
export const sqlJobCleanUp = async () => {
|
||||||
|
// running a query to disable jobs that are moved to lst to be better maintained
|
||||||
|
const sqlQuery = sqlQuerySelector("disableJob.query") as SqlQuery;
|
||||||
|
|
||||||
|
if (!sqlQuery.success) {
|
||||||
|
console.log("Failed to load the query: ", sqlQuery.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const job of jobNames) {
|
||||||
|
const { data, error } = await tryCatch(
|
||||||
|
query(
|
||||||
|
sqlQuery.query.replace("[jobName]", `${job}`),
|
||||||
|
`Disabling job: ${job}`,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
//console.log(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
{{!-- <link rel="stylesheet" href="styles/styles.css" /> --}}
|
||||||
|
{{> styles}}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>All,</p>
|
||||||
|
<p>The below are cycle counts that have been in progress for longer than {{checkTime}} min(s). </p>
|
||||||
|
<table >
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>WarehouseID</th>
|
||||||
|
<th>Warehouse</th>
|
||||||
|
<th>LocationID</th>
|
||||||
|
<th>Location</th>
|
||||||
|
<th>Cycle count Started</th>
|
||||||
|
<th>Started by</th>
|
||||||
|
{{!-- <th>Downtime finish</th> --}}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{#each items}}
|
||||||
|
<tr>
|
||||||
|
<td>{{idWarehouse}}</td>
|
||||||
|
<td>{{warehouse}}</td>
|
||||||
|
<td>{{locationId}}</td>
|
||||||
|
<td>{{location}}</td>
|
||||||
|
<td>{{cycleCountStartAt}}</td>
|
||||||
|
<td>{{blockedBy}}</td>
|
||||||
|
{{!-- <td>{{dtEnd}}</td> --}}
|
||||||
|
</tr>
|
||||||
|
{{/each}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div>
|
||||||
|
<p>Thank you,</p>
|
||||||
|
<p>LST Team</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
{{!-- <link rel="stylesheet" href="styles/styles.css" /> --}}
|
||||||
|
{{> styles}}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>All,</p>
|
||||||
|
<p>BOL: {{bol}} was created with the below pallets.</p>
|
||||||
|
<p>Please head to stock and import the pallets via the normal incoming goods process (now/immediately).</p>
|
||||||
|
<p>When encountering a discrepancy in pallets/cages received, please correct this after the pallets have been imported.</p>
|
||||||
|
<p>Due to these being plant to plant shipments, the only way to correct this is to bring them in then undo the incoming goods process.</p>
|
||||||
|
<br></br>
|
||||||
|
<table >
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Running Number</th>
|
||||||
|
<th>AV</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Lot number</th>
|
||||||
|
<th>Quantity</th>
|
||||||
|
{{!-- <th>Downtime finish</th> --}}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{#each items}}
|
||||||
|
<tr>
|
||||||
|
<td>{{runningNr}}</td>
|
||||||
|
<td>{{article}}</td>
|
||||||
|
<td>{{alias}}</td>
|
||||||
|
<td>{{lotNumber}}</td>
|
||||||
|
<td>{{qty}}</td>
|
||||||
|
{{!-- <td>{{dtEnd}}</td> --}}
|
||||||
|
</tr>
|
||||||
|
{{/each}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div>
|
||||||
|
<p>Thank you,</p>
|
||||||
|
<p>LST Team</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
{{!-- <link rel="stylesheet" href="styles/styles.css" /> --}}
|
||||||
|
{{> styles}}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>All,</p>
|
||||||
|
<p>The plant has encountered more than {{count}} errors in the last {{time}} mins, please see below errors and address as needed. </p>
|
||||||
|
<table >
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Username</th>
|
||||||
|
<th>Service</th>
|
||||||
|
<th>Message</th>
|
||||||
|
<th>Checked</th>
|
||||||
|
<th>LogTime</th>
|
||||||
|
{{!-- <th>Downtime finish</th> --}}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{#each data}}
|
||||||
|
<tr>
|
||||||
|
<td>{{username}}</td>
|
||||||
|
<td>{{service}}</td>
|
||||||
|
<td>{{message}}</td>
|
||||||
|
<td>{{checked}}</td>
|
||||||
|
<td>{{add_Date}}</td>
|
||||||
|
{{!-- <td>{{dtEnd}}</td> --}}
|
||||||
|
</tr>
|
||||||
|
{{/each}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div>
|
||||||
|
<p>Thank you,</p>
|
||||||
|
<p>LST Team</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -133,6 +133,14 @@ export const labelingProcess = async ({
|
|||||||
* The checks we do before we can actually print a label will take place meow.
|
* The checks we do before we can actually print a label will take place meow.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
// this will be for the rare case it actually doesn't find a lot properly or has some kinda error.
|
||||||
|
if(!Array.isArray(filteredLot) || filteredLot.length === 0){
|
||||||
|
createLog("error", "labeling", "ocp", `${printer?.name}, dose not apear to have a lot assigned to it.`);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: `${printer?.name}, dose not apear to have a lot assigned to it.`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// if the plant does not want to have dual printing and we have >2 assigned well return and send error.
|
// if the plant does not want to have dual printing and we have >2 assigned well return and send error.
|
||||||
let dualPrinting = settingData.filter((d) => d.name === "dualPrinting")[0]
|
let dualPrinting = settingData.filter((d) => d.name === "dualPrinting")[0]
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user