feat: add SQL Server support and refactor database layer for multi-database compatibility
- Add SqlServerService integration alongside existing MySQL support - Refactor DAOs (DiscreteMaterialPlanDAO, MaterialsToBeDeletedDAO, BipUsersDAO) to support both MySQL and SQL Server - Update validation handler to dynamically select database service based on DB_TYPE environment variable - Add connection pooling and proper connection management for SQL Server - Update package-lock.json dependency peer flags Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
33
package-lock.json
generated
33
package-lock.json
generated
@@ -99,6 +99,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.10.1.tgz",
|
"resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.10.1.tgz",
|
||||||
"integrity": "sha512-Nh5PhEOeY6PrnxNPsEHRr9eimxLwgLlpmguQaHKBinFYA/RU9+kOYVOQqOrTsCL+KSxrLLl1gD8Dk5BFW/7l/w==",
|
"integrity": "sha512-Nh5PhEOeY6PrnxNPsEHRr9eimxLwgLlpmguQaHKBinFYA/RU9+kOYVOQqOrTsCL+KSxrLLl1gD8Dk5BFW/7l/w==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@azure/abort-controller": "^2.1.2",
|
"@azure/abort-controller": "^2.1.2",
|
||||||
"@azure/core-auth": "^1.10.0",
|
"@azure/core-auth": "^1.10.0",
|
||||||
@@ -160,6 +161,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.22.2.tgz",
|
"resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.22.2.tgz",
|
||||||
"integrity": "sha512-MzHym+wOi8CLUlKCQu12de0nwcq9k9Kuv43j4Wa++CsCpJwps2eeBQwD2Bu8snkxTtDKDx4GwjuR9E8yC8LNrg==",
|
"integrity": "sha512-MzHym+wOi8CLUlKCQu12de0nwcq9k9Kuv43j4Wa++CsCpJwps2eeBQwD2Bu8snkxTtDKDx4GwjuR9E8yC8LNrg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@azure/abort-controller": "^2.1.2",
|
"@azure/abort-controller": "^2.1.2",
|
||||||
"@azure/core-auth": "^1.10.0",
|
"@azure/core-auth": "^1.10.0",
|
||||||
@@ -351,6 +353,7 @@
|
|||||||
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
|
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.29.0",
|
"@babel/code-frame": "^7.29.0",
|
||||||
"@babel/generator": "^7.29.0",
|
"@babel/generator": "^7.29.0",
|
||||||
@@ -1099,7 +1102,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cross-dirname": "^0.1.0",
|
"cross-dirname": "^0.1.0",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
@@ -1121,7 +1123,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"graceful-fs": "^4.2.0",
|
"graceful-fs": "^4.2.0",
|
||||||
"jsonfile": "^6.0.1",
|
"jsonfile": "^6.0.1",
|
||||||
@@ -1138,7 +1139,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"universalify": "^2.0.0"
|
"universalify": "^2.0.0"
|
||||||
},
|
},
|
||||||
@@ -1153,7 +1153,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 10.0.0"
|
"node": ">= 10.0.0"
|
||||||
}
|
}
|
||||||
@@ -3008,6 +3007,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.13.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.13.tgz",
|
||||||
"integrity": "sha512-akNQMv0wW5uyRpD2v2IEyRSZiR+BeGuoB6L310EgGObO44HSMNT8z1xzio28V8qOrgYaopIDNA18YgdXd+qTiw==",
|
"integrity": "sha512-akNQMv0wW5uyRpD2v2IEyRSZiR+BeGuoB6L310EgGObO44HSMNT8z1xzio28V8qOrgYaopIDNA18YgdXd+qTiw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~6.21.0"
|
"undici-types": "~6.21.0"
|
||||||
}
|
}
|
||||||
@@ -3030,6 +3030,7 @@
|
|||||||
"integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
|
"integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"csstype": "^3.2.2"
|
"csstype": "^3.2.2"
|
||||||
}
|
}
|
||||||
@@ -3132,6 +3133,7 @@
|
|||||||
"integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==",
|
"integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "8.56.1",
|
"@typescript-eslint/scope-manager": "8.56.1",
|
||||||
"@typescript-eslint/types": "8.56.1",
|
"@typescript-eslint/types": "8.56.1",
|
||||||
@@ -3565,6 +3567,7 @@
|
|||||||
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
|
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
},
|
},
|
||||||
@@ -3597,6 +3600,7 @@
|
|||||||
"integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==",
|
"integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fast-deep-equal": "^3.1.1",
|
"fast-deep-equal": "^3.1.1",
|
||||||
"fast-json-stable-stringify": "^2.0.0",
|
"fast-json-stable-stringify": "^2.0.0",
|
||||||
@@ -4329,6 +4333,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"baseline-browser-mapping": "^2.9.0",
|
"baseline-browser-mapping": "^2.9.0",
|
||||||
"caniuse-lite": "^1.0.30001759",
|
"caniuse-lite": "^1.0.30001759",
|
||||||
@@ -4984,8 +4989,7 @@
|
|||||||
"integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==",
|
"integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/cross-spawn": {
|
"node_modules/cross-spawn": {
|
||||||
"version": "7.0.6",
|
"version": "7.0.6",
|
||||||
@@ -5334,6 +5338,7 @@
|
|||||||
"integrity": "sha512-glMJgnTreo8CFINujtAhCgN96QAqApDMZ8Vl1r8f0QT8QprvC1UCltV4CcWj20YoIyLZx6IUskaJZ0NV8fokcg==",
|
"integrity": "sha512-glMJgnTreo8CFINujtAhCgN96QAqApDMZ8Vl1r8f0QT8QprvC1UCltV4CcWj20YoIyLZx6IUskaJZ0NV8fokcg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"app-builder-lib": "26.8.1",
|
"app-builder-lib": "26.8.1",
|
||||||
"builder-util": "26.8.1",
|
"builder-util": "26.8.1",
|
||||||
@@ -5562,6 +5567,7 @@
|
|||||||
"integrity": "sha512-Rz5QvP1pTqoU1DPRrG3EeX2oWBtS3uRmd6Z/wzZsb2e/iIUsrT+XcBaAhFr4FW48gDc8uP2wYVyY5Aamha/5Zg==",
|
"integrity": "sha512-Rz5QvP1pTqoU1DPRrG3EeX2oWBtS3uRmd6Z/wzZsb2e/iIUsrT+XcBaAhFr4FW48gDc8uP2wYVyY5Aamha/5Zg==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@electron/get": "^2.0.0",
|
"@electron/get": "^2.0.0",
|
||||||
"@types/node": "^22.7.7",
|
"@types/node": "^22.7.7",
|
||||||
@@ -5750,7 +5756,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@electron/asar": "^3.2.1",
|
"@electron/asar": "^3.2.1",
|
||||||
"debug": "^4.1.1",
|
"debug": "^4.1.1",
|
||||||
@@ -5771,7 +5776,6 @@
|
|||||||
"integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
|
"integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"graceful-fs": "^4.1.2",
|
"graceful-fs": "^4.1.2",
|
||||||
"jsonfile": "^4.0.0",
|
"jsonfile": "^4.0.0",
|
||||||
@@ -6099,6 +6103,7 @@
|
|||||||
"integrity": "sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg==",
|
"integrity": "sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.8.0",
|
"@eslint-community/eslint-utils": "^4.8.0",
|
||||||
"@eslint-community/regexpp": "^4.12.1",
|
"@eslint-community/regexpp": "^4.12.1",
|
||||||
@@ -6159,6 +6164,7 @@
|
|||||||
"integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
|
"integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"eslint-config-prettier": "bin/cli.js"
|
"eslint-config-prettier": "bin/cli.js"
|
||||||
},
|
},
|
||||||
@@ -9870,6 +9876,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
@@ -9951,6 +9958,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.11",
|
"nanoid": "^3.3.11",
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.1.1",
|
||||||
@@ -9974,7 +9982,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"commander": "^9.4.0"
|
"commander": "^9.4.0"
|
||||||
},
|
},
|
||||||
@@ -9992,7 +9999,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.20.0 || >=14"
|
"node": "^12.20.0 || >=14"
|
||||||
}
|
}
|
||||||
@@ -10013,6 +10019,7 @@
|
|||||||
"integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==",
|
"integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"prettier": "bin/prettier.cjs"
|
"prettier": "bin/prettier.cjs"
|
||||||
},
|
},
|
||||||
@@ -10145,6 +10152,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
|
||||||
"integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
|
"integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@@ -11380,7 +11388,6 @@
|
|||||||
"integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==",
|
"integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
"rimraf": "~2.6.2"
|
"rimraf": "~2.6.2"
|
||||||
@@ -11668,6 +11675,7 @@
|
|||||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
@@ -11902,6 +11910,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz",
|
||||||
"integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
|
"integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.27.0",
|
"esbuild": "^0.27.0",
|
||||||
"fdir": "^6.5.0",
|
"fdir": "^6.5.0",
|
||||||
@@ -12448,6 +12457,7 @@
|
|||||||
"integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==",
|
"integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vitest/expect": "4.0.18",
|
"@vitest/expect": "4.0.18",
|
||||||
"@vitest/mocker": "4.0.18",
|
"@vitest/mocker": "4.0.18",
|
||||||
@@ -12845,6 +12855,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz",
|
||||||
"integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
|
"integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/colinhacks"
|
"url": "https://github.com/sponsors/colinhacks"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
import { ipcMain } from 'electron'
|
import { ipcMain } from 'electron'
|
||||||
import { MySqlService } from '../services/database/mysql'
|
import { MySqlService } from '../services/database/mysql'
|
||||||
|
import { SqlServerService } from '../services/database/sql-server'
|
||||||
import { MaterialsToBeDeletedDAO } from '../services/database/materials-to-be-deleted-dao'
|
import { MaterialsToBeDeletedDAO } from '../services/database/materials-to-be-deleted-dao'
|
||||||
import { DiscreteMaterialPlanDAO } from '../services/database/discrete-material-plan-dao'
|
import { DiscreteMaterialPlanDAO } from '../services/database/discrete-material-plan-dao'
|
||||||
import type {
|
import type {
|
||||||
@@ -49,19 +50,53 @@ export function clearSharedProductionIds(): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get MySQL service for validation operations
|
* Get database service for validation operations (MySQL or SQL Server)
|
||||||
*/
|
*/
|
||||||
async function getValidationMySqlService(): Promise<MySqlService> {
|
async function getValidationDatabaseService(): Promise<MySqlService | SqlServerService> {
|
||||||
const mysqlService = new MySqlService({
|
const dbType = process.env.DB_TYPE?.toLowerCase()
|
||||||
host: process.env.DB_MYSQL_HOST || 'localhost',
|
|
||||||
port: parseInt(process.env.DB_MYSQL_PORT || '3306', 10),
|
|
||||||
user: process.env.DB_USERNAME || 'root',
|
|
||||||
password: process.env.DB_PASSWORD || '',
|
|
||||||
database: process.env.DB_NAME || ''
|
|
||||||
})
|
|
||||||
|
|
||||||
await mysqlService.connect()
|
if (dbType === 'sqlserver' || dbType === 'mssql') {
|
||||||
return mysqlService
|
const sqlServerService = new SqlServerService({
|
||||||
|
server: process.env.DB_SERVER || 'localhost',
|
||||||
|
port: parseInt(process.env.DB_SQLSERVER_PORT || '1433', 10),
|
||||||
|
user: process.env.DB_USERNAME || 'sa',
|
||||||
|
password: process.env.DB_PASSWORD || '',
|
||||||
|
database: process.env.DB_NAME || '',
|
||||||
|
options: {
|
||||||
|
encrypt: process.env.DB_TRUST_SERVER_CERTIFICATE === 'yes',
|
||||||
|
trustServerCertificate: process.env.DB_TRUST_SERVER_CERTIFICATE === 'yes'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await sqlServerService.connect()
|
||||||
|
return sqlServerService
|
||||||
|
} else {
|
||||||
|
const mysqlService = new MySqlService({
|
||||||
|
host: process.env.DB_MYSQL_HOST || 'localhost',
|
||||||
|
port: parseInt(process.env.DB_MYSQL_PORT || '3306', 10),
|
||||||
|
user: process.env.DB_USERNAME || 'root',
|
||||||
|
password: process.env.DB_PASSWORD || '',
|
||||||
|
database: process.env.DB_NAME || ''
|
||||||
|
})
|
||||||
|
await mysqlService.connect()
|
||||||
|
return mysqlService
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get table name based on database type
|
||||||
|
*/
|
||||||
|
function getTableName(mysqlTableName: string): string {
|
||||||
|
const dbType = process.env.DB_TYPE?.toLowerCase()
|
||||||
|
if (dbType === 'sqlserver' || dbType === 'mssql') {
|
||||||
|
// Convert MySQL table name to SQL Server format
|
||||||
|
// e.g., dbo_MaterialsToBeDeleted -> [dbo].[MaterialsToBeDeleted]
|
||||||
|
if (mysqlTableName.startsWith('dbo_')) {
|
||||||
|
const tableName = mysqlTableName.substring(4)
|
||||||
|
return `[dbo].[${tableName}]`
|
||||||
|
}
|
||||||
|
return `[dbo].[${mysqlTableName}]`
|
||||||
|
}
|
||||||
|
return mysqlTableName
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -96,10 +131,12 @@ function identifyInputType(input: string): 'production_id' | 'order_number' | 'u
|
|||||||
*/
|
*/
|
||||||
async function getSourceNumbersFromInputs(
|
async function getSourceNumbersFromInputs(
|
||||||
inputs: string[],
|
inputs: string[],
|
||||||
mysqlService: MySqlService
|
dbService: MySqlService | SqlServerService
|
||||||
): Promise<string[]> {
|
): Promise<string[]> {
|
||||||
const productionIds: string[] = []
|
const productionIds: string[] = []
|
||||||
const orderNumbers: string[] = []
|
const orderNumbers: string[] = []
|
||||||
|
const dbType = process.env.DB_TYPE?.toLowerCase()
|
||||||
|
const isSqlServer = dbType === 'sqlserver' || dbType === 'mssql'
|
||||||
|
|
||||||
for (const item of inputs) {
|
for (const item of inputs) {
|
||||||
const type = identifyInputType(item)
|
const type = identifyInputType(item)
|
||||||
@@ -114,17 +151,38 @@ async function getSourceNumbersFromInputs(
|
|||||||
// Table name in MySQL: productionContractData_26年压力表合同数据
|
// Table name in MySQL: productionContractData_26年压力表合同数据
|
||||||
// Column name: 生产订单号 (SourceNumber)
|
// Column name: 生产订单号 (SourceNumber)
|
||||||
if (productionIds.length > 0) {
|
if (productionIds.length > 0) {
|
||||||
const placeholders = productionIds.map(() => '?').join(',')
|
if (isSqlServer) {
|
||||||
const contractSql = `
|
const sql = require('mssql')
|
||||||
SELECT DISTINCT 生产订单号
|
const placeholders = productionIds.map((_, idx) => `@p${idx}`).join(',')
|
||||||
FROM productionContractData_26年压力表合同数据
|
const params: Record<string, { value: string; type: any }> = {}
|
||||||
WHERE 总排号 IN (${placeholders})
|
|
||||||
`
|
productionIds.forEach((id, idx) => {
|
||||||
const contractResult = await mysqlService.query(contractSql, productionIds)
|
params[`p${idx}`] = { value: id, type: sql.NVarChar }
|
||||||
const dbOrderNumbers = contractResult.rows.map(
|
})
|
||||||
row => row.生产订单号 as string
|
|
||||||
)
|
const contractSql = `
|
||||||
orderNumbers.push(...dbOrderNumbers)
|
SELECT DISTINCT 生产订单号
|
||||||
|
FROM productionContractData_26年压力表合同数据
|
||||||
|
WHERE 总排号 IN (${placeholders})
|
||||||
|
`
|
||||||
|
const contractResult = await (dbService as SqlServerService).queryWithParams(contractSql, params)
|
||||||
|
const dbOrderNumbers = contractResult.rows.map(
|
||||||
|
row => row.生产订单号 as string
|
||||||
|
)
|
||||||
|
orderNumbers.push(...dbOrderNumbers)
|
||||||
|
} else {
|
||||||
|
const placeholders = productionIds.map(() => '?').join(',')
|
||||||
|
const contractSql = `
|
||||||
|
SELECT DISTINCT 生产订单号
|
||||||
|
FROM productionContractData_26年压力表合同数据
|
||||||
|
WHERE 总排号 IN (${placeholders})
|
||||||
|
`
|
||||||
|
const contractResult = await (dbService as MySqlService).query(contractSql, productionIds)
|
||||||
|
const dbOrderNumbers = contractResult.rows.map(
|
||||||
|
row => row.生产订单号 as string
|
||||||
|
)
|
||||||
|
orderNumbers.push(...dbOrderNumbers)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deduplicate
|
// Deduplicate
|
||||||
@@ -146,13 +204,15 @@ export function registerValidationHandlers(): void {
|
|||||||
_event,
|
_event,
|
||||||
request: ValidationRequest
|
request: ValidationRequest
|
||||||
): Promise<ValidationResponse> => {
|
): Promise<ValidationResponse> => {
|
||||||
let mysqlService: MySqlService | null = null
|
let dbService: MySqlService | SqlServerService | null = null
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log('[Validation] Starting validation:', request)
|
console.log('[Validation] Starting validation:', request)
|
||||||
|
|
||||||
// Connect to MySQL
|
// Connect to database
|
||||||
mysqlService = await getValidationMySqlService()
|
dbService = await getValidationDatabaseService()
|
||||||
|
const dbType = process.env.DB_TYPE?.toLowerCase()
|
||||||
|
const isSqlServer = dbType === 'sqlserver' || dbType === 'mssql'
|
||||||
|
|
||||||
let sourceNumbers: string[] | null = null
|
let sourceNumbers: string[] | null = null
|
||||||
|
|
||||||
@@ -175,7 +235,7 @@ export function registerValidationHandlers(): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceNumbers = await getSourceNumbersFromInputs(sharedIds, mysqlService)
|
sourceNumbers = await getSourceNumbersFromInputs(sharedIds, dbService)
|
||||||
console.log(
|
console.log(
|
||||||
`[Validation] Got ${sourceNumbers.length} source numbers from shared Production IDs`
|
`[Validation] Got ${sourceNumbers.length} source numbers from shared Production IDs`
|
||||||
)
|
)
|
||||||
@@ -185,7 +245,7 @@ export function registerValidationHandlers(): void {
|
|||||||
console.log(
|
console.log(
|
||||||
`[Validation] Read ${inputs.length} inputs from file`
|
`[Validation] Read ${inputs.length} inputs from file`
|
||||||
)
|
)
|
||||||
sourceNumbers = await getSourceNumbersFromInputs(inputs, mysqlService)
|
sourceNumbers = await getSourceNumbersFromInputs(inputs, dbService)
|
||||||
console.log(
|
console.log(
|
||||||
`[Validation] Got ${sourceNumbers.length} source numbers`
|
`[Validation] Got ${sourceNumbers.length} source numbers`
|
||||||
)
|
)
|
||||||
@@ -194,8 +254,6 @@ export function registerValidationHandlers(): void {
|
|||||||
|
|
||||||
// Get material records from DiscreteMaterialPlanData
|
// Get material records from DiscreteMaterialPlanData
|
||||||
const materialDao = new DiscreteMaterialPlanDAO()
|
const materialDao = new DiscreteMaterialPlanDAO()
|
||||||
// Inject the mysqlService instance
|
|
||||||
;(materialDao as any).mysqlService = mysqlService
|
|
||||||
|
|
||||||
let materialRecords: any[] = []
|
let materialRecords: any[] = []
|
||||||
|
|
||||||
@@ -222,24 +280,32 @@ export function registerValidationHandlers(): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get type keywords from MaterialsTypeToBeDeleted
|
// Get type keywords from MaterialsTypeToBeDeleted
|
||||||
|
const typeKeywordTableName = getTableName('dbo_MaterialsTypeToBeDeleted')
|
||||||
const typeKeywordSql = `
|
const typeKeywordSql = `
|
||||||
SELECT MaterialName, ManagerName
|
SELECT MaterialName, ManagerName
|
||||||
FROM dbo_MaterialsTypeToBeDeleted
|
FROM ${typeKeywordTableName}
|
||||||
WHERE MaterialName IS NOT NULL
|
WHERE MaterialName IS NOT NULL
|
||||||
`
|
`
|
||||||
const typeKeywordResult = await mysqlService.query(typeKeywordSql)
|
const typeKeywordResult = isSqlServer
|
||||||
|
? await (dbService as SqlServerService).query(typeKeywordSql)
|
||||||
|
: await (dbService as MySqlService).query(typeKeywordSql)
|
||||||
|
|
||||||
const typeKeywords = typeKeywordResult.rows.map(row => ({
|
const typeKeywords = typeKeywordResult.rows.map(row => ({
|
||||||
materialName: row.MaterialName as string,
|
materialName: row.MaterialName as string,
|
||||||
managerName: row.ManagerName as string
|
managerName: row.ManagerName as string
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// Get marked material codes from MaterialsToBeDeleted
|
// Get marked material codes from MaterialsToBeDeleted
|
||||||
|
const markedTableName = getTableName('dbo_MaterialsToBeDeleted')
|
||||||
const markedSql = `
|
const markedSql = `
|
||||||
SELECT MaterialCode, ManagerName
|
SELECT MaterialCode, ManagerName
|
||||||
FROM dbo_MaterialsToBeDeleted
|
FROM ${markedTableName}
|
||||||
WHERE MaterialCode IS NOT NULL AND ManagerName IS NOT NULL
|
WHERE MaterialCode IS NOT NULL AND ManagerName IS NOT NULL
|
||||||
`
|
`
|
||||||
const markedResult = await mysqlService.query(markedSql)
|
const markedResult = isSqlServer
|
||||||
|
? await (dbService as SqlServerService).query(markedSql)
|
||||||
|
: await (dbService as MySqlService).query(markedSql)
|
||||||
|
|
||||||
const markedCodesDict = new Map<string, string>()
|
const markedCodesDict = new Map<string, string>()
|
||||||
for (const row of markedResult.rows) {
|
for (const row of markedResult.rows) {
|
||||||
markedCodesDict.set(
|
markedCodesDict.set(
|
||||||
@@ -306,11 +372,11 @@ export function registerValidationHandlers(): void {
|
|||||||
error: `Validation failed: ${message}`
|
error: `Validation failed: ${message}`
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (mysqlService) {
|
if (dbService) {
|
||||||
try {
|
try {
|
||||||
await mysqlService.disconnect()
|
await dbService.disconnect()
|
||||||
} catch (closeError) {
|
} catch (closeError) {
|
||||||
console.warn('[Validation] Error disconnecting MySQL:', closeError)
|
console.warn('[Validation] Error disconnecting database:', closeError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -328,13 +394,8 @@ export function registerValidationHandlers(): void {
|
|||||||
_event,
|
_event,
|
||||||
request: MaterialUpsertBatchRequest
|
request: MaterialUpsertBatchRequest
|
||||||
): Promise<MaterialOperationResponse> => {
|
): Promise<MaterialOperationResponse> => {
|
||||||
let mysqlService: MySqlService | null = null
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mysqlService = await getValidationMySqlService()
|
|
||||||
const dao = new MaterialsToBeDeletedDAO()
|
const dao = new MaterialsToBeDeletedDAO()
|
||||||
;(dao as any).mysqlService = mysqlService
|
|
||||||
|
|
||||||
const stats = await dao.upsertBatch(request.materials)
|
const stats = await dao.upsertBatch(request.materials)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -348,14 +409,6 @@ export function registerValidationHandlers(): void {
|
|||||||
success: false,
|
success: false,
|
||||||
error: `Upsert failed: ${message}`
|
error: `Upsert failed: ${message}`
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
if (mysqlService) {
|
|
||||||
try {
|
|
||||||
await mysqlService.disconnect()
|
|
||||||
} catch (closeError) {
|
|
||||||
console.warn('[Materials] Error disconnecting MySQL:', closeError)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -369,13 +422,8 @@ export function registerValidationHandlers(): void {
|
|||||||
_event,
|
_event,
|
||||||
request: MaterialDeleteRequest
|
request: MaterialDeleteRequest
|
||||||
): Promise<MaterialOperationResponse> => {
|
): Promise<MaterialOperationResponse> => {
|
||||||
let mysqlService: MySqlService | null = null
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mysqlService = await getValidationMySqlService()
|
|
||||||
const dao = new MaterialsToBeDeletedDAO()
|
const dao = new MaterialsToBeDeletedDAO()
|
||||||
;(dao as any).mysqlService = mysqlService
|
|
||||||
|
|
||||||
const count = await dao.deleteByMaterialCodes(request.materialCodes)
|
const count = await dao.deleteByMaterialCodes(request.materialCodes)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -389,14 +437,6 @@ export function registerValidationHandlers(): void {
|
|||||||
success: false,
|
success: false,
|
||||||
error: `Delete failed: ${message}`
|
error: `Delete failed: ${message}`
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
if (mysqlService) {
|
|
||||||
try {
|
|
||||||
await mysqlService.disconnect()
|
|
||||||
} catch (closeError) {
|
|
||||||
console.warn('[Materials] Error disconnecting MySQL:', closeError)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -407,26 +447,13 @@ export function registerValidationHandlers(): void {
|
|||||||
ipcMain.handle(
|
ipcMain.handle(
|
||||||
'materials:getManagers',
|
'materials:getManagers',
|
||||||
async (_event): Promise<{ managers: string[] }> => {
|
async (_event): Promise<{ managers: string[] }> => {
|
||||||
let mysqlService: MySqlService | null = null
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mysqlService = await getValidationMySqlService()
|
|
||||||
const dao = new MaterialsToBeDeletedDAO()
|
const dao = new MaterialsToBeDeletedDAO()
|
||||||
;(dao as any).mysqlService = mysqlService
|
|
||||||
|
|
||||||
const managers = await dao.getManagers()
|
const managers = await dao.getManagers()
|
||||||
return { managers }
|
return { managers }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[Materials] Get managers error:', error)
|
console.error('[Materials] Get managers error:', error)
|
||||||
return { managers: [] }
|
return { managers: [] }
|
||||||
} finally {
|
|
||||||
if (mysqlService) {
|
|
||||||
try {
|
|
||||||
await mysqlService.disconnect()
|
|
||||||
} catch (closeError) {
|
|
||||||
console.warn('[Materials] Error disconnecting MySQL:', closeError)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -440,13 +467,14 @@ export function registerValidationHandlers(): void {
|
|||||||
_event,
|
_event,
|
||||||
managerName: string
|
managerName: string
|
||||||
): Promise<{ materials: MaterialRecordSummary[] }> => {
|
): Promise<{ materials: MaterialRecordSummary[] }> => {
|
||||||
let mysqlService: MySqlService | null = null
|
let dbService: MySqlService | SqlServerService | null = null
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mysqlService = await getValidationMySqlService()
|
dbService = await getValidationDatabaseService()
|
||||||
const dao = new MaterialsToBeDeletedDAO()
|
const dbType = process.env.DB_TYPE?.toLowerCase()
|
||||||
;(dao as any).mysqlService = mysqlService
|
const isSqlServer = dbType === 'sqlserver' || dbType === 'mssql'
|
||||||
|
|
||||||
|
const dao = new MaterialsToBeDeletedDAO()
|
||||||
const materials = await dao.getMaterialsByManager(managerName)
|
const materials = await dao.getMaterialsByManager(managerName)
|
||||||
|
|
||||||
// Get material codes set for quick lookup
|
// Get material codes set for quick lookup
|
||||||
@@ -454,17 +482,32 @@ export function registerValidationHandlers(): void {
|
|||||||
|
|
||||||
// Enrich with material details from DiscreteMaterialPlanData
|
// Enrich with material details from DiscreteMaterialPlanData
|
||||||
const enrichedMaterials: MaterialRecordSummary[] = []
|
const enrichedMaterials: MaterialRecordSummary[] = []
|
||||||
|
const detailTableName = getTableName('dbo_DiscreteMaterialPlanData')
|
||||||
|
|
||||||
for (const mat of materials) {
|
for (const mat of materials) {
|
||||||
const detailSql = `
|
let detailResult: any
|
||||||
SELECT MaterialName, Specification, Model
|
|
||||||
FROM dbo_DiscreteMaterialPlanData
|
if (isSqlServer) {
|
||||||
WHERE MaterialCode = ?
|
const sql = require('mssql')
|
||||||
LIMIT 1
|
const detailSql = `
|
||||||
`
|
SELECT TOP 1 MaterialName, Specification, Model
|
||||||
const detailResult = await mysqlService.query(detailSql, [
|
FROM ${detailTableName}
|
||||||
mat.materialCode
|
WHERE MaterialCode = @materialCode
|
||||||
])
|
`
|
||||||
|
detailResult = await (dbService as SqlServerService).queryWithParams(detailSql, {
|
||||||
|
materialCode: { value: mat.materialCode, type: sql.NVarChar }
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
const detailSql = `
|
||||||
|
SELECT MaterialName, Specification, Model
|
||||||
|
FROM ${detailTableName}
|
||||||
|
WHERE MaterialCode = ?
|
||||||
|
LIMIT 1
|
||||||
|
`
|
||||||
|
detailResult = await (dbService as MySqlService).query(detailSql, [
|
||||||
|
mat.materialCode
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
enrichedMaterials.push({
|
enrichedMaterials.push({
|
||||||
materialCode: mat.materialCode,
|
materialCode: mat.materialCode,
|
||||||
@@ -490,11 +533,11 @@ export function registerValidationHandlers(): void {
|
|||||||
console.error('[Materials] Get by manager error:', error)
|
console.error('[Materials] Get by manager error:', error)
|
||||||
return { materials: [] }
|
return { materials: [] }
|
||||||
} finally {
|
} finally {
|
||||||
if (mysqlService) {
|
if (dbService) {
|
||||||
try {
|
try {
|
||||||
await mysqlService.disconnect()
|
await dbService.disconnect()
|
||||||
} catch (closeError) {
|
} catch (closeError) {
|
||||||
console.warn('[Materials] Error disconnecting MySQL:', closeError)
|
console.warn('[Materials] Error disconnecting database:', closeError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -507,28 +550,44 @@ export function registerValidationHandlers(): void {
|
|||||||
ipcMain.handle(
|
ipcMain.handle(
|
||||||
'materials:getAll',
|
'materials:getAll',
|
||||||
async (_event): Promise<{ materials: MaterialRecordSummary[] }> => {
|
async (_event): Promise<{ materials: MaterialRecordSummary[] }> => {
|
||||||
let mysqlService: MySqlService | null = null
|
let dbService: MySqlService | SqlServerService | null = null
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mysqlService = await getValidationMySqlService()
|
dbService = await getValidationDatabaseService()
|
||||||
const dao = new MaterialsToBeDeletedDAO()
|
const dbType = process.env.DB_TYPE?.toLowerCase()
|
||||||
;(dao as any).mysqlService = mysqlService
|
const isSqlServer = dbType === 'sqlserver' || dbType === 'mssql'
|
||||||
|
|
||||||
|
const dao = new MaterialsToBeDeletedDAO()
|
||||||
const materials = await dao.getAllRecords()
|
const materials = await dao.getAllRecords()
|
||||||
const markedCodes = await dao.getAllMaterialCodes()
|
const markedCodes = await dao.getAllMaterialCodes()
|
||||||
|
|
||||||
const enrichedMaterials: MaterialRecordSummary[] = []
|
const enrichedMaterials: MaterialRecordSummary[] = []
|
||||||
|
const detailTableName = getTableName('dbo_DiscreteMaterialPlanData')
|
||||||
|
|
||||||
for (const mat of materials) {
|
for (const mat of materials) {
|
||||||
const detailSql = `
|
let detailResult: any
|
||||||
SELECT MaterialName, Specification, Model
|
|
||||||
FROM dbo_DiscreteMaterialPlanData
|
if (isSqlServer) {
|
||||||
WHERE MaterialCode = ?
|
const sql = require('mssql')
|
||||||
LIMIT 1
|
const detailSql = `
|
||||||
`
|
SELECT TOP 1 MaterialName, Specification, Model
|
||||||
const detailResult = await mysqlService.query(detailSql, [
|
FROM ${detailTableName}
|
||||||
mat.materialCode
|
WHERE MaterialCode = @materialCode
|
||||||
])
|
`
|
||||||
|
detailResult = await (dbService as SqlServerService).queryWithParams(detailSql, {
|
||||||
|
materialCode: { value: mat.materialCode, type: sql.NVarChar }
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
const detailSql = `
|
||||||
|
SELECT MaterialName, Specification, Model
|
||||||
|
FROM ${detailTableName}
|
||||||
|
WHERE MaterialCode = ?
|
||||||
|
LIMIT 1
|
||||||
|
`
|
||||||
|
detailResult = await (dbService as MySqlService).query(detailSql, [
|
||||||
|
mat.materialCode
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
enrichedMaterials.push({
|
enrichedMaterials.push({
|
||||||
materialCode: mat.materialCode,
|
materialCode: mat.materialCode,
|
||||||
@@ -554,11 +613,11 @@ export function registerValidationHandlers(): void {
|
|||||||
console.error('[Materials] Get all error:', error)
|
console.error('[Materials] Get all error:', error)
|
||||||
return { materials: [] }
|
return { materials: [] }
|
||||||
} finally {
|
} finally {
|
||||||
if (mysqlService) {
|
if (dbService) {
|
||||||
try {
|
try {
|
||||||
await mysqlService.disconnect()
|
await dbService.disconnect()
|
||||||
} catch (closeError) {
|
} catch (closeError) {
|
||||||
console.warn('[Materials] Error disconnecting MySQL:', closeError)
|
console.warn('[Materials] Error disconnecting database:', closeError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -571,26 +630,13 @@ export function registerValidationHandlers(): void {
|
|||||||
ipcMain.handle(
|
ipcMain.handle(
|
||||||
'materials:getStatistics',
|
'materials:getStatistics',
|
||||||
async (_event): Promise<{ stats: any }> => {
|
async (_event): Promise<{ stats: any }> => {
|
||||||
let mysqlService: MySqlService | null = null
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mysqlService = await getValidationMySqlService()
|
|
||||||
const dao = new MaterialsToBeDeletedDAO()
|
const dao = new MaterialsToBeDeletedDAO()
|
||||||
;(dao as any).mysqlService = mysqlService
|
|
||||||
|
|
||||||
const stats = await dao.getStatistics()
|
const stats = await dao.getStatistics()
|
||||||
return { stats }
|
return { stats }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[Materials] Get statistics error:', error)
|
console.error('[Materials] Get statistics error:', error)
|
||||||
return { stats: null }
|
return { stats: null }
|
||||||
} finally {
|
|
||||||
if (mysqlService) {
|
|
||||||
try {
|
|
||||||
await mysqlService.disconnect()
|
|
||||||
} catch (closeError) {
|
|
||||||
console.warn('[Materials] Error disconnecting MySQL:', closeError)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -628,7 +674,7 @@ export function registerValidationHandlers(): void {
|
|||||||
materialCodes?: string[]
|
materialCodes?: string[]
|
||||||
error?: string
|
error?: string
|
||||||
}> => {
|
}> => {
|
||||||
let mysqlService: MySqlService | null = null
|
let dbService: MySqlService | SqlServerService | null = null
|
||||||
const sessionManager = (await import('../services/user/session-manager')).SessionManager.getInstance()
|
const sessionManager = (await import('../services/user/session-manager')).SessionManager.getInstance()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -643,11 +689,13 @@ export function registerValidationHandlers(): void {
|
|||||||
|
|
||||||
const isAdmin = userInfo.userType === 'Admin'
|
const isAdmin = userInfo.userType === 'Admin'
|
||||||
const username = userInfo.username
|
const username = userInfo.username
|
||||||
|
const dbType = process.env.DB_TYPE?.toLowerCase()
|
||||||
|
const isSqlServer = dbType === 'sqlserver' || dbType === 'mssql'
|
||||||
|
|
||||||
console.log(`[CleanerData] User: ${username}, isAdmin: ${isAdmin}`)
|
console.log(`[CleanerData] User: ${username}, isAdmin: ${isAdmin}`)
|
||||||
|
|
||||||
// Connect to MySQL
|
// Connect to database
|
||||||
mysqlService = await getValidationMySqlService()
|
dbService = await getValidationDatabaseService()
|
||||||
|
|
||||||
// 1. Get order numbers from shared Production IDs
|
// 1. Get order numbers from shared Production IDs
|
||||||
const sharedIds = getSharedProductionIds()
|
const sharedIds = getSharedProductionIds()
|
||||||
@@ -655,36 +703,55 @@ export function registerValidationHandlers(): void {
|
|||||||
|
|
||||||
if (sharedIds.length > 0) {
|
if (sharedIds.length > 0) {
|
||||||
console.log(`[CleanerData] Using ${sharedIds.length} shared Production IDs`)
|
console.log(`[CleanerData] Using ${sharedIds.length} shared Production IDs`)
|
||||||
orderNumbers = await getSourceNumbersFromInputs(sharedIds, mysqlService)
|
orderNumbers = await getSourceNumbersFromInputs(sharedIds, dbService)
|
||||||
console.log(`[CleanerData] Got ${orderNumbers.length} order numbers`)
|
console.log(`[CleanerData] Got ${orderNumbers.length} order numbers`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Get material codes from MaterialsToBeDeleted table
|
// 2. Get material codes from MaterialsToBeDeleted table
|
||||||
let materialCodes: string[] = []
|
let materialCodes: string[] = []
|
||||||
|
const markedTableName = getTableName('dbo_MaterialsToBeDeleted')
|
||||||
|
|
||||||
if (isAdmin) {
|
if (isAdmin) {
|
||||||
// Admin sees all materials
|
// Admin sees all materials
|
||||||
const allCodesSql = `
|
const allCodesSql = `
|
||||||
SELECT MaterialCode
|
SELECT MaterialCode
|
||||||
FROM dbo_MaterialsToBeDeleted
|
FROM ${markedTableName}
|
||||||
WHERE MaterialCode IS NOT NULL
|
WHERE MaterialCode IS NOT NULL
|
||||||
`
|
`
|
||||||
const result = await mysqlService.query(allCodesSql)
|
const result = isSqlServer
|
||||||
|
? await (dbService as SqlServerService).query(allCodesSql)
|
||||||
|
: await (dbService as MySqlService).query(allCodesSql)
|
||||||
|
|
||||||
materialCodes = result.rows
|
materialCodes = result.rows
|
||||||
.map(row => row.MaterialCode as string)
|
.map(row => row.MaterialCode as string)
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
console.log(`[CleanerData] Admin user: got ${materialCodes.length} materials`)
|
console.log(`[CleanerData] Admin user: got ${materialCodes.length} materials`)
|
||||||
} else {
|
} else {
|
||||||
// Regular users only see their own materials
|
// Regular users only see their own materials
|
||||||
const userMaterialsSql = `
|
if (isSqlServer) {
|
||||||
SELECT MaterialCode
|
const sql = require('mssql')
|
||||||
FROM dbo_MaterialsToBeDeleted
|
const userMaterialsSql = `
|
||||||
WHERE ManagerName = ? AND MaterialCode IS NOT NULL
|
SELECT MaterialCode
|
||||||
`
|
FROM ${markedTableName}
|
||||||
const result = await mysqlService.query(userMaterialsSql, [username])
|
WHERE ManagerName = @username AND MaterialCode IS NOT NULL
|
||||||
materialCodes = result.rows
|
`
|
||||||
.map(row => row.MaterialCode as string)
|
const result = await (dbService as SqlServerService).queryWithParams(userMaterialsSql, {
|
||||||
.filter(Boolean)
|
username: { value: username, type: sql.NVarChar }
|
||||||
|
})
|
||||||
|
materialCodes = result.rows
|
||||||
|
.map(row => row.MaterialCode as string)
|
||||||
|
.filter(Boolean)
|
||||||
|
} else {
|
||||||
|
const userMaterialsSql = `
|
||||||
|
SELECT MaterialCode
|
||||||
|
FROM ${markedTableName}
|
||||||
|
WHERE ManagerName = ? AND MaterialCode IS NOT NULL
|
||||||
|
`
|
||||||
|
const result = await (dbService as MySqlService).query(userMaterialsSql, [username])
|
||||||
|
materialCodes = result.rows
|
||||||
|
.map(row => row.MaterialCode as string)
|
||||||
|
.filter(Boolean)
|
||||||
|
}
|
||||||
console.log(`[CleanerData] Regular user: got ${materialCodes.length} materials`)
|
console.log(`[CleanerData] Regular user: got ${materialCodes.length} materials`)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -701,11 +768,11 @@ export function registerValidationHandlers(): void {
|
|||||||
error: `获取清理数据失败:${message}`
|
error: `获取清理数据失败:${message}`
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (mysqlService) {
|
if (dbService) {
|
||||||
try {
|
try {
|
||||||
await mysqlService.disconnect()
|
await dbService.disconnect()
|
||||||
} catch (closeError) {
|
} catch (closeError) {
|
||||||
console.warn('[CleanerData] Error disconnecting MySQL:', closeError)
|
console.warn('[CleanerData] Error disconnecting database:', closeError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { MySqlService } from './mysql'
|
import { MySqlService } from './mysql'
|
||||||
|
import { SqlServerService } from './sql-server'
|
||||||
|
import sql from 'mssql'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Material plan record interface
|
* Material plan record interface
|
||||||
@@ -50,6 +52,7 @@ export interface MaterialPlanRecord {
|
|||||||
* Configuration for DiscreteMaterialPlanData table
|
* Configuration for DiscreteMaterialPlanData table
|
||||||
*/
|
*/
|
||||||
export const DISCRETE_MATERIAL_PLAN_CONFIG = {
|
export const DISCRETE_MATERIAL_PLAN_CONFIG = {
|
||||||
|
TABLE_NAME_SQLSERVER: '[dbo].[DiscreteMaterialPlanData]',
|
||||||
TABLE_NAME_MYSQL: 'dbo_DiscreteMaterialPlanData',
|
TABLE_NAME_MYSQL: 'dbo_DiscreteMaterialPlanData',
|
||||||
COLUMNS: {
|
COLUMNS: {
|
||||||
ID: 'ID',
|
ID: 'ID',
|
||||||
@@ -90,25 +93,69 @@ export const DISCRETE_MATERIAL_PLAN_CONFIG = {
|
|||||||
*/
|
*/
|
||||||
export class DiscreteMaterialPlanDAO {
|
export class DiscreteMaterialPlanDAO {
|
||||||
private mysqlService: MySqlService | null = null
|
private mysqlService: MySqlService | null = null
|
||||||
|
private sqlServerService: SqlServerService | null = null
|
||||||
|
private dbType: 'mysql' | 'sqlserver' = 'mysql'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get MySQL service instance
|
* Constructor - determine database type from environment
|
||||||
*/
|
*/
|
||||||
private async getMySqlService(): Promise<MySqlService> {
|
constructor() {
|
||||||
if (this.mysqlService && this.mysqlService.isConnected()) {
|
const dbType = process.env.DB_TYPE?.toLowerCase()
|
||||||
|
if (dbType === 'sqlserver' || dbType === 'mssql') {
|
||||||
|
this.dbType = 'sqlserver'
|
||||||
|
} else {
|
||||||
|
this.dbType = 'mysql'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the appropriate table name based on database type
|
||||||
|
*/
|
||||||
|
private getTableName(): string {
|
||||||
|
return this.dbType === 'sqlserver'
|
||||||
|
? DISCRETE_MATERIAL_PLAN_CONFIG.TABLE_NAME_SQLSERVER
|
||||||
|
: DISCRETE_MATERIAL_PLAN_CONFIG.TABLE_NAME_MYSQL
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get database service instance (MySQL or SQL Server)
|
||||||
|
*/
|
||||||
|
private async getDatabaseService(): Promise<MySqlService | SqlServerService> {
|
||||||
|
if (this.dbType === 'sqlserver') {
|
||||||
|
if (this.sqlServerService && this.sqlServerService.isConnected()) {
|
||||||
|
return this.sqlServerService
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sqlServerService = new SqlServerService({
|
||||||
|
server: process.env.DB_SERVER || 'localhost',
|
||||||
|
port: parseInt(process.env.DB_SQLSERVER_PORT || '1433', 10),
|
||||||
|
user: process.env.DB_USERNAME || 'sa',
|
||||||
|
password: process.env.DB_PASSWORD || '',
|
||||||
|
database: process.env.DB_NAME || '',
|
||||||
|
options: {
|
||||||
|
encrypt: process.env.DB_TRUST_SERVER_CERTIFICATE === 'yes',
|
||||||
|
trustServerCertificate: process.env.DB_TRUST_SERVER_CERTIFICATE === 'yes'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
await this.sqlServerService.connect()
|
||||||
|
return this.sqlServerService
|
||||||
|
} else {
|
||||||
|
if (this.mysqlService && this.mysqlService.isConnected()) {
|
||||||
|
return this.mysqlService
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mysqlService = new MySqlService({
|
||||||
|
host: process.env.DB_MYSQL_HOST || 'localhost',
|
||||||
|
port: parseInt(process.env.DB_MYSQL_PORT || '3306', 10),
|
||||||
|
user: process.env.DB_USERNAME || 'root',
|
||||||
|
password: process.env.DB_PASSWORD || '',
|
||||||
|
database: process.env.DB_NAME || ''
|
||||||
|
})
|
||||||
|
|
||||||
|
await this.mysqlService.connect()
|
||||||
return this.mysqlService
|
return this.mysqlService
|
||||||
}
|
}
|
||||||
|
|
||||||
this.mysqlService = new MySqlService({
|
|
||||||
host: process.env.DB_MYSQL_HOST || 'localhost',
|
|
||||||
port: parseInt(process.env.DB_MYSQL_PORT || '3306', 10),
|
|
||||||
user: process.env.DB_USERNAME || 'root',
|
|
||||||
password: process.env.DB_PASSWORD || '',
|
|
||||||
database: process.env.DB_NAME || ''
|
|
||||||
})
|
|
||||||
|
|
||||||
await this.mysqlService.connect()
|
|
||||||
return this.mysqlService
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== QUERY ALL ====================
|
// ==================== QUERY ALL ====================
|
||||||
@@ -119,11 +166,15 @@ export class DiscreteMaterialPlanDAO {
|
|||||||
*/
|
*/
|
||||||
async queryAll(): Promise<any[]> {
|
async queryAll(): Promise<any[]> {
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
|
|
||||||
const sql = `SELECT * FROM ${DISCRETE_MATERIAL_PLAN_CONFIG.TABLE_NAME_MYSQL}`
|
const sql = `SELECT * FROM ${tableName}`
|
||||||
|
|
||||||
|
const result = this.dbType === 'sqlserver'
|
||||||
|
? await (dbService as SqlServerService).query(sql)
|
||||||
|
: await (dbService as MySqlService).query(sql)
|
||||||
|
|
||||||
const result = await mysqlService.query(sql)
|
|
||||||
return result.rows
|
return result.rows
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[DiscreteMaterialPlanDAO] Query all error:', error)
|
console.error('[DiscreteMaterialPlanDAO] Query all error:', error)
|
||||||
@@ -139,7 +190,8 @@ export class DiscreteMaterialPlanDAO {
|
|||||||
*/
|
*/
|
||||||
async queryAllDistinctByMaterialCode(): Promise<any[]> {
|
async queryAllDistinctByMaterialCode(): Promise<any[]> {
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
|
|
||||||
const sql = `
|
const sql = `
|
||||||
WITH RankedRecords AS (
|
WITH RankedRecords AS (
|
||||||
@@ -149,7 +201,7 @@ export class DiscreteMaterialPlanDAO {
|
|||||||
PARTITION BY MaterialCode
|
PARTITION BY MaterialCode
|
||||||
ORDER BY CreateDate ASC, SequenceNumber ASC
|
ORDER BY CreateDate ASC, SequenceNumber ASC
|
||||||
) AS rn
|
) AS rn
|
||||||
FROM ${DISCRETE_MATERIAL_PLAN_CONFIG.TABLE_NAME_MYSQL}
|
FROM ${tableName}
|
||||||
WHERE MaterialCode IS NOT NULL
|
WHERE MaterialCode IS NOT NULL
|
||||||
)
|
)
|
||||||
SELECT
|
SELECT
|
||||||
@@ -163,7 +215,10 @@ export class DiscreteMaterialPlanDAO {
|
|||||||
WHERE rn = 1
|
WHERE rn = 1
|
||||||
`
|
`
|
||||||
|
|
||||||
const result = await mysqlService.query(sql)
|
const result = this.dbType === 'sqlserver'
|
||||||
|
? await (dbService as SqlServerService).query(sql)
|
||||||
|
: await (dbService as MySqlService).query(sql)
|
||||||
|
|
||||||
return result.rows
|
return result.rows
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[DiscreteMaterialPlanDAO] Query all distinct by material code error:', error)
|
console.error('[DiscreteMaterialPlanDAO] Query all distinct by material code error:', error)
|
||||||
@@ -184,22 +239,42 @@ export class DiscreteMaterialPlanDAO {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
const batchSize = 2000
|
const batchSize = 2000
|
||||||
const allResults: any[] = []
|
const allResults: any[] = []
|
||||||
|
|
||||||
for (let i = 0; i < sourceNumbers.length; i += batchSize) {
|
for (let i = 0; i < sourceNumbers.length; i += batchSize) {
|
||||||
const batch = sourceNumbers.slice(i, i + batchSize)
|
const batch = sourceNumbers.slice(i, i + batchSize)
|
||||||
const placeholders = batch.map(() => '?').join(',')
|
|
||||||
|
|
||||||
const sql = `
|
if (this.dbType === 'sqlserver') {
|
||||||
SELECT *
|
const placeholders = batch.map((_, idx) => `@p${idx}`).join(',')
|
||||||
FROM ${DISCRETE_MATERIAL_PLAN_CONFIG.TABLE_NAME_MYSQL}
|
const params: Record<string, { value: string; type: sql.ISqlType }> = {}
|
||||||
WHERE SourceNumber IN (${placeholders})
|
|
||||||
`
|
|
||||||
|
|
||||||
const result = await mysqlService.query(sql, batch)
|
batch.forEach((num, idx) => {
|
||||||
allResults.push(...result.rows)
|
params[`p${idx}`] = { value: num, type: sql.NVarChar }
|
||||||
|
})
|
||||||
|
|
||||||
|
const sql = `
|
||||||
|
SELECT *
|
||||||
|
FROM ${tableName}
|
||||||
|
WHERE SourceNumber IN (${placeholders})
|
||||||
|
`
|
||||||
|
|
||||||
|
const result = await (dbService as SqlServerService).queryWithParams(sql, params)
|
||||||
|
allResults.push(...result.rows)
|
||||||
|
} else {
|
||||||
|
const placeholders = batch.map(() => '?').join(',')
|
||||||
|
|
||||||
|
const sql = `
|
||||||
|
SELECT *
|
||||||
|
FROM ${tableName}
|
||||||
|
WHERE SourceNumber IN (${placeholders})
|
||||||
|
`
|
||||||
|
|
||||||
|
const result = await (dbService as MySqlService).query(sql, batch)
|
||||||
|
allResults.push(...result.rows)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return allResults
|
return allResults
|
||||||
@@ -222,39 +297,76 @@ export class DiscreteMaterialPlanDAO {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
const batchSize = 2000
|
const batchSize = 2000
|
||||||
const allResults: any[] = []
|
const allResults: any[] = []
|
||||||
|
|
||||||
for (let i = 0; i < sourceNumbers.length; i += batchSize) {
|
for (let i = 0; i < sourceNumbers.length; i += batchSize) {
|
||||||
const batch = sourceNumbers.slice(i, i + batchSize)
|
const batch = sourceNumbers.slice(i, i + batchSize)
|
||||||
const placeholders = batch.map(() => '?').join(',')
|
|
||||||
|
|
||||||
const sql = `
|
if (this.dbType === 'sqlserver') {
|
||||||
WITH RankedRecords AS (
|
const placeholders = batch.map((_, idx) => `@p${idx}`).join(',')
|
||||||
|
const params: Record<string, { value: string; type: sql.ISqlType }> = {}
|
||||||
|
|
||||||
|
batch.forEach((num, idx) => {
|
||||||
|
params[`p${idx}`] = { value: num, type: sql.NVarChar }
|
||||||
|
})
|
||||||
|
|
||||||
|
const sql = `
|
||||||
|
WITH RankedRecords AS (
|
||||||
|
SELECT
|
||||||
|
*,
|
||||||
|
ROW_NUMBER() OVER (
|
||||||
|
PARTITION BY MaterialCode
|
||||||
|
ORDER BY CreateDate ASC, SequenceNumber ASC
|
||||||
|
) AS rn
|
||||||
|
FROM ${tableName}
|
||||||
|
WHERE SourceNumber IN (${placeholders})
|
||||||
|
AND MaterialCode IS NOT NULL
|
||||||
|
)
|
||||||
SELECT
|
SELECT
|
||||||
*,
|
Factory, MaterialStatus, PlanNumber, SourceNumber, MaterialType,
|
||||||
ROW_NUMBER() OVER (
|
ProductCode, ProductName, ProductUnit, ProductPlanQuantity,
|
||||||
PARTITION BY MaterialCode
|
UseDepartment, Remark, Creator, CreateDate, Approver, ApproveDate,
|
||||||
ORDER BY CreateDate ASC, SequenceNumber ASC
|
SequenceNumber, MaterialCode, MaterialName, Specification, Model,
|
||||||
) AS rn
|
DrawingNumber, MaterialQuality, PlanQuantity, Unit, RequiredDate,
|
||||||
FROM ${DISCRETE_MATERIAL_PLAN_CONFIG.TABLE_NAME_MYSQL}
|
Warehouse, UnitUsage, CumulativeOutputQuantity, BOMVersion
|
||||||
WHERE SourceNumber IN (${placeholders})
|
FROM RankedRecords
|
||||||
AND MaterialCode IS NOT NULL
|
WHERE rn = 1
|
||||||
)
|
`
|
||||||
SELECT
|
|
||||||
Factory, MaterialStatus, PlanNumber, SourceNumber, MaterialType,
|
|
||||||
ProductCode, ProductName, ProductUnit, ProductPlanQuantity,
|
|
||||||
UseDepartment, Remark, Creator, CreateDate, Approver, ApproveDate,
|
|
||||||
SequenceNumber, MaterialCode, MaterialName, Specification, Model,
|
|
||||||
DrawingNumber, MaterialQuality, PlanQuantity, Unit, RequiredDate,
|
|
||||||
Warehouse, UnitUsage, CumulativeOutputQuantity, BOMVersion
|
|
||||||
FROM RankedRecords
|
|
||||||
WHERE rn = 1
|
|
||||||
`
|
|
||||||
|
|
||||||
const result = await mysqlService.query(sql, batch)
|
const result = await (dbService as SqlServerService).queryWithParams(sql, params)
|
||||||
allResults.push(...result.rows)
|
allResults.push(...result.rows)
|
||||||
|
} else {
|
||||||
|
const placeholders = batch.map(() => '?').join(',')
|
||||||
|
|
||||||
|
const sql = `
|
||||||
|
WITH RankedRecords AS (
|
||||||
|
SELECT
|
||||||
|
*,
|
||||||
|
ROW_NUMBER() OVER (
|
||||||
|
PARTITION BY MaterialCode
|
||||||
|
ORDER BY CreateDate ASC, SequenceNumber ASC
|
||||||
|
) AS rn
|
||||||
|
FROM ${tableName}
|
||||||
|
WHERE SourceNumber IN (${placeholders})
|
||||||
|
AND MaterialCode IS NOT NULL
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
Factory, MaterialStatus, PlanNumber, SourceNumber, MaterialType,
|
||||||
|
ProductCode, ProductName, ProductUnit, ProductPlanQuantity,
|
||||||
|
UseDepartment, Remark, Creator, CreateDate, Approver, ApproveDate,
|
||||||
|
SequenceNumber, MaterialCode, MaterialName, Specification, Model,
|
||||||
|
DrawingNumber, MaterialQuality, PlanQuantity, Unit, RequiredDate,
|
||||||
|
Warehouse, UnitUsage, CumulativeOutputQuantity, BOMVersion
|
||||||
|
FROM RankedRecords
|
||||||
|
WHERE rn = 1
|
||||||
|
`
|
||||||
|
|
||||||
|
const result = await (dbService as MySqlService).query(sql, batch)
|
||||||
|
allResults.push(...result.rows)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return allResults
|
return allResults
|
||||||
@@ -271,16 +383,32 @@ export class DiscreteMaterialPlanDAO {
|
|||||||
*/
|
*/
|
||||||
async queryBySourceNumber(sourceNumber: string): Promise<any[]> {
|
async queryBySourceNumber(sourceNumber: string): Promise<any[]> {
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
|
|
||||||
const sql = `
|
if (this.dbType === 'sqlserver') {
|
||||||
SELECT *
|
const sql = `
|
||||||
FROM ${DISCRETE_MATERIAL_PLAN_CONFIG.TABLE_NAME_MYSQL}
|
SELECT *
|
||||||
WHERE SourceNumber = ?
|
FROM ${tableName}
|
||||||
`
|
WHERE SourceNumber = @sourceNumber
|
||||||
|
`
|
||||||
|
|
||||||
const result = await mysqlService.query(sql, [sourceNumber])
|
const result = await (dbService as SqlServerService).queryWithParams(sql, {
|
||||||
return result.rows
|
sourceNumber: { value: sourceNumber, type: sql.NVarChar }
|
||||||
|
})
|
||||||
|
|
||||||
|
return result.rows
|
||||||
|
} else {
|
||||||
|
const sql = `
|
||||||
|
SELECT *
|
||||||
|
FROM ${tableName}
|
||||||
|
WHERE SourceNumber = ?
|
||||||
|
`
|
||||||
|
|
||||||
|
const result = await (dbService as MySqlService).query(sql, [sourceNumber])
|
||||||
|
|
||||||
|
return result.rows
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[DiscreteMaterialPlanDAO] Query by source number error:', error)
|
console.error('[DiscreteMaterialPlanDAO] Query by source number error:', error)
|
||||||
return []
|
return []
|
||||||
@@ -296,16 +424,32 @@ export class DiscreteMaterialPlanDAO {
|
|||||||
*/
|
*/
|
||||||
async queryByPlanNumber(planNumber: string): Promise<any[]> {
|
async queryByPlanNumber(planNumber: string): Promise<any[]> {
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
|
|
||||||
const sql = `
|
if (this.dbType === 'sqlserver') {
|
||||||
SELECT *
|
const sql = `
|
||||||
FROM ${DISCRETE_MATERIAL_PLAN_CONFIG.TABLE_NAME_MYSQL}
|
SELECT *
|
||||||
WHERE PlanNumber = ?
|
FROM ${tableName}
|
||||||
`
|
WHERE PlanNumber = @planNumber
|
||||||
|
`
|
||||||
|
|
||||||
const result = await mysqlService.query(sql, [planNumber])
|
const result = await (dbService as SqlServerService).queryWithParams(sql, {
|
||||||
return result.rows
|
planNumber: { value: planNumber, type: sql.NVarChar }
|
||||||
|
})
|
||||||
|
|
||||||
|
return result.rows
|
||||||
|
} else {
|
||||||
|
const sql = `
|
||||||
|
SELECT *
|
||||||
|
FROM ${tableName}
|
||||||
|
WHERE PlanNumber = ?
|
||||||
|
`
|
||||||
|
|
||||||
|
const result = await (dbService as MySqlService).query(sql, [planNumber])
|
||||||
|
|
||||||
|
return result.rows
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[DiscreteMaterialPlanDAO] Query by plan number error:', error)
|
console.error('[DiscreteMaterialPlanDAO] Query by plan number error:', error)
|
||||||
return []
|
return []
|
||||||
@@ -323,17 +467,37 @@ export class DiscreteMaterialPlanDAO {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
const placeholders = planNumbers.map(() => '?').join(',')
|
const tableName = this.getTableName()
|
||||||
|
|
||||||
const sql = `
|
if (this.dbType === 'sqlserver') {
|
||||||
SELECT *
|
const placeholders = planNumbers.map((_, idx) => `@p${idx}`).join(',')
|
||||||
FROM ${DISCRETE_MATERIAL_PLAN_CONFIG.TABLE_NAME_MYSQL}
|
const params: Record<string, { value: string; type: sql.ISqlType }> = {}
|
||||||
WHERE PlanNumber IN (${placeholders})
|
|
||||||
`
|
|
||||||
|
|
||||||
const result = await mysqlService.query(sql, planNumbers)
|
planNumbers.forEach((num, idx) => {
|
||||||
return result.rows
|
params[`p${idx}`] = { value: num, type: sql.NVarChar }
|
||||||
|
})
|
||||||
|
|
||||||
|
const sql = `
|
||||||
|
SELECT *
|
||||||
|
FROM ${tableName}
|
||||||
|
WHERE PlanNumber IN (${placeholders})
|
||||||
|
`
|
||||||
|
|
||||||
|
const result = await (dbService as SqlServerService).queryWithParams(sql, params)
|
||||||
|
return result.rows
|
||||||
|
} else {
|
||||||
|
const placeholders = planNumbers.map(() => '?').join(',')
|
||||||
|
|
||||||
|
const sql = `
|
||||||
|
SELECT *
|
||||||
|
FROM ${tableName}
|
||||||
|
WHERE PlanNumber IN (${placeholders})
|
||||||
|
`
|
||||||
|
|
||||||
|
const result = await (dbService as MySqlService).query(sql, planNumbers)
|
||||||
|
return result.rows
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[DiscreteMaterialPlanDAO] Query by plan numbers error:', error)
|
console.error('[DiscreteMaterialPlanDAO] Query by plan numbers error:', error)
|
||||||
return []
|
return []
|
||||||
@@ -348,11 +512,15 @@ export class DiscreteMaterialPlanDAO {
|
|||||||
*/
|
*/
|
||||||
async countAll(): Promise<number> {
|
async countAll(): Promise<number> {
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
|
|
||||||
const sql = `SELECT COUNT(*) as count FROM ${DISCRETE_MATERIAL_PLAN_CONFIG.TABLE_NAME_MYSQL}`
|
const sql = `SELECT COUNT(*) as count FROM ${tableName}`
|
||||||
|
|
||||||
|
const result = this.dbType === 'sqlserver'
|
||||||
|
? await (dbService as SqlServerService).query(sql)
|
||||||
|
: await (dbService as MySqlService).query(sql)
|
||||||
|
|
||||||
const result = await mysqlService.query(sql)
|
|
||||||
return result.rows.length > 0 ? (result.rows[0].count as number) : 0
|
return result.rows.length > 0 ? (result.rows[0].count as number) : 0
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[DiscreteMaterialPlanDAO] Count all error:', error)
|
console.error('[DiscreteMaterialPlanDAO] Count all error:', error)
|
||||||
@@ -367,16 +535,32 @@ export class DiscreteMaterialPlanDAO {
|
|||||||
*/
|
*/
|
||||||
async countByPlanNumber(planNumber: string): Promise<number> {
|
async countByPlanNumber(planNumber: string): Promise<number> {
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
|
|
||||||
const sql = `
|
if (this.dbType === 'sqlserver') {
|
||||||
SELECT COUNT(*) as count
|
const sql = `
|
||||||
FROM ${DISCRETE_MATERIAL_PLAN_CONFIG.TABLE_NAME_MYSQL}
|
SELECT COUNT(*) as count
|
||||||
WHERE PlanNumber = ?
|
FROM ${tableName}
|
||||||
`
|
WHERE PlanNumber = @planNumber
|
||||||
|
`
|
||||||
|
|
||||||
const result = await mysqlService.query(sql, [planNumber])
|
const result = await (dbService as SqlServerService).queryWithParams(sql, {
|
||||||
return result.rows.length > 0 ? (result.rows[0].count as number) : 0
|
planNumber: { value: planNumber, type: sql.NVarChar }
|
||||||
|
})
|
||||||
|
|
||||||
|
return result.rows.length > 0 ? (result.rows[0].count as number) : 0
|
||||||
|
} else {
|
||||||
|
const sql = `
|
||||||
|
SELECT COUNT(*) as count
|
||||||
|
FROM ${tableName}
|
||||||
|
WHERE PlanNumber = ?
|
||||||
|
`
|
||||||
|
|
||||||
|
const result = await (dbService as MySqlService).query(sql, [planNumber])
|
||||||
|
|
||||||
|
return result.rows.length > 0 ? (result.rows[0].count as number) : 0
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[DiscreteMaterialPlanDAO] Count by plan number error:', error)
|
console.error('[DiscreteMaterialPlanDAO] Count by plan number error:', error)
|
||||||
return 0
|
return 0
|
||||||
@@ -390,32 +574,59 @@ export class DiscreteMaterialPlanDAO {
|
|||||||
*/
|
*/
|
||||||
async getUniqueMaterialNames(sourceNumbers?: string[]): Promise<string[]> {
|
async getUniqueMaterialNames(sourceNumbers?: string[]): Promise<string[]> {
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
let sql: string
|
|
||||||
let params: any[] = []
|
|
||||||
|
|
||||||
if (sourceNumbers && sourceNumbers.length > 0) {
|
if (sourceNumbers && sourceNumbers.length > 0) {
|
||||||
const placeholders = sourceNumbers.map(() => '?').join(',')
|
if (this.dbType === 'sqlserver') {
|
||||||
sql = `
|
const placeholders = sourceNumbers.map((_, idx) => `@p${idx}`).join(',')
|
||||||
SELECT DISTINCT MaterialName
|
const params: Record<string, { value: string; type: sql.ISqlType }> = {}
|
||||||
FROM ${DISCRETE_MATERIAL_PLAN_CONFIG.TABLE_NAME_MYSQL}
|
|
||||||
WHERE SourceNumber IN (${placeholders})
|
sourceNumbers.forEach((num, idx) => {
|
||||||
AND MaterialName IS NOT NULL
|
params[`p${idx}`] = { value: num, type: sql.NVarChar }
|
||||||
`
|
})
|
||||||
params = sourceNumbers
|
|
||||||
|
const sql = `
|
||||||
|
SELECT DISTINCT MaterialName
|
||||||
|
FROM ${tableName}
|
||||||
|
WHERE SourceNumber IN (${placeholders})
|
||||||
|
AND MaterialName IS NOT NULL
|
||||||
|
`
|
||||||
|
|
||||||
|
const result = await (dbService as SqlServerService).queryWithParams(sql, params)
|
||||||
|
return result.rows
|
||||||
|
.map(row => row.MaterialName as string)
|
||||||
|
.filter(Boolean)
|
||||||
|
} else {
|
||||||
|
const placeholders = sourceNumbers.map(() => '?').join(',')
|
||||||
|
|
||||||
|
const sql = `
|
||||||
|
SELECT DISTINCT MaterialName
|
||||||
|
FROM ${tableName}
|
||||||
|
WHERE SourceNumber IN (${placeholders})
|
||||||
|
AND MaterialName IS NOT NULL
|
||||||
|
`
|
||||||
|
|
||||||
|
const result = await (dbService as MySqlService).query(sql, sourceNumbers)
|
||||||
|
return result.rows
|
||||||
|
.map(row => row.MaterialName as string)
|
||||||
|
.filter(Boolean)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
sql = `
|
const sql = `
|
||||||
SELECT DISTINCT MaterialName
|
SELECT DISTINCT MaterialName
|
||||||
FROM ${DISCRETE_MATERIAL_PLAN_CONFIG.TABLE_NAME_MYSQL}
|
FROM ${tableName}
|
||||||
WHERE MaterialName IS NOT NULL
|
WHERE MaterialName IS NOT NULL
|
||||||
`
|
`
|
||||||
}
|
|
||||||
|
|
||||||
const result = await mysqlService.query(sql, params)
|
const result = this.dbType === 'sqlserver'
|
||||||
return result.rows
|
? await (dbService as SqlServerService).query(sql)
|
||||||
.map(row => row.MaterialName as string)
|
: await (dbService as MySqlService).query(sql)
|
||||||
.filter(Boolean)
|
|
||||||
|
return result.rows
|
||||||
|
.map(row => row.MaterialName as string)
|
||||||
|
.filter(Boolean)
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[DiscreteMaterialPlanDAO] Get unique material names error:', error)
|
console.error('[DiscreteMaterialPlanDAO] Get unique material names error:', error)
|
||||||
return []
|
return []
|
||||||
@@ -428,7 +639,8 @@ export class DiscreteMaterialPlanDAO {
|
|||||||
*/
|
*/
|
||||||
async getStatistics(): Promise<any> {
|
async getStatistics(): Promise<any> {
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
|
|
||||||
const sql = `
|
const sql = `
|
||||||
SELECT
|
SELECT
|
||||||
@@ -437,10 +649,13 @@ export class DiscreteMaterialPlanDAO {
|
|||||||
COUNT(DISTINCT SourceNumber) as uniqueOrders,
|
COUNT(DISTINCT SourceNumber) as uniqueOrders,
|
||||||
MIN(CreateDate) as earliestRecord,
|
MIN(CreateDate) as earliestRecord,
|
||||||
MAX(CreateDate) as latestRecord
|
MAX(CreateDate) as latestRecord
|
||||||
FROM ${DISCRETE_MATERIAL_PLAN_CONFIG.TABLE_NAME_MYSQL}
|
FROM ${tableName}
|
||||||
`
|
`
|
||||||
|
|
||||||
const result = await mysqlService.query(sql)
|
const result = this.dbType === 'sqlserver'
|
||||||
|
? await (dbService as SqlServerService).query(sql)
|
||||||
|
: await (dbService as MySqlService).query(sql)
|
||||||
|
|
||||||
return result.rows.length > 0 ? result.rows[0] : {}
|
return result.rows.length > 0 ? result.rows[0] : {}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[DiscreteMaterialPlanDAO] Get statistics error:', error)
|
console.error('[DiscreteMaterialPlanDAO] Get statistics error:', error)
|
||||||
@@ -456,5 +671,9 @@ export class DiscreteMaterialPlanDAO {
|
|||||||
await this.mysqlService.disconnect()
|
await this.mysqlService.disconnect()
|
||||||
this.mysqlService = null
|
this.mysqlService = null
|
||||||
}
|
}
|
||||||
|
if (this.sqlServerService) {
|
||||||
|
await this.sqlServerService.disconnect()
|
||||||
|
this.sqlServerService = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { MySqlService } from './mysql'
|
import { MySqlService } from './mysql'
|
||||||
|
import { SqlServerService } from './sql-server'
|
||||||
|
import sql from 'mssql'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Material record interface
|
* Material record interface
|
||||||
@@ -41,6 +43,7 @@ export interface MaterialStats {
|
|||||||
* Configuration for MaterialsToBeDeleted table
|
* Configuration for MaterialsToBeDeleted table
|
||||||
*/
|
*/
|
||||||
export const MATERIALS_TO_BE_DELETED_CONFIG = {
|
export const MATERIALS_TO_BE_DELETED_CONFIG = {
|
||||||
|
TABLE_NAME_SQLSERVER: '[dbo].[MaterialsToBeDeleted]',
|
||||||
TABLE_NAME_MYSQL: 'dbo_MaterialsToBeDeleted',
|
TABLE_NAME_MYSQL: 'dbo_MaterialsToBeDeleted',
|
||||||
COLUMNS: {
|
COLUMNS: {
|
||||||
ID: 'ID',
|
ID: 'ID',
|
||||||
@@ -54,25 +57,69 @@ export const MATERIALS_TO_BE_DELETED_CONFIG = {
|
|||||||
*/
|
*/
|
||||||
export class MaterialsToBeDeletedDAO {
|
export class MaterialsToBeDeletedDAO {
|
||||||
private mysqlService: MySqlService | null = null
|
private mysqlService: MySqlService | null = null
|
||||||
|
private sqlServerService: SqlServerService | null = null
|
||||||
|
private dbType: 'mysql' | 'sqlserver' = 'mysql'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get MySQL service instance
|
* Constructor - determine database type from environment
|
||||||
*/
|
*/
|
||||||
private async getMySqlService(): Promise<MySqlService> {
|
constructor() {
|
||||||
if (this.mysqlService && this.mysqlService.isConnected()) {
|
const dbType = process.env.DB_TYPE?.toLowerCase()
|
||||||
|
if (dbType === 'sqlserver' || dbType === 'mssql') {
|
||||||
|
this.dbType = 'sqlserver'
|
||||||
|
} else {
|
||||||
|
this.dbType = 'mysql'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the appropriate table name based on database type
|
||||||
|
*/
|
||||||
|
private getTableName(): string {
|
||||||
|
return this.dbType === 'sqlserver'
|
||||||
|
? MATERIALS_TO_BE_DELETED_CONFIG.TABLE_NAME_SQLSERVER
|
||||||
|
: MATERIALS_TO_BE_DELETED_CONFIG.TABLE_NAME_MYSQL
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get database service instance (MySQL or SQL Server)
|
||||||
|
*/
|
||||||
|
private async getDatabaseService(): Promise<MySqlService | SqlServerService> {
|
||||||
|
if (this.dbType === 'sqlserver') {
|
||||||
|
if (this.sqlServerService && this.sqlServerService.isConnected()) {
|
||||||
|
return this.sqlServerService
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sqlServerService = new SqlServerService({
|
||||||
|
server: process.env.DB_SERVER || 'localhost',
|
||||||
|
port: parseInt(process.env.DB_SQLSERVER_PORT || '1433', 10),
|
||||||
|
user: process.env.DB_USERNAME || 'sa',
|
||||||
|
password: process.env.DB_PASSWORD || '',
|
||||||
|
database: process.env.DB_NAME || '',
|
||||||
|
options: {
|
||||||
|
encrypt: process.env.DB_TRUST_SERVER_CERTIFICATE === 'yes',
|
||||||
|
trustServerCertificate: process.env.DB_TRUST_SERVER_CERTIFICATE === 'yes'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
await this.sqlServerService.connect()
|
||||||
|
return this.sqlServerService
|
||||||
|
} else {
|
||||||
|
if (this.mysqlService && this.mysqlService.isConnected()) {
|
||||||
|
return this.mysqlService
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mysqlService = new MySqlService({
|
||||||
|
host: process.env.DB_MYSQL_HOST || 'localhost',
|
||||||
|
port: parseInt(process.env.DB_MYSQL_PORT || '3306', 10),
|
||||||
|
user: process.env.DB_USERNAME || 'root',
|
||||||
|
password: process.env.DB_PASSWORD || '',
|
||||||
|
database: process.env.DB_NAME || ''
|
||||||
|
})
|
||||||
|
|
||||||
|
await this.mysqlService.connect()
|
||||||
return this.mysqlService
|
return this.mysqlService
|
||||||
}
|
}
|
||||||
|
|
||||||
this.mysqlService = new MySqlService({
|
|
||||||
host: process.env.DB_MYSQL_HOST || 'localhost',
|
|
||||||
port: parseInt(process.env.DB_MYSQL_PORT || '3306', 10),
|
|
||||||
user: process.env.DB_USERNAME || 'root',
|
|
||||||
password: process.env.DB_PASSWORD || '',
|
|
||||||
database: process.env.DB_NAME || ''
|
|
||||||
})
|
|
||||||
|
|
||||||
await this.mysqlService.connect()
|
|
||||||
return this.mysqlService
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== UPSERT (MERGE) ====================
|
// ==================== UPSERT (MERGE) ====================
|
||||||
@@ -90,15 +137,34 @@ export class MaterialsToBeDeletedDAO {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
|
const code = materialCode.trim()
|
||||||
|
const manager = managerName?.trim() || null
|
||||||
|
|
||||||
const sql = `
|
if (this.dbType === 'sqlserver') {
|
||||||
INSERT INTO ${MATERIALS_TO_BE_DELETED_CONFIG.TABLE_NAME_MYSQL} (MaterialCode, ManagerName)
|
const sql = `
|
||||||
VALUES (?, ?)
|
MERGE ${tableName} AS target
|
||||||
ON DUPLICATE KEY UPDATE ManagerName = VALUES(ManagerName)
|
USING (VALUES (@materialCode, @managerName)) AS source (MaterialCode, ManagerName)
|
||||||
`
|
ON target.MaterialCode = source.MaterialCode
|
||||||
|
WHEN MATCHED THEN UPDATE SET ManagerName = source.ManagerName
|
||||||
|
WHEN NOT MATCHED THEN INSERT (MaterialCode, ManagerName) VALUES (source.MaterialCode, source.ManagerName);
|
||||||
|
`
|
||||||
|
|
||||||
|
await (dbService as SqlServerService).queryWithParams(sql, {
|
||||||
|
materialCode: { value: code, type: sql.NVarChar },
|
||||||
|
managerName: { value: manager, type: sql.NVarChar }
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
const sql = `
|
||||||
|
INSERT INTO ${tableName} (MaterialCode, ManagerName)
|
||||||
|
VALUES (?, ?)
|
||||||
|
ON DUPLICATE KEY UPDATE ManagerName = VALUES(ManagerName)
|
||||||
|
`
|
||||||
|
|
||||||
|
await (dbService as MySqlService).query(sql, [code, manager])
|
||||||
|
}
|
||||||
|
|
||||||
await mysqlService.query(sql, [materialCode.trim(), managerName?.trim() || null])
|
|
||||||
return true
|
return true
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[MaterialsToBeDeletedDAO] Upsert material error:', error)
|
console.error('[MaterialsToBeDeletedDAO] Upsert material error:', error)
|
||||||
@@ -123,7 +189,8 @@ export class MaterialsToBeDeletedDAO {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
|
|
||||||
for (const material of materials) {
|
for (const material of materials) {
|
||||||
const materialCode = material.materialCode?.trim()
|
const materialCode = material.materialCode?.trim()
|
||||||
@@ -135,13 +202,29 @@ export class MaterialsToBeDeletedDAO {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const sql = `
|
if (this.dbType === 'sqlserver') {
|
||||||
INSERT INTO ${MATERIALS_TO_BE_DELETED_CONFIG.TABLE_NAME_MYSQL} (MaterialCode, ManagerName)
|
const sql = `
|
||||||
VALUES (?, ?)
|
MERGE ${tableName} AS target
|
||||||
ON DUPLICATE KEY UPDATE ManagerName = VALUES(ManagerName)
|
USING (VALUES (@materialCode, @managerName)) AS source (MaterialCode, ManagerName)
|
||||||
`
|
ON target.MaterialCode = source.MaterialCode
|
||||||
|
WHEN MATCHED THEN UPDATE SET ManagerName = source.ManagerName
|
||||||
|
WHEN NOT MATCHED THEN INSERT (MaterialCode, ManagerName) VALUES (source.MaterialCode, source.ManagerName);
|
||||||
|
`
|
||||||
|
|
||||||
|
await (dbService as SqlServerService).queryWithParams(sql, {
|
||||||
|
materialCode: { value: materialCode, type: sql.NVarChar },
|
||||||
|
managerName: { value: managerName || null, type: sql.NVarChar }
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
const sql = `
|
||||||
|
INSERT INTO ${tableName} (MaterialCode, ManagerName)
|
||||||
|
VALUES (?, ?)
|
||||||
|
ON DUPLICATE KEY UPDATE ManagerName = VALUES(ManagerName)
|
||||||
|
`
|
||||||
|
|
||||||
|
await (dbService as MySqlService).query(sql, [materialCode, managerName || null])
|
||||||
|
}
|
||||||
|
|
||||||
await mysqlService.query(sql, [materialCode, managerName || null])
|
|
||||||
stats.success++
|
stats.success++
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[MaterialsToBeDeletedDAO] Error upserting material:', materialCode, error)
|
console.error('[MaterialsToBeDeletedDAO] Error upserting material:', materialCode, error)
|
||||||
@@ -164,15 +247,19 @@ export class MaterialsToBeDeletedDAO {
|
|||||||
*/
|
*/
|
||||||
async getAllMaterialCodes(): Promise<Set<string>> {
|
async getAllMaterialCodes(): Promise<Set<string>> {
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
|
|
||||||
const sql = `
|
const sql = `
|
||||||
SELECT MaterialCode
|
SELECT MaterialCode
|
||||||
FROM ${MATERIALS_TO_BE_DELETED_CONFIG.TABLE_NAME_MYSQL}
|
FROM ${tableName}
|
||||||
WHERE MaterialCode IS NOT NULL
|
WHERE MaterialCode IS NOT NULL
|
||||||
`
|
`
|
||||||
|
|
||||||
const result = await mysqlService.query(sql)
|
const result = this.dbType === 'sqlserver'
|
||||||
|
? await (dbService as SqlServerService).query(sql)
|
||||||
|
: await (dbService as MySqlService).query(sql)
|
||||||
|
|
||||||
return new Set(result.rows.map(row => row.MaterialCode as string).filter(Boolean))
|
return new Set(result.rows.map(row => row.MaterialCode as string).filter(Boolean))
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[MaterialsToBeDeletedDAO] Get all material codes error:', error)
|
console.error('[MaterialsToBeDeletedDAO] Get all material codes error:', error)
|
||||||
@@ -186,16 +273,20 @@ export class MaterialsToBeDeletedDAO {
|
|||||||
*/
|
*/
|
||||||
async getAllRecords(): Promise<MaterialRecord[]> {
|
async getAllRecords(): Promise<MaterialRecord[]> {
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
|
|
||||||
const sql = `
|
const sql = `
|
||||||
SELECT ID, MaterialCode, ManagerName
|
SELECT ID, MaterialCode, ManagerName
|
||||||
FROM ${MATERIALS_TO_BE_DELETED_CONFIG.TABLE_NAME_MYSQL}
|
FROM ${tableName}
|
||||||
WHERE MaterialCode IS NOT NULL
|
WHERE MaterialCode IS NOT NULL
|
||||||
ORDER BY ManagerName, MaterialCode
|
ORDER BY ManagerName, MaterialCode
|
||||||
`
|
`
|
||||||
|
|
||||||
const result = await mysqlService.query(sql)
|
const result = this.dbType === 'sqlserver'
|
||||||
|
? await (dbService as SqlServerService).query(sql)
|
||||||
|
: await (dbService as MySqlService).query(sql)
|
||||||
|
|
||||||
return result.rows.map(row => ({
|
return result.rows.map(row => ({
|
||||||
id: row.ID as number,
|
id: row.ID as number,
|
||||||
materialCode: row.MaterialCode as string,
|
materialCode: row.MaterialCode as string,
|
||||||
@@ -214,21 +305,42 @@ export class MaterialsToBeDeletedDAO {
|
|||||||
*/
|
*/
|
||||||
async getMaterialsByManager(managerName: string): Promise<MaterialRecord[]> {
|
async getMaterialsByManager(managerName: string): Promise<MaterialRecord[]> {
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
|
|
||||||
const sql = `
|
if (this.dbType === 'sqlserver') {
|
||||||
SELECT ID, MaterialCode, ManagerName
|
const sql = `
|
||||||
FROM ${MATERIALS_TO_BE_DELETED_CONFIG.TABLE_NAME_MYSQL}
|
SELECT ID, MaterialCode, ManagerName
|
||||||
WHERE ManagerName = ? AND MaterialCode IS NOT NULL
|
FROM ${tableName}
|
||||||
ORDER BY MaterialCode
|
WHERE ManagerName = @managerName AND MaterialCode IS NOT NULL
|
||||||
`
|
ORDER BY MaterialCode
|
||||||
|
`
|
||||||
|
|
||||||
const result = await mysqlService.query(sql, [managerName])
|
const result = await (dbService as SqlServerService).queryWithParams(sql, {
|
||||||
return result.rows.map(row => ({
|
managerName: { value: managerName, type: sql.NVarChar }
|
||||||
id: row.ID as number,
|
})
|
||||||
materialCode: row.MaterialCode as string,
|
|
||||||
managerName: row.ManagerName as string
|
return result.rows.map(row => ({
|
||||||
}))
|
id: row.ID as number,
|
||||||
|
materialCode: row.MaterialCode as string,
|
||||||
|
managerName: row.ManagerName as string
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
const sql = `
|
||||||
|
SELECT ID, MaterialCode, ManagerName
|
||||||
|
FROM ${tableName}
|
||||||
|
WHERE ManagerName = ? AND MaterialCode IS NOT NULL
|
||||||
|
ORDER BY MaterialCode
|
||||||
|
`
|
||||||
|
|
||||||
|
const result = await (dbService as MySqlService).query(sql, [managerName])
|
||||||
|
|
||||||
|
return result.rows.map(row => ({
|
||||||
|
id: row.ID as number,
|
||||||
|
materialCode: row.MaterialCode as string,
|
||||||
|
managerName: row.ManagerName as string
|
||||||
|
}))
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[MaterialsToBeDeletedDAO] Get materials by manager error:', error)
|
console.error('[MaterialsToBeDeletedDAO] Get materials by manager error:', error)
|
||||||
return []
|
return []
|
||||||
@@ -241,16 +353,20 @@ export class MaterialsToBeDeletedDAO {
|
|||||||
*/
|
*/
|
||||||
async getManagers(): Promise<string[]> {
|
async getManagers(): Promise<string[]> {
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
|
|
||||||
const sql = `
|
const sql = `
|
||||||
SELECT DISTINCT ManagerName
|
SELECT DISTINCT ManagerName
|
||||||
FROM ${MATERIALS_TO_BE_DELETED_CONFIG.TABLE_NAME_MYSQL}
|
FROM ${tableName}
|
||||||
WHERE ManagerName IS NOT NULL
|
WHERE ManagerName IS NOT NULL
|
||||||
ORDER BY ManagerName
|
ORDER BY ManagerName
|
||||||
`
|
`
|
||||||
|
|
||||||
const result = await mysqlService.query(sql)
|
const result = this.dbType === 'sqlserver'
|
||||||
|
? await (dbService as SqlServerService).query(sql)
|
||||||
|
: await (dbService as MySqlService).query(sql)
|
||||||
|
|
||||||
return result.rows.map(row => row.ManagerName as string).filter(Boolean)
|
return result.rows.map(row => row.ManagerName as string).filter(Boolean)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[MaterialsToBeDeletedDAO] Get managers error:', error)
|
console.error('[MaterialsToBeDeletedDAO] Get managers error:', error)
|
||||||
@@ -265,24 +381,50 @@ export class MaterialsToBeDeletedDAO {
|
|||||||
*/
|
*/
|
||||||
async getRecordByMaterialCode(materialCode: string): Promise<MaterialRecord | null> {
|
async getRecordByMaterialCode(materialCode: string): Promise<MaterialRecord | null> {
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
|
const code = materialCode.trim()
|
||||||
|
|
||||||
const sql = `
|
if (this.dbType === 'sqlserver') {
|
||||||
SELECT ID, MaterialCode, ManagerName
|
const sql = `
|
||||||
FROM ${MATERIALS_TO_BE_DELETED_CONFIG.TABLE_NAME_MYSQL}
|
SELECT ID, MaterialCode, ManagerName
|
||||||
WHERE MaterialCode = ?
|
FROM ${tableName}
|
||||||
`
|
WHERE MaterialCode = @materialCode
|
||||||
|
`
|
||||||
|
|
||||||
const result = await mysqlService.query(sql, [materialCode.trim()])
|
const result = await (dbService as SqlServerService).queryWithParams(sql, {
|
||||||
if (result.rows.length === 0) {
|
materialCode: { value: code, type: sql.NVarChar }
|
||||||
return null
|
})
|
||||||
}
|
|
||||||
|
|
||||||
const row = result.rows[0]
|
if (result.rows.length === 0) {
|
||||||
return {
|
return null
|
||||||
id: row.ID as number,
|
}
|
||||||
materialCode: row.MaterialCode as string,
|
|
||||||
managerName: row.ManagerName as string
|
const row = result.rows[0]
|
||||||
|
return {
|
||||||
|
id: row.ID as number,
|
||||||
|
materialCode: row.MaterialCode as string,
|
||||||
|
managerName: row.ManagerName as string
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const sql = `
|
||||||
|
SELECT ID, MaterialCode, ManagerName
|
||||||
|
FROM ${tableName}
|
||||||
|
WHERE MaterialCode = ?
|
||||||
|
`
|
||||||
|
|
||||||
|
const result = await (dbService as MySqlService).query(sql, [code])
|
||||||
|
|
||||||
|
if (result.rows.length === 0) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const row = result.rows[0]
|
||||||
|
return {
|
||||||
|
id: row.ID as number,
|
||||||
|
materialCode: row.MaterialCode as string,
|
||||||
|
managerName: row.ManagerName as string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[MaterialsToBeDeletedDAO] Get record by material code error:', error)
|
console.error('[MaterialsToBeDeletedDAO] Get record by material code error:', error)
|
||||||
@@ -299,15 +441,31 @@ export class MaterialsToBeDeletedDAO {
|
|||||||
*/
|
*/
|
||||||
async deleteByMaterialCode(materialCode: string): Promise<boolean> {
|
async deleteByMaterialCode(materialCode: string): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
|
const code = materialCode.trim()
|
||||||
|
|
||||||
const sql = `
|
if (this.dbType === 'sqlserver') {
|
||||||
DELETE FROM ${MATERIALS_TO_BE_DELETED_CONFIG.TABLE_NAME_MYSQL}
|
const sql = `
|
||||||
WHERE MaterialCode = ?
|
DELETE FROM ${tableName}
|
||||||
`
|
WHERE MaterialCode = @materialCode
|
||||||
|
`
|
||||||
|
|
||||||
const result = await mysqlService.query(sql, [materialCode.trim()])
|
const result = await (dbService as SqlServerService).queryWithParams(sql, {
|
||||||
return result.rowCount > 0
|
materialCode: { value: code, type: sql.NVarChar }
|
||||||
|
})
|
||||||
|
|
||||||
|
return result.rowCount > 0
|
||||||
|
} else {
|
||||||
|
const sql = `
|
||||||
|
DELETE FROM ${tableName}
|
||||||
|
WHERE MaterialCode = ?
|
||||||
|
`
|
||||||
|
|
||||||
|
const result = await (dbService as MySqlService).query(sql, [code])
|
||||||
|
|
||||||
|
return result.rowCount > 0
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[MaterialsToBeDeletedDAO] Delete by material code error:', error)
|
console.error('[MaterialsToBeDeletedDAO] Delete by material code error:', error)
|
||||||
return false
|
return false
|
||||||
@@ -321,15 +479,30 @@ export class MaterialsToBeDeletedDAO {
|
|||||||
*/
|
*/
|
||||||
async deleteByManager(managerName: string): Promise<number> {
|
async deleteByManager(managerName: string): Promise<number> {
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
|
|
||||||
const sql = `
|
if (this.dbType === 'sqlserver') {
|
||||||
DELETE FROM ${MATERIALS_TO_BE_DELETED_CONFIG.TABLE_NAME_MYSQL}
|
const sql = `
|
||||||
WHERE ManagerName = ?
|
DELETE FROM ${tableName}
|
||||||
`
|
WHERE ManagerName = @managerName
|
||||||
|
`
|
||||||
|
|
||||||
const result = await mysqlService.query(sql, [managerName])
|
const result = await (dbService as SqlServerService).queryWithParams(sql, {
|
||||||
return result.rowCount
|
managerName: { value: managerName, type: sql.NVarChar }
|
||||||
|
})
|
||||||
|
|
||||||
|
return result.rowCount
|
||||||
|
} else {
|
||||||
|
const sql = `
|
||||||
|
DELETE FROM ${tableName}
|
||||||
|
WHERE ManagerName = ?
|
||||||
|
`
|
||||||
|
|
||||||
|
const result = await (dbService as MySqlService).query(sql, [managerName])
|
||||||
|
|
||||||
|
return result.rowCount
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[MaterialsToBeDeletedDAO] Delete by manager error:', error)
|
console.error('[MaterialsToBeDeletedDAO] Delete by manager error:', error)
|
||||||
return 0
|
return 0
|
||||||
@@ -342,11 +515,15 @@ export class MaterialsToBeDeletedDAO {
|
|||||||
*/
|
*/
|
||||||
async deleteAllMaterials(): Promise<number> {
|
async deleteAllMaterials(): Promise<number> {
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
|
|
||||||
const sql = `DELETE FROM ${MATERIALS_TO_BE_DELETED_CONFIG.TABLE_NAME_MYSQL}`
|
const sql = `DELETE FROM ${tableName}`
|
||||||
|
|
||||||
|
const result = this.dbType === 'sqlserver'
|
||||||
|
? await (dbService as SqlServerService).query(sql)
|
||||||
|
: await (dbService as MySqlService).query(sql)
|
||||||
|
|
||||||
const result = await mysqlService.query(sql)
|
|
||||||
return result.rowCount
|
return result.rowCount
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[MaterialsToBeDeletedDAO] Delete all materials error:', error)
|
console.error('[MaterialsToBeDeletedDAO] Delete all materials error:', error)
|
||||||
@@ -368,19 +545,38 @@ export class MaterialsToBeDeletedDAO {
|
|||||||
const batchSize = 1000
|
const batchSize = 1000
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
|
|
||||||
for (let i = 0; i < materialCodes.length; i += batchSize) {
|
for (let i = 0; i < materialCodes.length; i += batchSize) {
|
||||||
const batch = materialCodes.slice(i, i + batchSize)
|
const batch = materialCodes.slice(i, i + batchSize)
|
||||||
const placeholders = batch.map(() => '?').join(',')
|
|
||||||
|
|
||||||
const sql = `
|
if (this.dbType === 'sqlserver') {
|
||||||
DELETE FROM ${MATERIALS_TO_BE_DELETED_CONFIG.TABLE_NAME_MYSQL}
|
const placeholders = batch.map((_, idx) => `@p${idx}`).join(',')
|
||||||
WHERE MaterialCode IN (${placeholders})
|
const params: Record<string, { value: string; type: sql.ISqlType }> = {}
|
||||||
`
|
|
||||||
|
|
||||||
const result = await mysqlService.query(sql, batch)
|
batch.forEach((code, idx) => {
|
||||||
totalDeleted += result.rowCount
|
params[`p${idx}`] = { value: code.trim(), type: sql.NVarChar }
|
||||||
|
})
|
||||||
|
|
||||||
|
const sql = `
|
||||||
|
DELETE FROM ${tableName}
|
||||||
|
WHERE MaterialCode IN (${placeholders})
|
||||||
|
`
|
||||||
|
|
||||||
|
const result = await (dbService as SqlServerService).queryWithParams(sql, params)
|
||||||
|
totalDeleted += result.rowCount
|
||||||
|
} else {
|
||||||
|
const placeholders = batch.map(() => '?').join(',')
|
||||||
|
|
||||||
|
const sql = `
|
||||||
|
DELETE FROM ${tableName}
|
||||||
|
WHERE MaterialCode IN (${placeholders})
|
||||||
|
`
|
||||||
|
|
||||||
|
const result = await (dbService as MySqlService).query(sql, batch)
|
||||||
|
totalDeleted += result.rowCount
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[MaterialsToBeDeletedDAO] Delete by material codes error:', error)
|
console.error('[MaterialsToBeDeletedDAO] Delete by material codes error:', error)
|
||||||
@@ -398,16 +594,33 @@ export class MaterialsToBeDeletedDAO {
|
|||||||
*/
|
*/
|
||||||
async materialExists(materialCode: string): Promise<boolean> {
|
async materialExists(materialCode: string): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
|
const code = materialCode.trim()
|
||||||
|
|
||||||
const sql = `
|
if (this.dbType === 'sqlserver') {
|
||||||
SELECT COUNT(*) as count
|
const sql = `
|
||||||
FROM ${MATERIALS_TO_BE_DELETED_CONFIG.TABLE_NAME_MYSQL}
|
SELECT COUNT(*) as count
|
||||||
WHERE MaterialCode = ?
|
FROM ${tableName}
|
||||||
`
|
WHERE MaterialCode = @materialCode
|
||||||
|
`
|
||||||
|
|
||||||
const result = await mysqlService.query(sql, [materialCode.trim()])
|
const result = await (dbService as SqlServerService).queryWithParams(sql, {
|
||||||
return result.rows.length > 0 && (result.rows[0].count as number) > 0
|
materialCode: { value: code, type: sql.NVarChar }
|
||||||
|
})
|
||||||
|
|
||||||
|
return result.rows.length > 0 && (result.rows[0].count as number) > 0
|
||||||
|
} else {
|
||||||
|
const sql = `
|
||||||
|
SELECT COUNT(*) as count
|
||||||
|
FROM ${tableName}
|
||||||
|
WHERE MaterialCode = ?
|
||||||
|
`
|
||||||
|
|
||||||
|
const result = await (dbService as MySqlService).query(sql, [code])
|
||||||
|
|
||||||
|
return result.rows.length > 0 && (result.rows[0].count as number) > 0
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[MaterialsToBeDeletedDAO] Material exists error:', error)
|
console.error('[MaterialsToBeDeletedDAO] Material exists error:', error)
|
||||||
return false
|
return false
|
||||||
@@ -420,11 +633,15 @@ export class MaterialsToBeDeletedDAO {
|
|||||||
*/
|
*/
|
||||||
async countAll(): Promise<number> {
|
async countAll(): Promise<number> {
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
|
|
||||||
const sql = `SELECT COUNT(*) as count FROM ${MATERIALS_TO_BE_DELETED_CONFIG.TABLE_NAME_MYSQL}`
|
const sql = `SELECT COUNT(*) as count FROM ${tableName}`
|
||||||
|
|
||||||
|
const result = this.dbType === 'sqlserver'
|
||||||
|
? await (dbService as SqlServerService).query(sql)
|
||||||
|
: await (dbService as MySqlService).query(sql)
|
||||||
|
|
||||||
const result = await mysqlService.query(sql)
|
|
||||||
return result.rows.length > 0 ? (result.rows[0].count as number) : 0
|
return result.rows.length > 0 ? (result.rows[0].count as number) : 0
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[MaterialsToBeDeletedDAO] Count all error:', error)
|
console.error('[MaterialsToBeDeletedDAO] Count all error:', error)
|
||||||
@@ -439,16 +656,32 @@ export class MaterialsToBeDeletedDAO {
|
|||||||
*/
|
*/
|
||||||
async countByManager(managerName: string): Promise<number> {
|
async countByManager(managerName: string): Promise<number> {
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
|
|
||||||
const sql = `
|
if (this.dbType === 'sqlserver') {
|
||||||
SELECT COUNT(*) as count
|
const sql = `
|
||||||
FROM ${MATERIALS_TO_BE_DELETED_CONFIG.TABLE_NAME_MYSQL}
|
SELECT COUNT(*) as count
|
||||||
WHERE ManagerName = ?
|
FROM ${tableName}
|
||||||
`
|
WHERE ManagerName = @managerName
|
||||||
|
`
|
||||||
|
|
||||||
const result = await mysqlService.query(sql, [managerName])
|
const result = await (dbService as SqlServerService).queryWithParams(sql, {
|
||||||
return result.rows.length > 0 ? (result.rows[0].count as number) : 0
|
managerName: { value: managerName, type: sql.NVarChar }
|
||||||
|
})
|
||||||
|
|
||||||
|
return result.rows.length > 0 ? (result.rows[0].count as number) : 0
|
||||||
|
} else {
|
||||||
|
const sql = `
|
||||||
|
SELECT COUNT(*) as count
|
||||||
|
FROM ${tableName}
|
||||||
|
WHERE ManagerName = ?
|
||||||
|
`
|
||||||
|
|
||||||
|
const result = await (dbService as MySqlService).query(sql, [managerName])
|
||||||
|
|
||||||
|
return result.rows.length > 0 ? (result.rows[0].count as number) : 0
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[MaterialsToBeDeletedDAO] Count by manager error:', error)
|
console.error('[MaterialsToBeDeletedDAO] Count by manager error:', error)
|
||||||
return 0
|
return 0
|
||||||
@@ -461,30 +694,37 @@ export class MaterialsToBeDeletedDAO {
|
|||||||
*/
|
*/
|
||||||
async getStatistics(): Promise<MaterialStats> {
|
async getStatistics(): Promise<MaterialStats> {
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
|
|
||||||
// Get total and unique managers
|
// Get total and unique managers
|
||||||
const statsSql = `
|
const statsSql = `
|
||||||
SELECT
|
SELECT
|
||||||
COUNT(*) as totalMaterials,
|
COUNT(*) as totalMaterials,
|
||||||
COUNT(DISTINCT ManagerName) as uniqueManagers
|
COUNT(DISTINCT ManagerName) as uniqueManagers
|
||||||
FROM ${MATERIALS_TO_BE_DELETED_CONFIG.TABLE_NAME_MYSQL}
|
FROM ${tableName}
|
||||||
WHERE MaterialCode IS NOT NULL
|
WHERE MaterialCode IS NOT NULL
|
||||||
`
|
`
|
||||||
|
|
||||||
const statsResult = await mysqlService.query(statsSql)
|
const statsResult = this.dbType === 'sqlserver'
|
||||||
|
? await (dbService as SqlServerService).query(statsSql)
|
||||||
|
: await (dbService as MySqlService).query(statsSql)
|
||||||
|
|
||||||
const stats = statsResult.rows[0] || {}
|
const stats = statsResult.rows[0] || {}
|
||||||
|
|
||||||
// Get materials per manager
|
// Get materials per manager
|
||||||
const managerSql = `
|
const managerSql = `
|
||||||
SELECT ManagerName, COUNT(*) as count
|
SELECT ManagerName, COUNT(*) as count
|
||||||
FROM ${MATERIALS_TO_BE_DELETED_CONFIG.TABLE_NAME_MYSQL}
|
FROM ${tableName}
|
||||||
WHERE ManagerName IS NOT NULL
|
WHERE ManagerName IS NOT NULL
|
||||||
GROUP BY ManagerName
|
GROUP BY ManagerName
|
||||||
ORDER BY count DESC
|
ORDER BY count DESC
|
||||||
`
|
`
|
||||||
|
|
||||||
const managerResult = await mysqlService.query(managerSql)
|
const managerResult = this.dbType === 'sqlserver'
|
||||||
|
? await (dbService as SqlServerService).query(managerSql)
|
||||||
|
: await (dbService as MySqlService).query(managerSql)
|
||||||
|
|
||||||
const materialsPerManager = managerResult.rows.map(row => ({
|
const materialsPerManager = managerResult.rows.map(row => ({
|
||||||
[row.ManagerName as string]: row.count as number
|
[row.ManagerName as string]: row.count as number
|
||||||
}))
|
}))
|
||||||
@@ -512,5 +752,9 @@ export class MaterialsToBeDeletedDAO {
|
|||||||
await this.mysqlService.disconnect()
|
await this.mysqlService.disconnect()
|
||||||
this.mysqlService = null
|
this.mysqlService = null
|
||||||
}
|
}
|
||||||
|
if (this.sqlServerService) {
|
||||||
|
await this.sqlServerService.disconnect()
|
||||||
|
this.sqlServerService = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,8 +98,9 @@ export class SqlServerService {
|
|||||||
const result = await request.query(sqlString)
|
const result = await request.query(sqlString)
|
||||||
|
|
||||||
// Convert recordset to array of objects
|
// Convert recordset to array of objects
|
||||||
const columns = result.recordset.columns?.map((col) => col.name) || []
|
|
||||||
const rows = result.recordset as Record<string, unknown>[]
|
const rows = result.recordset as Record<string, unknown>[]
|
||||||
|
// Extract column names from the first row if available
|
||||||
|
const columns = rows.length > 0 ? Object.keys(rows[0]) : []
|
||||||
|
|
||||||
return {
|
return {
|
||||||
rows,
|
rows,
|
||||||
@@ -137,8 +138,9 @@ export class SqlServerService {
|
|||||||
const result = await request.query(sqlString)
|
const result = await request.query(sqlString)
|
||||||
|
|
||||||
// Convert recordset to array of objects
|
// Convert recordset to array of objects
|
||||||
const columns = result.recordset.columns?.map((col) => col.name) || []
|
|
||||||
const rows = result.recordset as Record<string, unknown>[]
|
const rows = result.recordset as Record<string, unknown>[]
|
||||||
|
// Extract column names from the first row if available
|
||||||
|
const columns = rows.length > 0 ? Object.keys(rows[0]) : []
|
||||||
|
|
||||||
return {
|
return {
|
||||||
rows,
|
rows,
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { MySqlService } from '../database/mysql'
|
import { MySqlService } from '../database/mysql'
|
||||||
|
import { SqlServerService } from '../database/sql-server'
|
||||||
|
import sql from 'mssql'
|
||||||
import type { UserInfo } from '../../types/user.types'
|
import type { UserInfo } from '../../types/user.types'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,25 +37,69 @@ export const BIP_USERS_CONFIG = {
|
|||||||
*/
|
*/
|
||||||
export class BIPUsersDAO {
|
export class BIPUsersDAO {
|
||||||
private mysqlService: MySqlService | null = null
|
private mysqlService: MySqlService | null = null
|
||||||
|
private sqlServerService: SqlServerService | null = null
|
||||||
|
private dbType: 'mysql' | 'sqlserver' = 'mysql'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get MySQL service instance
|
* Constructor - determine database type from environment
|
||||||
*/
|
*/
|
||||||
private async getMySqlService(): Promise<MySqlService> {
|
constructor() {
|
||||||
if (this.mysqlService && this.mysqlService.isConnected()) {
|
const dbType = process.env.DB_TYPE?.toLowerCase()
|
||||||
|
if (dbType === 'sqlserver' || dbType === 'mssql') {
|
||||||
|
this.dbType = 'sqlserver'
|
||||||
|
} else {
|
||||||
|
this.dbType = 'mysql'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the appropriate table name based on database type
|
||||||
|
*/
|
||||||
|
private getTableName(): string {
|
||||||
|
return this.dbType === 'sqlserver'
|
||||||
|
? BIP_USERS_CONFIG.TABLE_NAME_SQLSERVER
|
||||||
|
: BIP_USERS_CONFIG.TABLE_NAME_MYSQL
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get database service instance (MySQL or SQL Server)
|
||||||
|
*/
|
||||||
|
private async getDatabaseService(): Promise<MySqlService | SqlServerService> {
|
||||||
|
if (this.dbType === 'sqlserver') {
|
||||||
|
if (this.sqlServerService && this.sqlServerService.isConnected()) {
|
||||||
|
return this.sqlServerService
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sqlServerService = new SqlServerService({
|
||||||
|
server: process.env.DB_SERVER || 'localhost',
|
||||||
|
port: parseInt(process.env.DB_SQLSERVER_PORT || '1433', 10),
|
||||||
|
user: process.env.DB_USERNAME || 'sa',
|
||||||
|
password: process.env.DB_PASSWORD || '',
|
||||||
|
database: process.env.DB_NAME || '',
|
||||||
|
options: {
|
||||||
|
encrypt: process.env.DB_TRUST_SERVER_CERTIFICATE === 'yes',
|
||||||
|
trustServerCertificate: process.env.DB_TRUST_SERVER_CERTIFICATE === 'yes'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
await this.sqlServerService.connect()
|
||||||
|
return this.sqlServerService
|
||||||
|
} else {
|
||||||
|
if (this.mysqlService && this.mysqlService.isConnected()) {
|
||||||
|
return this.mysqlService
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mysqlService = new MySqlService({
|
||||||
|
host: process.env.DB_MYSQL_HOST || 'localhost',
|
||||||
|
port: parseInt(process.env.DB_MYSQL_PORT || '3306', 10),
|
||||||
|
user: process.env.DB_USERNAME || 'root',
|
||||||
|
password: process.env.DB_PASSWORD || '',
|
||||||
|
database: process.env.DB_NAME || ''
|
||||||
|
})
|
||||||
|
|
||||||
|
await this.mysqlService.connect()
|
||||||
return this.mysqlService
|
return this.mysqlService
|
||||||
}
|
}
|
||||||
|
|
||||||
this.mysqlService = new MySqlService({
|
|
||||||
host: process.env.DB_MYSQL_HOST || 'localhost',
|
|
||||||
port: parseInt(process.env.DB_MYSQL_PORT || '3306', 10),
|
|
||||||
user: process.env.DB_USERNAME || 'root',
|
|
||||||
password: process.env.DB_PASSWORD || '',
|
|
||||||
database: process.env.DB_NAME || ''
|
|
||||||
})
|
|
||||||
|
|
||||||
await this.mysqlService.connect()
|
|
||||||
return this.mysqlService
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -64,25 +110,49 @@ export class BIPUsersDAO {
|
|||||||
*/
|
*/
|
||||||
async authenticate(username: string, password: string): Promise<UserInfo | null> {
|
async authenticate(username: string, password: string): Promise<UserInfo | null> {
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
|
|
||||||
const sql = `
|
if (this.dbType === 'sqlserver') {
|
||||||
SELECT ID, UserName, UserType
|
const sql = `
|
||||||
FROM ${BIP_USERS_CONFIG.TABLE_NAME_MYSQL}
|
SELECT ID, UserName, UserType
|
||||||
WHERE UserName = ? AND Password = ?
|
FROM ${tableName}
|
||||||
`
|
WHERE UserName = @username AND Password = @password
|
||||||
|
`
|
||||||
|
|
||||||
const result = await mysqlService.query(sql, [username, password])
|
const result = await (dbService as SqlServerService).queryWithParams(sql, {
|
||||||
|
username: { value: username, type: sql.NVarChar },
|
||||||
|
password: { value: password, type: sql.NVarChar }
|
||||||
|
})
|
||||||
|
|
||||||
if (result.rows.length > 0) {
|
if (result.rows.length > 0) {
|
||||||
const row = result.rows[0]
|
const row = result.rows[0]
|
||||||
return {
|
return {
|
||||||
id: row.ID as number,
|
id: row.ID as number,
|
||||||
username: row.UserName as string,
|
username: row.UserName as string,
|
||||||
userType: row.UserType as 'Admin' | 'User' | 'Guest'
|
userType: row.UserType as 'Admin' | 'User' | 'Guest'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return null
|
||||||
|
} else {
|
||||||
|
const sql = `
|
||||||
|
SELECT ID, UserName, UserType
|
||||||
|
FROM ${tableName}
|
||||||
|
WHERE UserName = ? AND Password = ?
|
||||||
|
`
|
||||||
|
|
||||||
|
const result = await (dbService as MySqlService).query(sql, [username, password])
|
||||||
|
|
||||||
|
if (result.rows.length > 0) {
|
||||||
|
const row = result.rows[0]
|
||||||
|
return {
|
||||||
|
id: row.ID as number,
|
||||||
|
username: row.UserName as string,
|
||||||
|
userType: row.UserType as 'Admin' | 'User' | 'Guest'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
return null
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[BIPUsersDAO] Authenticate error:', error)
|
console.error('[BIPUsersDAO] Authenticate error:', error)
|
||||||
return null
|
return null
|
||||||
@@ -96,25 +166,48 @@ export class BIPUsersDAO {
|
|||||||
*/
|
*/
|
||||||
async authenticateByComputerName(computerName: string): Promise<UserInfo | null> {
|
async authenticateByComputerName(computerName: string): Promise<UserInfo | null> {
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
|
|
||||||
const sql = `
|
if (this.dbType === 'sqlserver') {
|
||||||
SELECT ID, UserName, UserType
|
const sql = `
|
||||||
FROM ${BIP_USERS_CONFIG.TABLE_NAME_MYSQL}
|
SELECT ID, UserName, UserType
|
||||||
WHERE ComputerNmae = ?
|
FROM ${tableName}
|
||||||
`
|
WHERE ComputerNmae = @computerName
|
||||||
|
`
|
||||||
|
|
||||||
const result = await mysqlService.query(sql, [computerName])
|
const result = await (dbService as SqlServerService).queryWithParams(sql, {
|
||||||
|
computerName: { value: computerName, type: sql.NVarChar }
|
||||||
|
})
|
||||||
|
|
||||||
if (result.rows.length > 0) {
|
if (result.rows.length > 0) {
|
||||||
const row = result.rows[0]
|
const row = result.rows[0]
|
||||||
return {
|
return {
|
||||||
id: row.ID as number,
|
id: row.ID as number,
|
||||||
username: row.UserName as string,
|
username: row.UserName as string,
|
||||||
userType: row.UserType as 'Admin' | 'User' | 'Guest'
|
userType: row.UserType as 'Admin' | 'User' | 'Guest'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return null
|
||||||
|
} else {
|
||||||
|
const sql = `
|
||||||
|
SELECT ID, UserName, UserType
|
||||||
|
FROM ${tableName}
|
||||||
|
WHERE ComputerNmae = ?
|
||||||
|
`
|
||||||
|
|
||||||
|
const result = await (dbService as MySqlService).query(sql, [computerName])
|
||||||
|
|
||||||
|
if (result.rows.length > 0) {
|
||||||
|
const row = result.rows[0]
|
||||||
|
return {
|
||||||
|
id: row.ID as number,
|
||||||
|
username: row.UserName as string,
|
||||||
|
userType: row.UserType as 'Admin' | 'User' | 'Guest'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
return null
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[BIPUsersDAO] Authenticate by computer name error:', error)
|
console.error('[BIPUsersDAO] Authenticate by computer name error:', error)
|
||||||
return null
|
return null
|
||||||
@@ -127,15 +220,18 @@ export class BIPUsersDAO {
|
|||||||
*/
|
*/
|
||||||
async getAllUsers(): Promise<UserInfo[]> {
|
async getAllUsers(): Promise<UserInfo[]> {
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
|
|
||||||
const sql = `
|
const sql = `
|
||||||
SELECT ID, UserName, UserType, CreateTime
|
SELECT ID, UserName, UserType, CreateTime
|
||||||
FROM ${BIP_USERS_CONFIG.TABLE_NAME_MYSQL}
|
FROM ${tableName}
|
||||||
ORDER BY UserName
|
ORDER BY UserName
|
||||||
`
|
`
|
||||||
|
|
||||||
const result = await mysqlService.query(sql)
|
const result = this.dbType === 'sqlserver'
|
||||||
|
? await (dbService as SqlServerService).query(sql)
|
||||||
|
: await (dbService as MySqlService).query(sql)
|
||||||
|
|
||||||
return result.rows.map(row => ({
|
return result.rows.map(row => ({
|
||||||
id: row.ID as number,
|
id: row.ID as number,
|
||||||
@@ -164,29 +260,63 @@ export class BIPUsersDAO {
|
|||||||
computerName: string = ''
|
computerName: string = ''
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
|
|
||||||
let sql: string
|
if (this.dbType === 'sqlserver') {
|
||||||
let params: any[]
|
let sql: string
|
||||||
|
let params: Record<string, { value: unknown; type?: sql.ISqlType }>
|
||||||
|
|
||||||
if (computerName) {
|
if (computerName) {
|
||||||
sql = `
|
sql = `
|
||||||
INSERT INTO ${BIP_USERS_CONFIG.TABLE_NAME_MYSQL}
|
INSERT INTO ${tableName}
|
||||||
(UserName, Password, UserType, ComputerNmae)
|
(UserName, Password, UserType, ComputerNmae)
|
||||||
VALUES (?, ?, ?, ?)
|
VALUES (@username, @password, @userType, @computerName)
|
||||||
`
|
`
|
||||||
params = [username, password, userType, computerName]
|
params = {
|
||||||
|
username: { value: username, type: sql.NVarChar },
|
||||||
|
password: { value: password, type: sql.NVarChar },
|
||||||
|
userType: { value: userType, type: sql.NVarChar },
|
||||||
|
computerName: { value: computerName, type: sql.NVarChar }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sql = `
|
||||||
|
INSERT INTO ${tableName}
|
||||||
|
(UserName, Password, UserType)
|
||||||
|
VALUES (@username, @password, @userType)
|
||||||
|
`
|
||||||
|
params = {
|
||||||
|
username: { value: username, type: sql.NVarChar },
|
||||||
|
password: { value: password, type: sql.NVarChar },
|
||||||
|
userType: { value: userType, type: sql.NVarChar }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await (dbService as SqlServerService).queryWithParams(sql, params)
|
||||||
|
return true
|
||||||
} else {
|
} else {
|
||||||
sql = `
|
let sql: string
|
||||||
INSERT INTO ${BIP_USERS_CONFIG.TABLE_NAME_MYSQL}
|
let params: any[]
|
||||||
(UserName, Password, UserType)
|
|
||||||
VALUES (?, ?, ?)
|
|
||||||
`
|
|
||||||
params = [username, password, userType]
|
|
||||||
}
|
|
||||||
|
|
||||||
await mysqlService.query(sql, params)
|
if (computerName) {
|
||||||
return true
|
sql = `
|
||||||
|
INSERT INTO ${tableName}
|
||||||
|
(UserName, Password, UserType, ComputerNmae)
|
||||||
|
VALUES (?, ?, ?, ?)
|
||||||
|
`
|
||||||
|
params = [username, password, userType, computerName]
|
||||||
|
} else {
|
||||||
|
sql = `
|
||||||
|
INSERT INTO ${tableName}
|
||||||
|
(UserName, Password, UserType)
|
||||||
|
VALUES (?, ?, ?)
|
||||||
|
`
|
||||||
|
params = [username, password, userType]
|
||||||
|
}
|
||||||
|
|
||||||
|
await (dbService as MySqlService).query(sql, params)
|
||||||
|
return true
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[BIPUsersDAO] Create user error:', error)
|
console.error('[BIPUsersDAO] Create user error:', error)
|
||||||
return false
|
return false
|
||||||
@@ -201,16 +331,31 @@ export class BIPUsersDAO {
|
|||||||
*/
|
*/
|
||||||
async updateUserType(username: string, userType: string): Promise<boolean> {
|
async updateUserType(username: string, userType: string): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
|
|
||||||
const sql = `
|
if (this.dbType === 'sqlserver') {
|
||||||
UPDATE ${BIP_USERS_CONFIG.TABLE_NAME_MYSQL}
|
const sql = `
|
||||||
SET UserType = ?
|
UPDATE ${tableName}
|
||||||
WHERE UserName = ?
|
SET UserType = @userType
|
||||||
`
|
WHERE UserName = @username
|
||||||
|
`
|
||||||
|
|
||||||
await mysqlService.query(sql, [userType, username])
|
await (dbService as SqlServerService).queryWithParams(sql, {
|
||||||
return true
|
username: { value: username, type: sql.NVarChar },
|
||||||
|
userType: { value: userType, type: sql.NVarChar }
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
const sql = `
|
||||||
|
UPDATE ${tableName}
|
||||||
|
SET UserType = ?
|
||||||
|
WHERE UserName = ?
|
||||||
|
`
|
||||||
|
|
||||||
|
await (dbService as MySqlService).query(sql, [userType, username])
|
||||||
|
return true
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[BIPUsersDAO] Update user type error:', error)
|
console.error('[BIPUsersDAO] Update user type error:', error)
|
||||||
return false
|
return false
|
||||||
@@ -225,16 +370,31 @@ export class BIPUsersDAO {
|
|||||||
*/
|
*/
|
||||||
async updatePassword(username: string, newPassword: string): Promise<boolean> {
|
async updatePassword(username: string, newPassword: string): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
|
|
||||||
const sql = `
|
if (this.dbType === 'sqlserver') {
|
||||||
UPDATE ${BIP_USERS_CONFIG.TABLE_NAME_MYSQL}
|
const sql = `
|
||||||
SET Password = ?
|
UPDATE ${tableName}
|
||||||
WHERE UserName = ?
|
SET Password = @newPassword
|
||||||
`
|
WHERE UserName = @username
|
||||||
|
`
|
||||||
|
|
||||||
await mysqlService.query(sql, [newPassword, username])
|
await (dbService as SqlServerService).queryWithParams(sql, {
|
||||||
return true
|
username: { value: username, type: sql.NVarChar },
|
||||||
|
newPassword: { value: newPassword, type: sql.NVarChar }
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
const sql = `
|
||||||
|
UPDATE ${tableName}
|
||||||
|
SET Password = ?
|
||||||
|
WHERE UserName = ?
|
||||||
|
`
|
||||||
|
|
||||||
|
await (dbService as MySqlService).query(sql, [newPassword, username])
|
||||||
|
return true
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[BIPUsersDAO] Update password error:', error)
|
console.error('[BIPUsersDAO] Update password error:', error)
|
||||||
return false
|
return false
|
||||||
@@ -248,15 +408,28 @@ export class BIPUsersDAO {
|
|||||||
*/
|
*/
|
||||||
async deleteUser(username: string): Promise<boolean> {
|
async deleteUser(username: string): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
|
|
||||||
const sql = `
|
if (this.dbType === 'sqlserver') {
|
||||||
DELETE FROM ${BIP_USERS_CONFIG.TABLE_NAME_MYSQL}
|
const sql = `
|
||||||
WHERE UserName = ?
|
DELETE FROM ${tableName}
|
||||||
`
|
WHERE UserName = @username
|
||||||
|
`
|
||||||
|
|
||||||
await mysqlService.query(sql, [username])
|
await (dbService as SqlServerService).queryWithParams(sql, {
|
||||||
return true
|
username: { value: username, type: sql.NVarChar }
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
const sql = `
|
||||||
|
DELETE FROM ${tableName}
|
||||||
|
WHERE UserName = ?
|
||||||
|
`
|
||||||
|
|
||||||
|
await (dbService as MySqlService).query(sql, [username])
|
||||||
|
return true
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[BIPUsersDAO] Delete user error:', error)
|
console.error('[BIPUsersDAO] Delete user error:', error)
|
||||||
return false
|
return false
|
||||||
@@ -270,16 +443,30 @@ export class BIPUsersDAO {
|
|||||||
*/
|
*/
|
||||||
async userExists(username: string): Promise<boolean> {
|
async userExists(username: string): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
const mysqlService = await this.getMySqlService()
|
const dbService = await this.getDatabaseService()
|
||||||
|
const tableName = this.getTableName()
|
||||||
|
|
||||||
const sql = `
|
if (this.dbType === 'sqlserver') {
|
||||||
SELECT COUNT(*) as count
|
const sql = `
|
||||||
FROM ${BIP_USERS_CONFIG.TABLE_NAME_MYSQL}
|
SELECT COUNT(*) as count
|
||||||
WHERE UserName = ?
|
FROM ${tableName}
|
||||||
`
|
WHERE UserName = @username
|
||||||
|
`
|
||||||
|
|
||||||
const result = await mysqlService.query(sql, [username])
|
const result = await (dbService as SqlServerService).queryWithParams(sql, {
|
||||||
return result.rows.length > 0 && (result.rows[0].count as number) > 0
|
username: { value: username, type: sql.NVarChar }
|
||||||
|
})
|
||||||
|
return result.rows.length > 0 && (result.rows[0].count as number) > 0
|
||||||
|
} else {
|
||||||
|
const sql = `
|
||||||
|
SELECT COUNT(*) as count
|
||||||
|
FROM ${tableName}
|
||||||
|
WHERE UserName = ?
|
||||||
|
`
|
||||||
|
|
||||||
|
const result = await (dbService as MySqlService).query(sql, [username])
|
||||||
|
return result.rows.length > 0 && (result.rows[0].count as number) > 0
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[BIPUsersDAO] User exists error:', error)
|
console.error('[BIPUsersDAO] User exists error:', error)
|
||||||
return false
|
return false
|
||||||
@@ -294,5 +481,9 @@ export class BIPUsersDAO {
|
|||||||
await this.mysqlService.disconnect()
|
await this.mysqlService.disconnect()
|
||||||
this.mysqlService = null
|
this.mysqlService = null
|
||||||
}
|
}
|
||||||
|
if (this.sqlServerService) {
|
||||||
|
await this.sqlServerService.disconnect()
|
||||||
|
this.sqlServerService = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user