Merge branch 'develop'
This commit is contained in:
commit
8a3a9e7eb3
42 changed files with 1295 additions and 226 deletions
|
|
@ -24,6 +24,7 @@
|
|||
"@types/cors": "^2.8.17",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/morgan": "^1.9.9",
|
||||
"@types/multer": "^1.4.12",
|
||||
"@types/node": "^20.17.10",
|
||||
"@types/nodemailer": "^6.4.17",
|
||||
"nodemon": "^3.1.9",
|
||||
|
|
@ -46,12 +47,14 @@
|
|||
"dayjs-plugin-utc": "^0.1.2",
|
||||
"docx-templates": "^4.13.0",
|
||||
"dotenv": "^16.4.7",
|
||||
"exceljs": "^4.4.0",
|
||||
"express": "^4.21.2",
|
||||
"fast-jwt": "^5.0.5",
|
||||
"json-2-csv": "^5.5.8",
|
||||
"kysely": "^0.27.5",
|
||||
"minio": "^8.0.2",
|
||||
"morgan": "^1.10.0",
|
||||
"multer": "^1.4.5-lts.2",
|
||||
"nodemailer": "^6.10.0",
|
||||
"prisma-extension-kysely": "^3.0.0",
|
||||
"promise.any": "^2.0.6",
|
||||
|
|
|
|||
254
pnpm-lock.yaml
generated
254
pnpm-lock.yaml
generated
|
|
@ -44,6 +44,9 @@ importers:
|
|||
dotenv:
|
||||
specifier: ^16.4.7
|
||||
version: 16.4.7
|
||||
exceljs:
|
||||
specifier: ^4.4.0
|
||||
version: 4.4.0
|
||||
express:
|
||||
specifier: ^4.21.2
|
||||
version: 4.21.2
|
||||
|
|
@ -62,6 +65,9 @@ importers:
|
|||
morgan:
|
||||
specifier: ^1.10.0
|
||||
version: 1.10.0
|
||||
multer:
|
||||
specifier: ^1.4.5-lts.2
|
||||
version: 1.4.5-lts.2
|
||||
nodemailer:
|
||||
specifier: ^6.10.0
|
||||
version: 6.10.0
|
||||
|
|
@ -99,6 +105,9 @@ importers:
|
|||
'@types/morgan':
|
||||
specifier: ^1.9.9
|
||||
version: 1.9.9
|
||||
'@types/multer':
|
||||
specifier: ^1.4.12
|
||||
version: 1.4.12
|
||||
'@types/node':
|
||||
specifier: ^20.17.10
|
||||
version: 20.17.10
|
||||
|
|
@ -177,6 +186,12 @@ packages:
|
|||
resolution: {integrity: sha512-jasKNQeOb1vNf9aEYg+8zXmetaFjApDTSCC4QTl6aTixvyiRiSLcCiB8P6Q0lY9JIII/BhqNl8WbpFnsKitntw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@fast-csv/format@4.3.5':
|
||||
resolution: {integrity: sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A==}
|
||||
|
||||
'@fast-csv/parse@4.3.6':
|
||||
resolution: {integrity: sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA==}
|
||||
|
||||
'@fast-csv/parse@5.0.2':
|
||||
resolution: {integrity: sha512-gMu1Btmm99TP+wc0tZnlH30E/F1Gw1Tah3oMDBHNPe9W8S68ixVHjt89Wg5lh7d9RuQMtwN+sGl5kxR891+fzw==}
|
||||
|
||||
|
|
@ -492,6 +507,9 @@ packages:
|
|||
'@types/multer@1.4.12':
|
||||
resolution: {integrity: sha512-pQ2hoqvXiJt2FP9WQVLPRO+AmiIm/ZYkavPlIQnx282u4ZrVdztx0pkh3jjpQt0Kz+YI0YhSG264y08UJKoUQg==}
|
||||
|
||||
'@types/node@14.18.63':
|
||||
resolution: {integrity: sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==}
|
||||
|
||||
'@types/node@20.17.10':
|
||||
resolution: {integrity: sha512-/jrvh5h6NXhEauFFexRin69nA0uHJ5gwk4iDivp/DeoEua3uwCUto6PC86IpRITBOs4+6i2I56K5x5b6WYGXHA==}
|
||||
|
||||
|
|
@ -587,6 +605,9 @@ packages:
|
|||
resolution: {integrity: sha512-v/ShMp57iBnBp4lDgV8Jx3d3Q5/Hac25FWmQ98eMahUiHPXcvwIMKJD0hBIgclm/FCG+LwPkAKtkRO1O/W0YGg==}
|
||||
hasBin: true
|
||||
|
||||
append-field@1.0.0:
|
||||
resolution: {integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==}
|
||||
|
||||
archiver-utils@2.1.0:
|
||||
resolution: {integrity: sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==}
|
||||
engines: {node: '>= 6'}
|
||||
|
|
@ -682,6 +703,10 @@ packages:
|
|||
resolution: {integrity: sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
big-integer@1.6.52:
|
||||
resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==}
|
||||
engines: {node: '>=0.6'}
|
||||
|
||||
binary-extensions@2.3.0:
|
||||
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
|
||||
engines: {node: '>=8'}
|
||||
|
|
@ -689,12 +714,18 @@ packages:
|
|||
binary-search@1.3.6:
|
||||
resolution: {integrity: sha512-nbE1WxOTTrUWIfsfZ4aHGYu5DOuNkbxGokjV6Z2kxfJK3uaAb8zNK1muzOeipoLHZjInT4Br88BHpzevc681xA==}
|
||||
|
||||
binary@0.3.0:
|
||||
resolution: {integrity: sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==}
|
||||
|
||||
bl@4.1.0:
|
||||
resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
|
||||
|
||||
block-stream2@2.1.0:
|
||||
resolution: {integrity: sha512-suhjmLI57Ewpmq00qaygS8UgEq2ly2PCItenIyhMqVjo4t4pGzqMvfgJuX8iWTeSDdfSSqS6j38fL4ToNL7Pfg==}
|
||||
|
||||
bluebird@3.4.7:
|
||||
resolution: {integrity: sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==}
|
||||
|
||||
bn.js@4.12.1:
|
||||
resolution: {integrity: sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==}
|
||||
|
||||
|
|
@ -725,9 +756,24 @@ packages:
|
|||
resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==}
|
||||
engines: {node: '>=8.0.0'}
|
||||
|
||||
buffer-from@1.1.2:
|
||||
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
|
||||
|
||||
buffer-indexof-polyfill@1.0.2:
|
||||
resolution: {integrity: sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==}
|
||||
engines: {node: '>=0.10'}
|
||||
|
||||
buffer@5.7.1:
|
||||
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
|
||||
|
||||
buffers@0.1.1:
|
||||
resolution: {integrity: sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==}
|
||||
engines: {node: '>=0.2.0'}
|
||||
|
||||
busboy@1.6.0:
|
||||
resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
|
||||
engines: {node: '>=10.16.0'}
|
||||
|
||||
bytes@3.1.2:
|
||||
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
|
@ -744,6 +790,9 @@ packages:
|
|||
resolution: {integrity: sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
chainsaw@0.1.0:
|
||||
resolution: {integrity: sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==}
|
||||
|
||||
chalk-template@0.4.0:
|
||||
resolution: {integrity: sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==}
|
||||
engines: {node: '>=12'}
|
||||
|
|
@ -821,6 +870,10 @@ packages:
|
|||
concat-map@0.0.1:
|
||||
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
||||
|
||||
concat-stream@1.6.2:
|
||||
resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==}
|
||||
engines: {'0': node >= 0.8}
|
||||
|
||||
console-log-level@1.4.1:
|
||||
resolution: {integrity: sha512-VZzbIORbP+PPcN/gg3DXClTLPLg5Slwd5fL2MIc+o1qZ4BXBvWyc6QxPk6T/Mkr6IVjRpoAGf32XxP3ZWMVRcQ==}
|
||||
|
||||
|
|
@ -985,6 +1038,9 @@ packages:
|
|||
resolution: {integrity: sha512-9+Sj30DIu+4KvHqMfLUGLFYL2PkURSYMVXJyXe92nFRvlYq5hBjLEhblKB+vkd/WVlUYMWigiY07T91Fkk0+4A==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
duplexer2@0.1.4:
|
||||
resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==}
|
||||
|
||||
eastasianwidth@0.2.0:
|
||||
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
|
||||
|
||||
|
|
@ -1087,6 +1143,10 @@ packages:
|
|||
eventemitter3@5.0.1:
|
||||
resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
|
||||
|
||||
exceljs@4.4.0:
|
||||
resolution: {integrity: sha512-XctvKaEMaj1Ii9oDOqbW/6e1gXknSY4g/aLCDicOXqBE4M0nRWkUu0PTp++UPNzoFY12BNHMfs/VadKIS6llvg==}
|
||||
engines: {node: '>=8.3.0'}
|
||||
|
||||
execa@5.1.1:
|
||||
resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
|
||||
engines: {node: '>=10'}
|
||||
|
|
@ -1095,6 +1155,10 @@ packages:
|
|||
resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==}
|
||||
engines: {node: '>= 0.10.0'}
|
||||
|
||||
fast-csv@4.3.6:
|
||||
resolution: {integrity: sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
|
||||
fast-glob@3.3.2:
|
||||
resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
|
||||
engines: {node: '>=8.6.0'}
|
||||
|
|
@ -1203,6 +1267,11 @@ packages:
|
|||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||
os: [darwin]
|
||||
|
||||
fstream@1.0.12:
|
||||
resolution: {integrity: sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==}
|
||||
engines: {node: '>=0.6'}
|
||||
deprecated: This package is no longer supported.
|
||||
|
||||
function-bind@1.1.2:
|
||||
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
|
||||
|
||||
|
|
@ -1623,6 +1692,9 @@ packages:
|
|||
lines-and-columns@1.2.4:
|
||||
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
|
||||
|
||||
listenercount@1.0.1:
|
||||
resolution: {integrity: sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==}
|
||||
|
||||
locate-path@5.0.0:
|
||||
resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
|
||||
engines: {node: '>=8'}
|
||||
|
|
@ -1649,6 +1721,13 @@ packages:
|
|||
lodash.groupby@4.6.0:
|
||||
resolution: {integrity: sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==}
|
||||
|
||||
lodash.isboolean@3.0.3:
|
||||
resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==}
|
||||
|
||||
lodash.isequal@4.5.0:
|
||||
resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
|
||||
deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead.
|
||||
|
||||
lodash.isfunction@3.0.9:
|
||||
resolution: {integrity: sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==}
|
||||
|
||||
|
|
@ -1796,6 +1875,10 @@ packages:
|
|||
resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
|
||||
mkdirp@0.5.6:
|
||||
resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
|
||||
hasBin: true
|
||||
|
||||
mnemonist@0.39.8:
|
||||
resolution: {integrity: sha512-vyWo2K3fjrUw8YeeZ1zF0fy6Mu59RHokURlld8ymdUPjMlD9EC9ov1/YPqTgqRvUN9nTr3Gqfz29LYAmu0PHPQ==}
|
||||
|
||||
|
|
@ -1818,6 +1901,10 @@ packages:
|
|||
ms@2.1.3:
|
||||
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
||||
|
||||
multer@1.4.5-lts.2:
|
||||
resolution: {integrity: sha512-VzGiVigcG9zUAoCNU+xShztrlr1auZOlurXynNvO9GiWD1/mTBbUljOKY+qMeazBqXgRnjzeEgJI/wyjJUHg9A==}
|
||||
engines: {node: '>= 6.0.0'}
|
||||
|
||||
negotiator@0.6.3:
|
||||
resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
|
@ -2190,6 +2277,11 @@ packages:
|
|||
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
|
||||
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
|
||||
|
||||
rimraf@2.7.1:
|
||||
resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==}
|
||||
deprecated: Rimraf versions prior to v4 are no longer supported
|
||||
hasBin: true
|
||||
|
||||
rimraf@3.0.2:
|
||||
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
|
||||
deprecated: Rimraf versions prior to v4 are no longer supported
|
||||
|
|
@ -2225,6 +2317,10 @@ packages:
|
|||
sax@1.4.1:
|
||||
resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==}
|
||||
|
||||
saxes@5.0.1:
|
||||
resolution: {integrity: sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
secure-json-parse@2.7.0:
|
||||
resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==}
|
||||
|
||||
|
|
@ -2372,6 +2468,10 @@ packages:
|
|||
resolution: {integrity: sha512-LsvisgE3iThboRqA+XLmtnY9ktPLVPOj3zZxXMhlezeCcAh0RhomquXJgB8H+lb/RR/pPcbNVGHVKFUwjpoRtw==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
streamsearch@1.1.0:
|
||||
resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
|
||||
strict-uri-encode@2.0.0:
|
||||
resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==}
|
||||
engines: {node: '>=4'}
|
||||
|
|
@ -2498,6 +2598,9 @@ packages:
|
|||
tr46@1.0.1:
|
||||
resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==}
|
||||
|
||||
traverse@0.3.9:
|
||||
resolution: {integrity: sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==}
|
||||
|
||||
triple-beam@1.4.1:
|
||||
resolution: {integrity: sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==}
|
||||
engines: {node: '>= 14.0.0'}
|
||||
|
|
@ -2567,6 +2670,9 @@ packages:
|
|||
resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
typedarray@0.0.6:
|
||||
resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==}
|
||||
|
||||
typescript@5.7.2:
|
||||
resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==}
|
||||
engines: {node: '>=14.17'}
|
||||
|
|
@ -2616,6 +2722,9 @@ packages:
|
|||
resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
unzipper@0.10.14:
|
||||
resolution: {integrity: sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==}
|
||||
|
||||
util-deprecate@1.0.2:
|
||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||
|
||||
|
|
@ -2626,6 +2735,10 @@ packages:
|
|||
resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
|
||||
engines: {node: '>= 0.4.0'}
|
||||
|
||||
uuid@8.3.2:
|
||||
resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
|
||||
hasBin: true
|
||||
|
||||
uuid@9.0.0:
|
||||
resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==}
|
||||
hasBin: true
|
||||
|
|
@ -2718,6 +2831,13 @@ packages:
|
|||
resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==}
|
||||
engines: {node: '>=4.0'}
|
||||
|
||||
xmlchars@2.2.0:
|
||||
resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
|
||||
|
||||
xtend@4.0.2:
|
||||
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
|
||||
engines: {node: '>=0.4'}
|
||||
|
||||
y18n@5.0.8:
|
||||
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
|
||||
engines: {node: '>=10'}
|
||||
|
|
@ -2826,6 +2946,25 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@fast-csv/format@4.3.5':
|
||||
dependencies:
|
||||
'@types/node': 14.18.63
|
||||
lodash.escaperegexp: 4.1.2
|
||||
lodash.isboolean: 3.0.3
|
||||
lodash.isequal: 4.5.0
|
||||
lodash.isfunction: 3.0.9
|
||||
lodash.isnil: 4.0.0
|
||||
|
||||
'@fast-csv/parse@4.3.6':
|
||||
dependencies:
|
||||
'@types/node': 14.18.63
|
||||
lodash.escaperegexp: 4.1.2
|
||||
lodash.groupby: 4.6.0
|
||||
lodash.isfunction: 3.0.9
|
||||
lodash.isnil: 4.0.0
|
||||
lodash.isundefined: 3.0.1
|
||||
lodash.uniq: 4.5.0
|
||||
|
||||
'@fast-csv/parse@5.0.2':
|
||||
dependencies:
|
||||
lodash.escaperegexp: 4.1.2
|
||||
|
|
@ -3341,6 +3480,8 @@ snapshots:
|
|||
dependencies:
|
||||
'@types/express': 4.17.21
|
||||
|
||||
'@types/node@14.18.63': {}
|
||||
|
||||
'@types/node@20.17.10':
|
||||
dependencies:
|
||||
undici-types: 6.19.8
|
||||
|
|
@ -3440,6 +3581,8 @@ snapshots:
|
|||
json-bignum: 0.0.3
|
||||
tslib: 2.8.1
|
||||
|
||||
append-field@1.0.0: {}
|
||||
|
||||
archiver-utils@2.1.0:
|
||||
dependencies:
|
||||
glob: 7.2.3
|
||||
|
|
@ -3563,11 +3706,18 @@ snapshots:
|
|||
dependencies:
|
||||
safe-buffer: 5.1.2
|
||||
|
||||
big-integer@1.6.52: {}
|
||||
|
||||
binary-extensions@2.3.0: {}
|
||||
|
||||
binary-search@1.3.6:
|
||||
optional: true
|
||||
|
||||
binary@0.3.0:
|
||||
dependencies:
|
||||
buffers: 0.1.1
|
||||
chainsaw: 0.1.0
|
||||
|
||||
bl@4.1.0:
|
||||
dependencies:
|
||||
buffer: 5.7.1
|
||||
|
|
@ -3578,6 +3728,8 @@ snapshots:
|
|||
dependencies:
|
||||
readable-stream: 3.6.2
|
||||
|
||||
bluebird@3.4.7: {}
|
||||
|
||||
bn.js@4.12.1: {}
|
||||
|
||||
body-parser@1.20.3:
|
||||
|
|
@ -3621,11 +3773,21 @@ snapshots:
|
|||
|
||||
buffer-crc32@1.0.0: {}
|
||||
|
||||
buffer-from@1.1.2: {}
|
||||
|
||||
buffer-indexof-polyfill@1.0.2: {}
|
||||
|
||||
buffer@5.7.1:
|
||||
dependencies:
|
||||
base64-js: 1.5.1
|
||||
ieee754: 1.2.1
|
||||
|
||||
buffers@0.1.1: {}
|
||||
|
||||
busboy@1.6.0:
|
||||
dependencies:
|
||||
streamsearch: 1.1.0
|
||||
|
||||
bytes@3.1.2: {}
|
||||
|
||||
call-bind-apply-helpers@1.0.1:
|
||||
|
|
@ -3645,6 +3807,10 @@ snapshots:
|
|||
call-bind-apply-helpers: 1.0.1
|
||||
get-intrinsic: 1.2.6
|
||||
|
||||
chainsaw@0.1.0:
|
||||
dependencies:
|
||||
traverse: 0.3.9
|
||||
|
||||
chalk-template@0.4.0:
|
||||
dependencies:
|
||||
chalk: 4.1.2
|
||||
|
|
@ -3756,6 +3922,13 @@ snapshots:
|
|||
|
||||
concat-map@0.0.1: {}
|
||||
|
||||
concat-stream@1.6.2:
|
||||
dependencies:
|
||||
buffer-from: 1.1.2
|
||||
inherits: 2.0.4
|
||||
readable-stream: 2.3.8
|
||||
typedarray: 0.0.6
|
||||
|
||||
console-log-level@1.4.1:
|
||||
optional: true
|
||||
|
||||
|
|
@ -3899,6 +4072,10 @@ snapshots:
|
|||
es-errors: 1.3.0
|
||||
gopd: 1.2.0
|
||||
|
||||
duplexer2@0.1.4:
|
||||
dependencies:
|
||||
readable-stream: 2.3.8
|
||||
|
||||
eastasianwidth@0.2.0: {}
|
||||
|
||||
ecdsa-sig-formatter@1.0.11:
|
||||
|
|
@ -4088,6 +4265,18 @@ snapshots:
|
|||
|
||||
eventemitter3@5.0.1: {}
|
||||
|
||||
exceljs@4.4.0:
|
||||
dependencies:
|
||||
archiver: 5.3.2
|
||||
dayjs: 1.11.13
|
||||
fast-csv: 4.3.6
|
||||
jszip: 3.10.1
|
||||
readable-stream: 3.6.2
|
||||
saxes: 5.0.1
|
||||
tmp: 0.2.1
|
||||
unzipper: 0.10.14
|
||||
uuid: 8.3.2
|
||||
|
||||
execa@5.1.1:
|
||||
dependencies:
|
||||
cross-spawn: 7.0.6
|
||||
|
|
@ -4136,6 +4325,11 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
fast-csv@4.3.6:
|
||||
dependencies:
|
||||
'@fast-csv/format': 4.3.5
|
||||
'@fast-csv/parse': 4.3.6
|
||||
|
||||
fast-glob@3.3.2:
|
||||
dependencies:
|
||||
'@nodelib/fs.stat': 2.0.5
|
||||
|
|
@ -4258,6 +4452,13 @@ snapshots:
|
|||
fsevents@2.3.3:
|
||||
optional: true
|
||||
|
||||
fstream@1.0.12:
|
||||
dependencies:
|
||||
graceful-fs: 4.2.11
|
||||
inherits: 2.0.4
|
||||
mkdirp: 0.5.6
|
||||
rimraf: 2.7.1
|
||||
|
||||
function-bind@1.1.2: {}
|
||||
|
||||
function.prototype.name@1.1.7:
|
||||
|
|
@ -4693,6 +4894,8 @@ snapshots:
|
|||
|
||||
lines-and-columns@1.2.4: {}
|
||||
|
||||
listenercount@1.0.1: {}
|
||||
|
||||
locate-path@5.0.0:
|
||||
dependencies:
|
||||
p-locate: 4.1.0
|
||||
|
|
@ -4713,6 +4916,10 @@ snapshots:
|
|||
|
||||
lodash.groupby@4.6.0: {}
|
||||
|
||||
lodash.isboolean@3.0.3: {}
|
||||
|
||||
lodash.isequal@4.5.0: {}
|
||||
|
||||
lodash.isfunction@3.0.9: {}
|
||||
|
||||
lodash.isnil@4.0.0: {}
|
||||
|
|
@ -4853,6 +5060,10 @@ snapshots:
|
|||
|
||||
minipass@7.1.2: {}
|
||||
|
||||
mkdirp@0.5.6:
|
||||
dependencies:
|
||||
minimist: 1.2.8
|
||||
|
||||
mnemonist@0.39.8:
|
||||
dependencies:
|
||||
obliterator: 2.0.4
|
||||
|
|
@ -4879,6 +5090,16 @@ snapshots:
|
|||
|
||||
ms@2.1.3: {}
|
||||
|
||||
multer@1.4.5-lts.2:
|
||||
dependencies:
|
||||
append-field: 1.0.0
|
||||
busboy: 1.6.0
|
||||
concat-stream: 1.6.2
|
||||
mkdirp: 0.5.6
|
||||
object-assign: 4.1.1
|
||||
type-is: 1.6.18
|
||||
xtend: 4.0.2
|
||||
|
||||
negotiator@0.6.3: {}
|
||||
|
||||
neo-async@2.6.2: {}
|
||||
|
|
@ -5273,6 +5494,10 @@ snapshots:
|
|||
|
||||
reusify@1.0.4: {}
|
||||
|
||||
rimraf@2.7.1:
|
||||
dependencies:
|
||||
glob: 7.2.3
|
||||
|
||||
rimraf@3.0.2:
|
||||
dependencies:
|
||||
glob: 7.2.3
|
||||
|
|
@ -5307,6 +5532,10 @@ snapshots:
|
|||
|
||||
sax@1.4.1: {}
|
||||
|
||||
saxes@5.0.1:
|
||||
dependencies:
|
||||
xmlchars: 2.2.0
|
||||
|
||||
secure-json-parse@2.7.0: {}
|
||||
|
||||
semver@5.7.2: {}
|
||||
|
|
@ -5478,6 +5707,8 @@ snapshots:
|
|||
|
||||
stream-to-buffer@0.0.1: {}
|
||||
|
||||
streamsearch@1.1.0: {}
|
||||
|
||||
strict-uri-encode@2.0.0: {}
|
||||
|
||||
string-width@4.2.3:
|
||||
|
|
@ -5618,6 +5849,8 @@ snapshots:
|
|||
punycode: 2.3.1
|
||||
optional: true
|
||||
|
||||
traverse@0.3.9: {}
|
||||
|
||||
triple-beam@1.4.1: {}
|
||||
|
||||
ts-deepmerge@7.0.2: {}
|
||||
|
|
@ -5697,6 +5930,8 @@ snapshots:
|
|||
possible-typed-array-names: 1.0.0
|
||||
reflect.getprototypeof: 1.0.8
|
||||
|
||||
typedarray@0.0.6: {}
|
||||
|
||||
typescript@5.7.2: {}
|
||||
|
||||
typical@4.0.0: {}
|
||||
|
|
@ -5736,6 +5971,19 @@ snapshots:
|
|||
|
||||
unpipe@1.0.0: {}
|
||||
|
||||
unzipper@0.10.14:
|
||||
dependencies:
|
||||
big-integer: 1.6.52
|
||||
binary: 0.3.0
|
||||
bluebird: 3.4.7
|
||||
buffer-indexof-polyfill: 1.0.2
|
||||
duplexer2: 0.1.4
|
||||
fstream: 1.0.12
|
||||
graceful-fs: 4.2.11
|
||||
listenercount: 1.0.1
|
||||
readable-stream: 2.3.8
|
||||
setimmediate: 1.0.5
|
||||
|
||||
util-deprecate@1.0.2: {}
|
||||
|
||||
util@0.12.5:
|
||||
|
|
@ -5748,6 +5996,8 @@ snapshots:
|
|||
|
||||
utils-merge@1.0.1: {}
|
||||
|
||||
uuid@8.3.2: {}
|
||||
|
||||
uuid@9.0.0: {}
|
||||
|
||||
v8-compile-cache-lib@3.0.1: {}
|
||||
|
|
@ -5888,6 +6138,10 @@ snapshots:
|
|||
|
||||
xmlbuilder@11.0.1: {}
|
||||
|
||||
xmlchars@2.2.0: {}
|
||||
|
||||
xtend@4.0.2: {}
|
||||
|
||||
y18n@5.0.8: {}
|
||||
|
||||
yallist@2.1.2:
|
||||
|
|
|
|||
3
prisma/migrations/20250410102415_add/migration.sql
Normal file
3
prisma/migrations/20250410102415_add/migration.sql
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
-- AlterTable
|
||||
ALTER TABLE "User" ADD COLUMN "contactName" TEXT,
|
||||
ADD COLUMN "contactTel" TEXT;
|
||||
3
prisma/migrations/20250410104307_change/migration.sql
Normal file
3
prisma/migrations/20250410104307_change/migration.sql
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
-- AlterTable
|
||||
ALTER TABLE "User" ALTER COLUMN "firstName" DROP NOT NULL,
|
||||
ALTER COLUMN "lastName" DROP NOT NULL;
|
||||
2
prisma/migrations/20250418095201_add/migration.sql
Normal file
2
prisma/migrations/20250418095201_add/migration.sql
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
-- AlterTable
|
||||
ALTER TABLE "TaskOrder" ADD COLUMN "codeProductReceived" TEXT;
|
||||
18
prisma/migrations/20250418103300_add/migration.sql
Normal file
18
prisma/migrations/20250418103300_add/migration.sql
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
-- AlterTable
|
||||
ALTER TABLE "Institution" ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
ADD COLUMN "createdByUserId" TEXT,
|
||||
ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
ADD COLUMN "updatedByUserId" TEXT;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Payment" ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
ADD COLUMN "updatedByUserId" TEXT;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Institution" ADD CONSTRAINT "Institution_createdByUserId_fkey" FOREIGN KEY ("createdByUserId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Institution" ADD CONSTRAINT "Institution_updatedByUserId_fkey" FOREIGN KEY ("updatedByUserId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Payment" ADD CONSTRAINT "Payment_updatedByUserId_fkey" FOREIGN KEY ("updatedByUserId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
-- AlterTable
|
||||
ALTER TABLE "Employee" ALTER COLUMN "lastNameEN" DROP NOT NULL;
|
||||
11
prisma/migrations/20250424042834_add/migration.sql
Normal file
11
prisma/migrations/20250424042834_add/migration.sql
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
-- CreateTable
|
||||
CREATE TABLE "WorkflowTemplateStepGroup" (
|
||||
"id" TEXT NOT NULL,
|
||||
"group" TEXT NOT NULL,
|
||||
"workflowTemplateStepId" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "WorkflowTemplateStepGroup_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "WorkflowTemplateStepGroup" ADD CONSTRAINT "WorkflowTemplateStepGroup_workflowTemplateStepId_fkey" FOREIGN KEY ("workflowTemplateStepId") REFERENCES "WorkflowTemplateStep"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `importNationality` on the `User` table. All the data in the column will be lost.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "User" DROP COLUMN "importNationality";
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "UserImportNationality" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "UserImportNationality_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "UserImportNationality" ADD CONSTRAINT "UserImportNationality_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
2
prisma/migrations/20250425040315_add/migration.sql
Normal file
2
prisma/migrations/20250425040315_add/migration.sql
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
-- AlterTable
|
||||
ALTER TABLE "Employee" ADD COLUMN "otherNationality" TEXT;
|
||||
2
prisma/migrations/20250425041426_add/migration.sql
Normal file
2
prisma/migrations/20250425041426_add/migration.sql
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
-- AlterTable
|
||||
ALTER TABLE "EmployeePassport" ADD COLUMN "otherNationality" TEXT;
|
||||
|
|
@ -366,16 +366,24 @@ enum UserType {
|
|||
AGENCY
|
||||
}
|
||||
|
||||
model UserImportNationality {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
userId String
|
||||
}
|
||||
|
||||
model User {
|
||||
id String @id @default(cuid())
|
||||
|
||||
code String?
|
||||
namePrefix String?
|
||||
firstName String
|
||||
firstName String?
|
||||
firstNameEN String
|
||||
middleName String?
|
||||
middleNameEN String?
|
||||
lastName String
|
||||
lastName String?
|
||||
lastNameEN String
|
||||
username String
|
||||
gender String
|
||||
|
|
@ -424,7 +432,7 @@ model User {
|
|||
licenseExpireDate DateTime? @db.Date
|
||||
|
||||
sourceNationality String?
|
||||
importNationality String?
|
||||
importNationality UserImportNationality[]
|
||||
|
||||
trainingPlace String?
|
||||
responsibleArea UserResponsibleArea[]
|
||||
|
|
@ -484,12 +492,15 @@ model User {
|
|||
flowCreated WorkflowTemplate[] @relation("FlowCreatedByUser")
|
||||
flowUpdated WorkflowTemplate[] @relation("FlowUpdatedByUser")
|
||||
invoiceCreated Invoice[]
|
||||
paymentCreated Payment[]
|
||||
paymentCreated Payment[] @relation("PaymentCreatedByUser")
|
||||
paymentUpdated Payment[] @relation("PaymentUpdatedByUser")
|
||||
notificationReceive Notification[] @relation("NotificationReceiver")
|
||||
notificationRead Notification[] @relation("NotificationRead")
|
||||
notificationDelete Notification[] @relation("NotificationDelete")
|
||||
taskOrderCreated TaskOrder[] @relation("TaskOrderCreatedByUser")
|
||||
creditNoteCreated CreditNote[] @relation("CreditNoteCreatedByUser")
|
||||
institutionCreated Institution[] @relation("InstitutionCreatedByUser")
|
||||
institutionUpdated Institution[] @relation("InstitutionUpdatedByUser")
|
||||
|
||||
requestWorkStepStatus RequestWorkStepStatus[]
|
||||
userTask UserTask[]
|
||||
|
|
@ -497,6 +508,9 @@ model User {
|
|||
|
||||
remark String?
|
||||
agencyStatus String?
|
||||
|
||||
contactName String?
|
||||
contactTel String?
|
||||
}
|
||||
|
||||
model UserResponsibleArea {
|
||||
|
|
@ -771,11 +785,12 @@ model Employee {
|
|||
middleName String?
|
||||
middleNameEN String?
|
||||
lastName String?
|
||||
lastNameEN String
|
||||
lastNameEN String?
|
||||
|
||||
dateOfBirth DateTime? @db.Date
|
||||
gender String
|
||||
nationality String
|
||||
dateOfBirth DateTime? @db.Date
|
||||
gender String
|
||||
nationality String
|
||||
otherNationality String?
|
||||
|
||||
address String?
|
||||
addressEN String?
|
||||
|
|
@ -850,18 +865,19 @@ model EmployeePassport {
|
|||
issuePlace String
|
||||
previousPassportRef String?
|
||||
|
||||
workerStatus String?
|
||||
nationality String?
|
||||
namePrefix String?
|
||||
firstName String?
|
||||
firstNameEN String?
|
||||
middleName String?
|
||||
middleNameEN String?
|
||||
lastName String?
|
||||
lastNameEN String?
|
||||
gender String?
|
||||
birthDate String?
|
||||
birthCountry String?
|
||||
workerStatus String?
|
||||
nationality String?
|
||||
otherNationality String?
|
||||
namePrefix String?
|
||||
firstName String?
|
||||
firstNameEN String?
|
||||
middleName String?
|
||||
middleNameEN String?
|
||||
lastName String?
|
||||
lastNameEN String?
|
||||
gender String?
|
||||
birthDate String?
|
||||
birthCountry String?
|
||||
|
||||
employee Employee @relation(fields: [employeeId], references: [id], onDelete: Cascade)
|
||||
employeeId String
|
||||
|
|
@ -1012,6 +1028,13 @@ model Institution {
|
|||
contactEmail String?
|
||||
contactTel String?
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
createdBy User? @relation(name: "InstitutionCreatedByUser", fields: [createdByUserId], references: [id], onDelete: SetNull)
|
||||
createdByUserId String?
|
||||
updatedAt DateTime @default(now()) @updatedAt
|
||||
updatedBy User? @relation(name: "InstitutionUpdatedByUser", fields: [updatedByUserId], references: [id], onDelete: SetNull)
|
||||
updatedByUserId String?
|
||||
|
||||
bank InstitutionBank[]
|
||||
}
|
||||
|
||||
|
|
@ -1076,6 +1099,15 @@ model WorkflowTemplateStepInstitution {
|
|||
workflowTemplateStepId String
|
||||
}
|
||||
|
||||
model WorkflowTemplateStepGroup {
|
||||
id String @id @default(cuid())
|
||||
|
||||
group String
|
||||
|
||||
workflowTemplateStep WorkflowTemplateStep @relation(fields: [workflowTemplateStepId], references: [id], onDelete: Cascade)
|
||||
workflowTemplateStepId String
|
||||
}
|
||||
|
||||
model WorkflowTemplateStep {
|
||||
id String @id @default(cuid())
|
||||
|
||||
|
|
@ -1086,6 +1118,7 @@ model WorkflowTemplateStep {
|
|||
value WorkflowTemplateStepValue[] // NOTE: For enum or options type
|
||||
responsiblePerson WorkflowTemplateStepUser[]
|
||||
responsibleInstitution WorkflowTemplateStepInstitution[]
|
||||
responsibleGroup WorkflowTemplateStepGroup[]
|
||||
messengerByArea Boolean @default(false)
|
||||
|
||||
attributes Json?
|
||||
|
|
@ -1460,8 +1493,12 @@ model Payment {
|
|||
date DateTime?
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
createdBy User? @relation(fields: [createdByUserId], references: [id], onDelete: SetNull)
|
||||
createdBy User? @relation(name: "PaymentCreatedByUser", fields: [createdByUserId], references: [id], onDelete: SetNull)
|
||||
createdByUserId String?
|
||||
|
||||
updatedAt DateTime @default(now()) @updatedAt
|
||||
updatedBy User? @relation(name: "PaymentUpdatedByUser", fields: [updatedByUserId], references: [id], onDelete: SetNull)
|
||||
updatedByUserId String?
|
||||
}
|
||||
|
||||
enum RequestDataStatus {
|
||||
|
|
@ -1614,7 +1651,8 @@ model TaskProduct {
|
|||
model TaskOrder {
|
||||
id String @id @default(cuid())
|
||||
|
||||
code String
|
||||
code String
|
||||
codeProductReceived String?
|
||||
|
||||
taskName String
|
||||
taskOrderStatus TaskOrderStatus @default(Pending)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Body, Controller, Get, Path, Post, Query, Route, Tags } from "tsoa";
|
|||
import prisma from "../db";
|
||||
import { queryOrNot } from "../utils/relation";
|
||||
import { notFoundError } from "../utils/error";
|
||||
import { Prisma } from "@prisma/client";
|
||||
|
||||
@Route("/api/v1/employment-office")
|
||||
@Tags("Employment Office")
|
||||
|
|
@ -11,6 +12,39 @@ export class EmploymentOfficeController extends Controller {
|
|||
return this.getEmploymentOfficeListByCriteria(districtId, query);
|
||||
}
|
||||
|
||||
@Post("list-same-office-area")
|
||||
async getSameOfficeArea(@Body() body: { districtId: string }) {
|
||||
const office = await prisma.employmentOffice.findFirst({
|
||||
include: {
|
||||
province: {
|
||||
include: {
|
||||
district: true,
|
||||
},
|
||||
},
|
||||
district: true,
|
||||
},
|
||||
where: {
|
||||
OR: [
|
||||
{
|
||||
province: { district: { some: { id: body.districtId } } },
|
||||
district: { none: {} },
|
||||
},
|
||||
{
|
||||
district: {
|
||||
some: { districtId: body.districtId },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
if (!office) return [];
|
||||
|
||||
return [
|
||||
...office.district.map((v) => v.districtId),
|
||||
...office.province.district.map((v) => v.id),
|
||||
];
|
||||
}
|
||||
|
||||
@Post("list")
|
||||
async getEmploymentOfficeListByCriteria(
|
||||
@Query() districtId?: string,
|
||||
|
|
@ -40,11 +74,14 @@ export class EmploymentOfficeController extends Controller {
|
|||
],
|
||||
[],
|
||||
),
|
||||
...queryOrNot(
|
||||
...(queryOrNot(
|
||||
query,
|
||||
[{ name: { contains: query } }, { nameEN: { contains: query } }],
|
||||
[
|
||||
{ name: { contains: query, mode: "insensitive" } },
|
||||
{ nameEN: { contains: query, mode: "insensitive" } },
|
||||
],
|
||||
[],
|
||||
),
|
||||
) satisfies Prisma.EmploymentOfficeWhereInput["OR"]),
|
||||
...queryOrNot(!!body?.id, [{ id: { in: body?.id } }], []),
|
||||
]
|
||||
: undefined,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Body, Controller, Delete, Get, Path, Post, Route, Security, Tags } from "tsoa";
|
||||
import { addUserRoles, listRole, removeUserRoles } from "../services/keycloak";
|
||||
import { Body, Controller, Delete, Get, Path, Post, Query, Route, Security, Tags } from "tsoa";
|
||||
import { addUserRoles, getGroup, listRole, removeUserRoles } from "../services/keycloak";
|
||||
|
||||
@Route("api/v1/keycloak")
|
||||
@Tags("Single-Sign On")
|
||||
|
|
@ -44,4 +44,13 @@ export class KeycloakController extends Controller {
|
|||
);
|
||||
if (!result) throw new Error("Failed. Cannot remove user's role.");
|
||||
}
|
||||
|
||||
@Get("group")
|
||||
async getGroup(@Query() query: string = "") {
|
||||
const querySearch = query === "" ? "q" : `search=${query}`;
|
||||
const group = await getGroup(querySearch);
|
||||
if (!Array.isArray(group)) throw new Error("Failed. Cannot get group(s) data from the server.");
|
||||
|
||||
return group;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,8 +36,8 @@ export class NotificationController extends Controller {
|
|||
AND: [
|
||||
{
|
||||
OR: queryOrNot<(typeof where)[]>(query, [
|
||||
{ title: { contains: query } },
|
||||
{ detail: { contains: query } },
|
||||
{ title: { contains: query, mode: "insensitive" } },
|
||||
{ detail: { contains: query, mode: "insensitive" } },
|
||||
]),
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ import {
|
|||
connectOrNot,
|
||||
queryOrNot,
|
||||
whereAddressQuery,
|
||||
whereDateQuery,
|
||||
} from "../utils/relation";
|
||||
import { isUsedError, notFoundError, relationError } from "../utils/error";
|
||||
|
||||
|
|
@ -250,6 +251,8 @@ export class BranchController extends Controller {
|
|||
@Query() query: string = "",
|
||||
@Query() page: number = 1,
|
||||
@Query() pageSize: number = 30,
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
) {
|
||||
const where = {
|
||||
AND: {
|
||||
|
|
@ -265,26 +268,27 @@ export class BranchController extends Controller {
|
|||
},
|
||||
OR: queryOrNot<Prisma.BranchWhereInput[]>(query, [
|
||||
{ code: { contains: query, mode: "insensitive" } },
|
||||
{ nameEN: { contains: query } },
|
||||
{ name: { contains: query } },
|
||||
{ email: { contains: query } },
|
||||
{ telephoneNo: { contains: query } },
|
||||
{ nameEN: { contains: query, mode: "insensitive" } },
|
||||
{ name: { contains: query, mode: "insensitive" } },
|
||||
{ email: { contains: query, mode: "insensitive" } },
|
||||
{ telephoneNo: { contains: query, mode: "insensitive" } },
|
||||
...whereAddressQuery(query),
|
||||
{
|
||||
branch: {
|
||||
some: {
|
||||
OR: [
|
||||
{ code: { contains: query, mode: "insensitive" } },
|
||||
{ nameEN: { contains: query } },
|
||||
{ name: { contains: query } },
|
||||
{ email: { contains: query } },
|
||||
{ telephoneNo: { contains: query } },
|
||||
{ nameEN: { contains: query, mode: "insensitive" } },
|
||||
{ name: { contains: query, mode: "insensitive" } },
|
||||
{ email: { contains: query, mode: "insensitive" } },
|
||||
{ telephoneNo: { contains: query, mode: "insensitive" } },
|
||||
...whereAddressQuery(query),
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
]),
|
||||
...whereDateQuery(startDate, endDate),
|
||||
} satisfies Prisma.BranchWhereInput;
|
||||
|
||||
const [result, total] = await prisma.$transaction([
|
||||
|
|
@ -309,12 +313,13 @@ export class BranchController extends Controller {
|
|||
where: {
|
||||
AND: { OR: permissionCond(req.user) },
|
||||
OR: [
|
||||
{ nameEN: { contains: query } },
|
||||
{ name: { contains: query } },
|
||||
{ email: { contains: query } },
|
||||
{ telephoneNo: { contains: query } },
|
||||
{ nameEN: { contains: query, mode: "insensitive" } },
|
||||
{ name: { contains: query, mode: "insensitive" } },
|
||||
{ email: { contains: query, mode: "insensitive" } },
|
||||
{ telephoneNo: { contains: query, mode: "insensitive" } },
|
||||
...whereAddressQuery(query),
|
||||
],
|
||||
...whereDateQuery(startDate, endDate),
|
||||
},
|
||||
include: {
|
||||
province: true,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import HttpError from "../interfaces/http-error";
|
|||
import HttpStatus from "../interfaces/http-status";
|
||||
import { RequestWithUser } from "../interfaces/user";
|
||||
import { branchRelationPermInclude, createPermCheck } from "../services/permission";
|
||||
import { queryOrNot } from "../utils/relation";
|
||||
import { queryOrNot, whereDateQuery } from "../utils/relation";
|
||||
|
||||
const MANAGE_ROLES = ["system", "head_of_admin", "admin", "branch_manager"];
|
||||
|
||||
|
|
@ -97,6 +97,8 @@ export class UserBranchController extends Controller {
|
|||
@Query() query: string = "",
|
||||
@Query() page: number = 1,
|
||||
@Query() pageSize: number = 30,
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
) {
|
||||
const where = {
|
||||
AND: {
|
||||
|
|
@ -104,9 +106,10 @@ export class UserBranchController extends Controller {
|
|||
userId,
|
||||
},
|
||||
OR: queryOrNot<Prisma.BranchUserWhereInput[]>(query, [
|
||||
{ branch: { name: { contains: query } } },
|
||||
{ branch: { nameEN: { contains: query } } },
|
||||
{ branch: { name: { contains: query, mode: "insensitive" } } },
|
||||
{ branch: { nameEN: { contains: query, mode: "insensitive" } } },
|
||||
]),
|
||||
...whereDateQuery(startDate, endDate),
|
||||
} satisfies Prisma.BranchUserWhereInput;
|
||||
|
||||
const [result, total] = await prisma.$transaction([
|
||||
|
|
@ -150,6 +153,8 @@ export class BranchUserController extends Controller {
|
|||
@Query() query: string = "",
|
||||
@Query() page: number = 1,
|
||||
@Query() pageSize: number = 30,
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
) {
|
||||
const where = {
|
||||
AND: {
|
||||
|
|
@ -157,13 +162,14 @@ export class BranchUserController extends Controller {
|
|||
branchId,
|
||||
},
|
||||
OR: [
|
||||
{ user: { firstName: { contains: query } } },
|
||||
{ user: { firstNameEN: { contains: query } } },
|
||||
{ user: { lastName: { contains: query } } },
|
||||
{ user: { lastNameEN: { contains: query } } },
|
||||
{ user: { email: { contains: query } } },
|
||||
{ user: { telephoneNo: { contains: query } } },
|
||||
{ user: { firstName: { contains: query, mode: "insensitive" } } },
|
||||
{ user: { firstNameEN: { contains: query, mode: "insensitive" } } },
|
||||
{ user: { lastName: { contains: query, mode: "insensitive" } } },
|
||||
{ user: { lastNameEN: { contains: query, mode: "insensitive" } } },
|
||||
{ user: { email: { contains: query, mode: "insensitive" } } },
|
||||
{ user: { telephoneNo: { contains: query, mode: "insensitive" } } },
|
||||
],
|
||||
...whereDateQuery(startDate, endDate),
|
||||
} satisfies Prisma.BranchUserWhereInput;
|
||||
|
||||
const [result, total] = await prisma.$transaction([
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import {
|
|||
listRole,
|
||||
getUserRoles,
|
||||
removeUserRoles,
|
||||
getGroupUser,
|
||||
} from "../services/keycloak";
|
||||
import { isSystem } from "../utils/keycloak";
|
||||
import {
|
||||
|
|
@ -51,6 +52,7 @@ import {
|
|||
connectOrNot,
|
||||
queryOrNot,
|
||||
whereAddressQuery,
|
||||
whereDateQuery,
|
||||
} from "../utils/relation";
|
||||
import { isUsedError, notFoundError, relationError } from "../utils/error";
|
||||
import { retry } from "../utils/func";
|
||||
|
|
@ -79,11 +81,11 @@ type UserCreate = {
|
|||
citizenExpire?: Date | null;
|
||||
|
||||
namePrefix?: string | null;
|
||||
firstName: string;
|
||||
firstName?: string;
|
||||
firstNameEN: string;
|
||||
middleName?: string | null;
|
||||
middleNameEN?: string | null;
|
||||
lastName: string;
|
||||
lastName?: string;
|
||||
lastNameEN: string;
|
||||
gender: string;
|
||||
|
||||
|
|
@ -97,7 +99,7 @@ type UserCreate = {
|
|||
licenseIssueDate?: Date | null;
|
||||
licenseExpireDate?: Date | null;
|
||||
sourceNationality?: string | null;
|
||||
importNationality?: string | null;
|
||||
importNationality?: string[] | null;
|
||||
trainingPlace?: string | null;
|
||||
responsibleArea?: string[] | null;
|
||||
birthDate?: Date | null;
|
||||
|
|
@ -123,6 +125,9 @@ type UserCreate = {
|
|||
|
||||
remark?: string;
|
||||
agencyStatus?: string;
|
||||
|
||||
contactName?: string;
|
||||
contactTel?: string;
|
||||
};
|
||||
|
||||
type UserUpdate = {
|
||||
|
|
@ -139,9 +144,9 @@ type UserUpdate = {
|
|||
|
||||
namePrefix?: string | null;
|
||||
firstName?: string;
|
||||
firstNameEN?: string;
|
||||
firstNameEN: string;
|
||||
middleName?: string | null;
|
||||
middleNameEN?: string | null;
|
||||
middleNameEN: string | null;
|
||||
lastName?: string;
|
||||
lastNameEN?: string;
|
||||
gender?: string;
|
||||
|
|
@ -156,7 +161,7 @@ type UserUpdate = {
|
|||
licenseIssueDate?: Date | null;
|
||||
licenseExpireDate?: Date | null;
|
||||
sourceNationality?: string | null;
|
||||
importNationality?: string | null;
|
||||
importNationality?: string[] | null;
|
||||
trainingPlace?: string | null;
|
||||
responsibleArea?: string[] | null;
|
||||
birthDate?: Date | null;
|
||||
|
|
@ -182,6 +187,9 @@ type UserUpdate = {
|
|||
|
||||
remark?: string;
|
||||
agencyStatus?: string;
|
||||
|
||||
contactName?: string;
|
||||
contactTel?: string;
|
||||
};
|
||||
|
||||
const permissionCondCompany = createPermCondition((_) => true);
|
||||
|
|
@ -273,6 +281,8 @@ export class UserController extends Controller {
|
|||
@Query() status?: Status,
|
||||
@Query() responsibleDistrictId?: string,
|
||||
@Query() activeBranchOnly?: boolean,
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
) {
|
||||
return this.getUserByCriteria(
|
||||
req,
|
||||
|
|
@ -284,6 +294,8 @@ export class UserController extends Controller {
|
|||
status,
|
||||
responsibleDistrictId,
|
||||
activeBranchOnly,
|
||||
startDate,
|
||||
endDate,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -299,6 +311,8 @@ export class UserController extends Controller {
|
|||
@Query() status?: Status,
|
||||
@Query() responsibleDistrictId?: string,
|
||||
@Query() activeBranchOnly?: boolean,
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
@Body()
|
||||
body?: {
|
||||
userId?: string[];
|
||||
|
|
@ -324,12 +338,12 @@ export class UserController extends Controller {
|
|||
const where = {
|
||||
OR: queryOrNot<Prisma.UserWhereInput[]>(query, [
|
||||
{ code: { contains: query, mode: "insensitive" } },
|
||||
{ firstName: { contains: query } },
|
||||
{ firstNameEN: { contains: query } },
|
||||
{ lastName: { contains: query } },
|
||||
{ lastNameEN: { contains: query } },
|
||||
{ email: { contains: query } },
|
||||
{ telephoneNo: { contains: query } },
|
||||
{ firstName: { contains: query, mode: "insensitive" } },
|
||||
{ firstNameEN: { contains: query, mode: "insensitive" } },
|
||||
{ lastName: { contains: query, mode: "insensitive" } },
|
||||
{ lastNameEN: { contains: query, mode: "insensitive" } },
|
||||
{ email: { contains: query, mode: "insensitive" } },
|
||||
{ telephoneNo: { contains: query, mode: "insensitive" } },
|
||||
...whereAddressQuery(query),
|
||||
]),
|
||||
AND: {
|
||||
|
|
@ -362,12 +376,14 @@ export class UserController extends Controller {
|
|||
},
|
||||
},
|
||||
},
|
||||
...whereDateQuery(startDate, endDate),
|
||||
} satisfies Prisma.UserWhereInput;
|
||||
|
||||
const [result, total] = await prisma.$transaction([
|
||||
prisma.user.findMany({
|
||||
orderBy: [{ statusOrder: "asc" }, { createdAt: "asc" }],
|
||||
include: {
|
||||
importNationality: true,
|
||||
responsibleArea: true,
|
||||
province: true,
|
||||
district: true,
|
||||
|
|
@ -386,6 +402,7 @@ export class UserController extends Controller {
|
|||
return {
|
||||
result: result.map((v) => ({
|
||||
...v,
|
||||
importNationality: v.importNationality.map((v) => v.name),
|
||||
responsibleArea: v.responsibleArea.map((v) => v.area),
|
||||
branch: includeBranch ? v.branch.map((a) => a.branch) : undefined,
|
||||
})),
|
||||
|
|
@ -400,6 +417,7 @@ export class UserController extends Controller {
|
|||
async getUserById(@Path() userId: string) {
|
||||
const record = await prisma.user.findFirst({
|
||||
include: {
|
||||
importNationality: true,
|
||||
province: true,
|
||||
district: true,
|
||||
subDistrict: true,
|
||||
|
|
@ -411,7 +429,11 @@ export class UserController extends Controller {
|
|||
|
||||
if (!record) throw notFoundError("User");
|
||||
|
||||
return record;
|
||||
const { importNationality, ...rest } = record;
|
||||
|
||||
return Object.assign(rest, {
|
||||
importNationality: importNationality.map((v) => v.name),
|
||||
});
|
||||
}
|
||||
|
||||
@Post()
|
||||
|
|
@ -477,8 +499,8 @@ export class UserController extends Controller {
|
|||
}
|
||||
|
||||
const userId = await createUser(username, username, {
|
||||
firstName: body.firstName,
|
||||
lastName: body.lastName,
|
||||
firstName: body.firstNameEN,
|
||||
lastName: body.lastNameEN,
|
||||
email: body.email,
|
||||
requiredActions: ["UPDATE_PASSWORD"],
|
||||
enabled: rest.status !== "INACTIVE",
|
||||
|
|
@ -513,6 +535,9 @@ export class UserController extends Controller {
|
|||
create: rest.responsibleArea.map((v) => ({ area: v })),
|
||||
}
|
||||
: undefined,
|
||||
importNationality: {
|
||||
createMany: { data: rest.importNationality?.map((v) => ({ name: v })) || [] },
|
||||
},
|
||||
statusOrder: +(rest.status === "INACTIVE"),
|
||||
username,
|
||||
userRole: role.name,
|
||||
|
|
@ -668,6 +693,7 @@ export class UserController extends Controller {
|
|||
|
||||
const record = await prisma.user.update({
|
||||
include: {
|
||||
importNationality: true,
|
||||
province: true,
|
||||
district: true,
|
||||
subDistrict: true,
|
||||
|
|
@ -682,6 +708,10 @@ export class UserController extends Controller {
|
|||
create: rest.responsibleArea.map((v) => ({ area: v })),
|
||||
}
|
||||
: undefined,
|
||||
importNationality: {
|
||||
deleteMany: {},
|
||||
createMany: { data: rest.importNationality?.map((v) => ({ name: v })) || [] },
|
||||
},
|
||||
statusOrder: +(rest.status === "INACTIVE"),
|
||||
userRole,
|
||||
province: connectOrDisconnect(provinceId),
|
||||
|
|
@ -933,3 +963,17 @@ export class UserSignatureController extends Controller {
|
|||
await deleteFile(fileLocation.user.signature(userId));
|
||||
}
|
||||
}
|
||||
|
||||
@Route("api/v1/user/{userId}/group")
|
||||
@Tags("User")
|
||||
@Security("keycloak")
|
||||
export class UserGroupController extends Controller {
|
||||
@Get()
|
||||
async getUserGroup(@Path() userId: string) {
|
||||
const groupUser = await getGroupUser(userId);
|
||||
if (!Array.isArray(groupUser))
|
||||
throw new Error("Failed. Cannot get user group(s) data from the server.");
|
||||
|
||||
return groupUser;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import {
|
|||
connectOrNot,
|
||||
queryOrNot,
|
||||
whereAddressQuery,
|
||||
whereDateQuery,
|
||||
} from "../utils/relation";
|
||||
import { isUsedError, notFoundError, relationError } from "../utils/error";
|
||||
import {
|
||||
|
|
@ -195,18 +196,20 @@ export class CustomerBranchController extends Controller {
|
|||
@Query() page: number = 1,
|
||||
@Query() pageSize: number = 30,
|
||||
@Query() activeRegisBranchOnly?: boolean,
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
) {
|
||||
const where = {
|
||||
OR: queryOrNot<Prisma.CustomerBranchWhereInput[]>(query, [
|
||||
{ customerName: { contains: query } },
|
||||
{ registerName: { contains: query } },
|
||||
{ registerNameEN: { contains: query } },
|
||||
{ email: { contains: query } },
|
||||
{ code: { contains: query } },
|
||||
{ firstName: { contains: query } },
|
||||
{ firstNameEN: { contains: query } },
|
||||
{ lastName: { contains: query } },
|
||||
{ lastNameEN: { contains: query } },
|
||||
{ customerName: { contains: query, mode: "insensitive" } },
|
||||
{ registerName: { contains: query, mode: "insensitive" } },
|
||||
{ registerNameEN: { contains: query, mode: "insensitive" } },
|
||||
{ email: { contains: query, mode: "insensitive" } },
|
||||
{ code: { contains: query, mode: "insensitive" } },
|
||||
{ firstName: { contains: query, mode: "insensitive" } },
|
||||
{ firstNameEN: { contains: query, mode: "insensitive" } },
|
||||
{ lastName: { contains: query, mode: "insensitive" } },
|
||||
{ lastNameEN: { contains: query, mode: "insensitive" } },
|
||||
...whereAddressQuery(query),
|
||||
]),
|
||||
AND: {
|
||||
|
|
@ -229,6 +232,7 @@ export class CustomerBranchController extends Controller {
|
|||
subDistrict: zipCode ? { zipCode } : undefined,
|
||||
...filterStatus(activeRegisBranchOnly ? Status.ACTIVE : status),
|
||||
},
|
||||
...whereDateQuery(startDate, endDate),
|
||||
} satisfies Prisma.CustomerBranchWhereInput;
|
||||
|
||||
const [result, total] = await prisma.$transaction([
|
||||
|
|
@ -285,13 +289,15 @@ export class CustomerBranchController extends Controller {
|
|||
@Query() visa?: boolean,
|
||||
@Query() page: number = 1,
|
||||
@Query() pageSize: number = 30,
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
) {
|
||||
const where = {
|
||||
OR: queryOrNot<Prisma.EmployeeWhereInput[]>(query, [
|
||||
{ firstName: { contains: query } },
|
||||
{ firstNameEN: { contains: query } },
|
||||
{ lastName: { contains: query } },
|
||||
{ lastNameEN: { contains: query } },
|
||||
{ firstName: { contains: query, mode: "insensitive" } },
|
||||
{ firstNameEN: { contains: query, mode: "insensitive" } },
|
||||
{ lastName: { contains: query, mode: "insensitive" } },
|
||||
{ lastNameEN: { contains: query, mode: "insensitive" } },
|
||||
...whereAddressQuery(query),
|
||||
]),
|
||||
AND: {
|
||||
|
|
@ -300,6 +306,7 @@ export class CustomerBranchController extends Controller {
|
|||
subDistrict: zipCode ? { zipCode } : undefined,
|
||||
gender,
|
||||
},
|
||||
...whereDateQuery(startDate, endDate),
|
||||
} satisfies Prisma.EmployeeWhereInput;
|
||||
|
||||
const [result, total] = await prisma.$transaction([
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ import {
|
|||
setFile,
|
||||
} from "../utils/minio";
|
||||
import { isUsedError, notFoundError, relationError } from "../utils/error";
|
||||
import { connectOrNot, queryOrNot } from "../utils/relation";
|
||||
import { connectOrNot, queryOrNot, whereDateQuery } from "../utils/relation";
|
||||
|
||||
const MANAGE_ROLES = [
|
||||
"system",
|
||||
|
|
@ -165,17 +165,19 @@ export class CustomerController extends Controller {
|
|||
@Query() includeBranch: boolean = false,
|
||||
@Query() company: boolean = false,
|
||||
@Query() activeBranchOnly?: boolean,
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
) {
|
||||
const where = {
|
||||
OR: queryOrNot<Prisma.CustomerWhereInput[]>(query, [
|
||||
{ branch: { some: { namePrefix: { contains: query } } } },
|
||||
{ branch: { some: { customerName: { contains: query } } } },
|
||||
{ branch: { some: { registerName: { contains: query } } } },
|
||||
{ branch: { some: { registerNameEN: { contains: query } } } },
|
||||
{ branch: { some: { firstName: { contains: query } } } },
|
||||
{ branch: { some: { firstNameEN: { contains: query } } } },
|
||||
{ branch: { some: { lastName: { contains: query } } } },
|
||||
{ branch: { some: { lastNameEN: { contains: query } } } },
|
||||
{ branch: { some: { namePrefix: { contains: query, mode: "insensitive" } } } },
|
||||
{ branch: { some: { customerName: { contains: query, mode: "insensitive" } } } },
|
||||
{ branch: { some: { registerName: { contains: query, mode: "insensitive" } } } },
|
||||
{ branch: { some: { registerNameEN: { contains: query, mode: "insensitive" } } } },
|
||||
{ branch: { some: { firstName: { contains: query, mode: "insensitive" } } } },
|
||||
{ branch: { some: { firstNameEN: { contains: query, mode: "insensitive" } } } },
|
||||
{ branch: { some: { lastName: { contains: query, mode: "insensitive" } } } },
|
||||
{ branch: { some: { lastNameEN: { contains: query, mode: "insensitive" } } } },
|
||||
]),
|
||||
AND: {
|
||||
customerType,
|
||||
|
|
@ -188,6 +190,7 @@ export class CustomerController extends Controller {
|
|||
: permissionCond(req.user, { activeOnly: activeBranchOnly }),
|
||||
},
|
||||
},
|
||||
...whereDateQuery(startDate, endDate),
|
||||
} satisfies Prisma.CustomerWhereInput;
|
||||
|
||||
const [result, total] = await prisma.$transaction([
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import {
|
|||
connectOrNot,
|
||||
queryOrNot,
|
||||
whereAddressQuery,
|
||||
whereDateQuery,
|
||||
} from "../utils/relation";
|
||||
import { isUsedError, notFoundError, relationError } from "../utils/error";
|
||||
import {
|
||||
|
|
@ -73,6 +74,7 @@ type EmployeeCreate = {
|
|||
dateOfBirth?: Date | null;
|
||||
gender: string;
|
||||
nationality: string;
|
||||
otherNationality?: string;
|
||||
|
||||
namePrefix?: string | null;
|
||||
firstName?: string;
|
||||
|
|
@ -109,6 +111,7 @@ type EmployeeUpdate = {
|
|||
dateOfBirth?: Date;
|
||||
gender?: string;
|
||||
nationality?: string;
|
||||
otherNationality?: string;
|
||||
|
||||
namePrefix?: string | null;
|
||||
firstName?: string;
|
||||
|
|
@ -116,7 +119,7 @@ type EmployeeUpdate = {
|
|||
middleName?: string | null;
|
||||
middleNameEN?: string | null;
|
||||
lastName?: string;
|
||||
lastNameEN: string;
|
||||
lastNameEN?: string;
|
||||
|
||||
addressEN?: string;
|
||||
address?: string;
|
||||
|
|
@ -154,6 +157,8 @@ export class EmployeeController extends Controller {
|
|||
@Query() customerBranchId?: string,
|
||||
@Query() status?: Status,
|
||||
@Query() query: string = "",
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
) {
|
||||
return await prisma.employee
|
||||
.groupBy({
|
||||
|
|
@ -163,13 +168,13 @@ export class EmployeeController extends Controller {
|
|||
OR: queryOrNot<Prisma.EmployeeWhereInput[]>(query, [
|
||||
{
|
||||
employeePassport: {
|
||||
some: { number: { contains: query } },
|
||||
some: { number: { contains: query, mode: "insensitive" } },
|
||||
},
|
||||
},
|
||||
{ firstName: { contains: query } },
|
||||
{ firstNameEN: { contains: query } },
|
||||
{ lastName: { contains: query } },
|
||||
{ lastNameEN: { contains: query } },
|
||||
{ firstName: { contains: query, mode: "insensitive" } },
|
||||
{ firstNameEN: { contains: query, mode: "insensitive" } },
|
||||
{ lastName: { contains: query, mode: "insensitive" } },
|
||||
{ lastNameEN: { contains: query, mode: "insensitive" } },
|
||||
...whereAddressQuery(query),
|
||||
]),
|
||||
AND: {
|
||||
|
|
@ -183,6 +188,7 @@ export class EmployeeController extends Controller {
|
|||
},
|
||||
},
|
||||
},
|
||||
...whereDateQuery(startDate, endDate),
|
||||
},
|
||||
})
|
||||
.then((res) =>
|
||||
|
|
@ -208,6 +214,8 @@ export class EmployeeController extends Controller {
|
|||
@Query() page: number = 1,
|
||||
@Query() pageSize: number = 30,
|
||||
@Query() activeOnly?: boolean,
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
) {
|
||||
return this.listByCriteria(
|
||||
req,
|
||||
|
|
@ -222,6 +230,8 @@ export class EmployeeController extends Controller {
|
|||
page,
|
||||
pageSize,
|
||||
activeOnly,
|
||||
startDate,
|
||||
endDate,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -240,6 +250,8 @@ export class EmployeeController extends Controller {
|
|||
@Query() page: number = 1,
|
||||
@Query() pageSize: number = 30,
|
||||
@Query() activeOnly?: boolean,
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
@Body()
|
||||
body?: {
|
||||
passport?: string[];
|
||||
|
|
@ -252,13 +264,13 @@ export class EmployeeController extends Controller {
|
|||
...(queryOrNot<Prisma.EmployeeWhereInput[]>(query, [
|
||||
{
|
||||
employeePassport: {
|
||||
some: { number: { contains: query } },
|
||||
some: { number: { contains: query, mode: "insensitive" } },
|
||||
},
|
||||
},
|
||||
{ firstName: { contains: query } },
|
||||
{ firstNameEN: { contains: query } },
|
||||
{ lastName: { contains: query } },
|
||||
{ lastNameEN: { contains: query } },
|
||||
{ firstName: { contains: query, mode: "insensitive" } },
|
||||
{ firstNameEN: { contains: query, mode: "insensitive" } },
|
||||
{ lastName: { contains: query, mode: "insensitive" } },
|
||||
{ lastNameEN: { contains: query, mode: "insensitive" } },
|
||||
...whereAddressQuery(query),
|
||||
]) ?? []),
|
||||
...(queryOrNot<Prisma.EmployeeWhereInput[]>(!!body, [
|
||||
|
|
@ -288,6 +300,7 @@ export class EmployeeController extends Controller {
|
|||
subDistrict: zipCode ? { zipCode } : undefined,
|
||||
gender,
|
||||
},
|
||||
...whereDateQuery(startDate, endDate),
|
||||
} satisfies Prisma.EmployeeWhereInput;
|
||||
|
||||
const [result, total] = await prisma.$transaction([
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ type EmployeePassportPayload = {
|
|||
|
||||
workerStatus: string;
|
||||
nationality: string;
|
||||
otherNationality: string;
|
||||
namePrefix?: string | null;
|
||||
firstName: string;
|
||||
firstNameEN: string;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import HttpError from "../interfaces/http-error";
|
|||
import HttpStatus from "../interfaces/http-status";
|
||||
import { notFoundError } from "../utils/error";
|
||||
import { filterStatus } from "../services/prisma";
|
||||
import { queryOrNot } from "../utils/relation";
|
||||
import { queryOrNot, whereDateQuery } from "../utils/relation";
|
||||
|
||||
type WorkflowPayload = {
|
||||
name: string;
|
||||
|
|
@ -37,6 +37,7 @@ type WorkflowPayload = {
|
|||
attributes?: { [key: string]: any };
|
||||
responsiblePersonId?: string[];
|
||||
responsibleInstitution?: string[];
|
||||
responsibleGroup?: string[];
|
||||
messengerByArea?: boolean;
|
||||
}[];
|
||||
registeredBranchId?: string;
|
||||
|
|
@ -58,13 +59,15 @@ export class FlowTemplateController extends Controller {
|
|||
@Query() status?: Status,
|
||||
@Query() query = "",
|
||||
@Query() activeOnly?: boolean,
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
) {
|
||||
const where = {
|
||||
OR: queryOrNot(query, [
|
||||
{ name: { contains: query } },
|
||||
{ name: { contains: query, mode: "insensitive" } },
|
||||
{
|
||||
step: {
|
||||
some: { name: { contains: query } },
|
||||
some: { name: { contains: query, mode: "insensitive" } },
|
||||
},
|
||||
},
|
||||
]),
|
||||
|
|
@ -74,6 +77,7 @@ export class FlowTemplateController extends Controller {
|
|||
OR: permissionCondCompany(req.user, { activeOnly: true }),
|
||||
},
|
||||
},
|
||||
...whereDateQuery(startDate, endDate),
|
||||
} satisfies Prisma.WorkflowTemplateWhereInput;
|
||||
const [result, total] = await prisma.$transaction([
|
||||
prisma.workflowTemplate.findMany({
|
||||
|
|
@ -86,6 +90,7 @@ export class FlowTemplateController extends Controller {
|
|||
include: { user: true },
|
||||
},
|
||||
responsibleInstitution: true,
|
||||
responsibleGroup: true,
|
||||
},
|
||||
orderBy: { order: "asc" },
|
||||
},
|
||||
|
|
@ -103,6 +108,7 @@ export class FlowTemplateController extends Controller {
|
|||
step: r.step.map((v) => ({
|
||||
...v,
|
||||
responsibleInstitution: v.responsibleInstitution.map((institution) => institution.group),
|
||||
responsibleGroup: v.responsibleGroup.map((group) => group.group),
|
||||
})),
|
||||
})),
|
||||
page,
|
||||
|
|
@ -123,6 +129,7 @@ export class FlowTemplateController extends Controller {
|
|||
include: { user: true },
|
||||
},
|
||||
responsibleInstitution: true,
|
||||
responsibleGroup: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -137,6 +144,7 @@ export class FlowTemplateController extends Controller {
|
|||
step: record.step.map((v) => ({
|
||||
...v,
|
||||
responsibleInstitution: v.responsibleInstitution.map((institution) => institution.group),
|
||||
responsibleGroup: v.responsibleGroup.map((group) => group.group),
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
|
@ -212,6 +220,9 @@ export class FlowTemplateController extends Controller {
|
|||
responsibleInstitution: {
|
||||
create: v.responsibleInstitution?.map((group) => ({ group })),
|
||||
},
|
||||
responsibleGroup: {
|
||||
create: v.responsibleGroup?.map((group) => ({ group })),
|
||||
},
|
||||
})),
|
||||
},
|
||||
},
|
||||
|
|
@ -292,6 +303,10 @@ export class FlowTemplateController extends Controller {
|
|||
deleteMany: {},
|
||||
create: v.responsibleInstitution?.map((group) => ({ group })),
|
||||
},
|
||||
responsibleGroup: {
|
||||
deleteMany: {},
|
||||
create: v.responsibleGroup?.map((group) => ({ group })),
|
||||
},
|
||||
},
|
||||
})),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import {
|
|||
} from "tsoa";
|
||||
import prisma from "../db";
|
||||
import { isUsedError, notFoundError } from "../utils/error";
|
||||
import { queryOrNot } from "../utils/relation";
|
||||
import { queryOrNot, whereDateQuery } from "../utils/relation";
|
||||
import { RequestWithUser } from "../interfaces/user";
|
||||
import { deleteFile, fileLocation, getFile, getPresigned, listFile, setFile } from "../utils/minio";
|
||||
import HttpError from "../interfaces/http-error";
|
||||
|
|
@ -108,8 +108,19 @@ export class InstitutionController extends Controller {
|
|||
@Query() status?: Status,
|
||||
@Query() activeOnly?: boolean,
|
||||
@Query() group?: string,
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
) {
|
||||
return this.getInstitutionListByCriteria(query, page, pageSize, status, activeOnly, group);
|
||||
return this.getInstitutionListByCriteria(
|
||||
query,
|
||||
page,
|
||||
pageSize,
|
||||
status,
|
||||
activeOnly,
|
||||
group,
|
||||
startDate,
|
||||
endDate,
|
||||
);
|
||||
}
|
||||
|
||||
@Post("list")
|
||||
|
|
@ -122,6 +133,8 @@ export class InstitutionController extends Controller {
|
|||
@Query() status?: Status,
|
||||
@Query() activeOnly?: boolean,
|
||||
@Query() group?: string,
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
@Body()
|
||||
body?: {
|
||||
group?: string[];
|
||||
|
|
@ -131,9 +144,10 @@ export class InstitutionController extends Controller {
|
|||
...filterStatus(activeOnly ? Status.ACTIVE : status),
|
||||
group: body?.group ? { in: body.group } : group,
|
||||
OR: queryOrNot<Prisma.InstitutionWhereInput[]>(query, [
|
||||
{ name: { contains: query } },
|
||||
{ name: { contains: query, mode: "insensitive" } },
|
||||
{ code: { contains: query, mode: "insensitive" } },
|
||||
]),
|
||||
...whereDateQuery(startDate, endDate),
|
||||
} satisfies Prisma.InstitutionWhereInput;
|
||||
|
||||
const [result, total] = await prisma.$transaction([
|
||||
|
|
@ -178,6 +192,7 @@ export class InstitutionController extends Controller {
|
|||
body: InstitutionPayload & {
|
||||
status?: Status;
|
||||
},
|
||||
@Request() req: RequestWithUser,
|
||||
) {
|
||||
return await prisma.$transaction(async (tx) => {
|
||||
const last = await tx.runningNo.upsert({
|
||||
|
|
@ -194,6 +209,8 @@ export class InstitutionController extends Controller {
|
|||
return await tx.institution.create({
|
||||
include: {
|
||||
bank: true,
|
||||
createdBy: true,
|
||||
updatedBy: true,
|
||||
},
|
||||
data: {
|
||||
...body,
|
||||
|
|
@ -204,6 +221,8 @@ export class InstitutionController extends Controller {
|
|||
data: body.bank ?? [],
|
||||
},
|
||||
},
|
||||
createdByUserId: req.user.sub,
|
||||
updatedByUserId: req.user.sub,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import {
|
|||
createPermCondition,
|
||||
} from "../services/permission";
|
||||
import { PaymentStatus } from "../generated/kysely/types";
|
||||
import { whereDateQuery } from "../utils/relation";
|
||||
|
||||
type InvoicePayload = {
|
||||
quotationId: string;
|
||||
|
|
@ -95,23 +96,25 @@ export class InvoiceController extends Controller {
|
|||
@Query() quotationId?: string,
|
||||
@Query() debitNoteId?: string,
|
||||
@Query() pay?: boolean,
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
) {
|
||||
const where: Prisma.InvoiceWhereInput = {
|
||||
OR: [
|
||||
{ code: { contains: query, mode: "insensitive" } },
|
||||
{ quotation: { workName: { contains: query } } },
|
||||
{ quotation: { workName: { contains: query, mode: "insensitive" } } },
|
||||
{
|
||||
quotation: {
|
||||
customerBranch: {
|
||||
OR: [
|
||||
{ code: { contains: query, mode: "insensitive" } },
|
||||
{ customerName: { contains: query } },
|
||||
{ registerName: { contains: query } },
|
||||
{ registerNameEN: { contains: query } },
|
||||
{ firstName: { contains: query } },
|
||||
{ firstNameEN: { contains: query } },
|
||||
{ lastName: { contains: query } },
|
||||
{ lastNameEN: { contains: query } },
|
||||
{ customerName: { contains: query, mode: "insensitive" } },
|
||||
{ registerName: { contains: query, mode: "insensitive" } },
|
||||
{ registerNameEN: { contains: query, mode: "insensitive" } },
|
||||
{ firstName: { contains: query, mode: "insensitive" } },
|
||||
{ firstNameEN: { contains: query, mode: "insensitive" } },
|
||||
{ lastName: { contains: query, mode: "insensitive" } },
|
||||
{ lastNameEN: { contains: query, mode: "insensitive" } },
|
||||
],
|
||||
},
|
||||
},
|
||||
|
|
@ -132,6 +135,7 @@ export class InvoiceController extends Controller {
|
|||
OR: permissionCondCompany(req.user),
|
||||
},
|
||||
},
|
||||
...whereDateQuery(startDate, endDate),
|
||||
};
|
||||
|
||||
const [result, total] = await prisma.$transaction([
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import {
|
|||
Security,
|
||||
Tags,
|
||||
Query,
|
||||
UploadedFile,
|
||||
} from "tsoa";
|
||||
import { Prisma, Product, Status } from "@prisma/client";
|
||||
|
||||
|
|
@ -27,7 +28,8 @@ import { isSystem } from "../utils/keycloak";
|
|||
import { filterStatus } from "../services/prisma";
|
||||
import { deleteFile, deleteFolder, fileLocation, getFile, listFile, setFile } from "../utils/minio";
|
||||
import { isUsedError, notFoundError, relationError } from "../utils/error";
|
||||
import { queryOrNot } from "../utils/relation";
|
||||
import { queryOrNot, whereDateQuery } from "../utils/relation";
|
||||
import spreadsheet from "../utils/spreadsheet";
|
||||
|
||||
const MANAGE_ROLES = [
|
||||
"system",
|
||||
|
|
@ -139,6 +141,8 @@ export class ProductController extends Controller {
|
|||
@Query() orderField?: keyof Product,
|
||||
@Query() orderBy?: "asc" | "desc",
|
||||
@Query() activeOnly?: boolean,
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
) {
|
||||
// NOTE: will be used to scope product within product group that is shared between branch but not company when select shared product if user is system
|
||||
const targetGroup =
|
||||
|
|
@ -154,8 +158,8 @@ export class ProductController extends Controller {
|
|||
|
||||
const where = {
|
||||
OR: queryOrNot<Prisma.ProductWhereInput[]>(query, [
|
||||
{ name: { contains: query } },
|
||||
{ detail: { contains: query } },
|
||||
{ name: { contains: query, mode: "insensitive" } },
|
||||
{ detail: { contains: query, mode: "insensitive" } },
|
||||
{ code: { contains: query, mode: "insensitive" } },
|
||||
]),
|
||||
AND: {
|
||||
|
|
@ -194,6 +198,7 @@ export class ProductController extends Controller {
|
|||
: []),
|
||||
],
|
||||
},
|
||||
...whereDateQuery(startDate, endDate),
|
||||
} satisfies Prisma.ProductWhereInput;
|
||||
|
||||
const [result, total] = await prisma.$transaction([
|
||||
|
|
@ -444,6 +449,146 @@ export class ProductController extends Controller {
|
|||
where: { id: productId },
|
||||
});
|
||||
}
|
||||
|
||||
@Post("import-product")
|
||||
@Security("keycloak", MANAGE_ROLES)
|
||||
async importProduct(
|
||||
@Request() req: RequestWithUser,
|
||||
@UploadedFile() file: Express.Multer.File,
|
||||
@Query() productGroupId: string,
|
||||
) {
|
||||
if (!file?.buffer) throw notFoundError("File");
|
||||
|
||||
const buffer = new Uint8Array(file.buffer).buffer;
|
||||
const dataFile = await spreadsheet.readExcel(buffer, {
|
||||
header: true,
|
||||
worksheet: "Sheet1",
|
||||
});
|
||||
|
||||
let dataName: string[] = [];
|
||||
const data = dataFile.map((item: any) => {
|
||||
dataName.push(item.name);
|
||||
return {
|
||||
...item,
|
||||
expenseType:
|
||||
item.expenseType === "ค่าธรรมเนียม"
|
||||
? "fee"
|
||||
: item.expenseType === "ค่าบริการ"
|
||||
? "serviceFee"
|
||||
: "processingFee",
|
||||
shared: item.shared === "ใช่" ? true : false,
|
||||
price:
|
||||
typeof item.price === "number"
|
||||
? item.price
|
||||
: +parseFloat(item.price?.replace(",", "") || "0").toFixed(6),
|
||||
calcVat: item.calcVat === "ใช่" ? true : false,
|
||||
vatIncluded: item.vatIncluded === "รวม" ? true : false,
|
||||
agentPrice:
|
||||
typeof item.agentPrice === "number"
|
||||
? item.agentPrice
|
||||
: +parseFloat(item.agentPrice?.replace(",", "") || "0").toFixed(6),
|
||||
agentPriceCalcVat: item.agentPriceCalcVat === "ใช่" ? true : false,
|
||||
agentPriceVatIncluded: item.agentPriceVatIncluded === "รวม" ? true : false,
|
||||
serviceCharge:
|
||||
typeof item.serviceCharge === "number"
|
||||
? item.serviceCharge
|
||||
: +parseFloat(item.serviceCharge?.replace(",", "") || "0").toFixed(6),
|
||||
serviceChargeCalcVat: item.serviceChargeCalcVat === "ใช่" ? true : false,
|
||||
serviceChargeVatIncluded: item.serviceChargeVatIncluded === "รวม" ? true : false,
|
||||
};
|
||||
});
|
||||
|
||||
const [productGroup, productSameName] = await prisma.$transaction([
|
||||
prisma.productGroup.findFirst({
|
||||
include: {
|
||||
registeredBranch: {
|
||||
include: branchRelationPermInclude(req.user),
|
||||
},
|
||||
createdBy: true,
|
||||
updatedBy: true,
|
||||
},
|
||||
where: { id: productGroupId },
|
||||
}),
|
||||
prisma.product.findMany({
|
||||
where: {
|
||||
productGroup: {
|
||||
id: productGroupId,
|
||||
registeredBranch: {
|
||||
OR: permissionCondCompany(req.user),
|
||||
},
|
||||
},
|
||||
name: { in: dataName },
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
if (!productGroup) throw relationError("Product Group");
|
||||
|
||||
await permissionCheck(req.user, productGroup.registeredBranch);
|
||||
let dataProduct: ProductCreate[] = [];
|
||||
|
||||
const record = await prisma.$transaction(
|
||||
async (tx) => {
|
||||
const branch = productGroup.registeredBranch;
|
||||
const company = (branch.headOffice || branch).code;
|
||||
|
||||
await Promise.all(
|
||||
data.map(async (item) => {
|
||||
const dataDuplicate = productSameName.some(
|
||||
(v) => v.code.slice(0, -3) === item.code.toUpperCase() && v.name === item.name,
|
||||
);
|
||||
|
||||
if (!dataDuplicate) {
|
||||
const last = await tx.runningNo.upsert({
|
||||
where: {
|
||||
key: `PRODUCT_${company}_${item.code.toLocaleUpperCase()}`,
|
||||
},
|
||||
create: {
|
||||
key: `PRODUCT_${company}_${item.code.toLocaleUpperCase()}`,
|
||||
value: 1,
|
||||
},
|
||||
update: { value: { increment: 1 } },
|
||||
});
|
||||
|
||||
dataProduct.push({
|
||||
...item,
|
||||
code: `${item.code.toLocaleUpperCase()}${last.value.toString().padStart(3, "0")}`,
|
||||
createdByUserId: req.user.sub,
|
||||
updatedByUserId: req.user.sub,
|
||||
productGroupId: productGroupId,
|
||||
});
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
return await prisma.product.createManyAndReturn({
|
||||
data: dataProduct,
|
||||
include: {
|
||||
createdBy: true,
|
||||
updatedBy: true,
|
||||
},
|
||||
});
|
||||
},
|
||||
{
|
||||
isolationLevel: Prisma.TransactionIsolationLevel.Serializable,
|
||||
},
|
||||
);
|
||||
|
||||
if (productGroup.status === "CREATED") {
|
||||
await prisma.productGroup.update({
|
||||
include: {
|
||||
createdBy: true,
|
||||
updatedBy: true,
|
||||
},
|
||||
where: { id: productGroupId },
|
||||
data: { status: Status.ACTIVE },
|
||||
});
|
||||
}
|
||||
|
||||
this.setStatus(HttpStatus.CREATED);
|
||||
|
||||
return record;
|
||||
}
|
||||
}
|
||||
|
||||
@Route("api/v1/product/{productId}")
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import {
|
|||
} from "../services/permission";
|
||||
import { filterStatus } from "../services/prisma";
|
||||
import { isUsedError, notFoundError, relationError } from "../utils/error";
|
||||
import { queryOrNot } from "../utils/relation";
|
||||
import { queryOrNot, whereDateQuery } from "../utils/relation";
|
||||
|
||||
type ProductGroupCreate = {
|
||||
name: string;
|
||||
|
|
@ -90,11 +90,13 @@ export class ProductGroup extends Controller {
|
|||
@Query() page: number = 1,
|
||||
@Query() pageSize: number = 30,
|
||||
@Query() activeOnly?: boolean,
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
) {
|
||||
const where = {
|
||||
OR: queryOrNot<Prisma.ProductGroupWhereInput[]>(query, [
|
||||
{ name: { contains: query } },
|
||||
{ detail: { contains: query } },
|
||||
{ name: { contains: query, mode: "insensitive" } },
|
||||
{ detail: { contains: query, mode: "insensitive" } },
|
||||
{ code: { contains: query, mode: "insensitive" } },
|
||||
]),
|
||||
AND: [
|
||||
|
|
@ -105,6 +107,7 @@ export class ProductGroup extends Controller {
|
|||
: { OR: permissionCond(req.user, { activeOnly }) },
|
||||
},
|
||||
],
|
||||
...whereDateQuery(startDate, endDate),
|
||||
} satisfies Prisma.ProductGroupWhereInput;
|
||||
|
||||
const [result, total] = await prisma.$transaction([
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import HttpError from "../interfaces/http-error";
|
|||
import HttpStatus from "../interfaces/http-status";
|
||||
import { notFoundError } from "../utils/error";
|
||||
import { filterStatus } from "../services/prisma";
|
||||
import { queryOrNot } from "../utils/relation";
|
||||
import { queryOrNot, whereDateQuery } from "../utils/relation";
|
||||
|
||||
type PropertyPayload = {
|
||||
name: string;
|
||||
|
|
@ -49,15 +49,21 @@ export class PropertiesController extends Controller {
|
|||
@Query() status?: Status,
|
||||
@Query() query = "",
|
||||
@Query() activeOnly?: boolean,
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
) {
|
||||
const where = {
|
||||
OR: queryOrNot(query, [{ name: { contains: query } }, { nameEN: { contains: query } }]),
|
||||
OR: queryOrNot(query, [
|
||||
{ name: { contains: query, mode: "insensitive" } },
|
||||
{ nameEN: { contains: query, mode: "insensitive" } },
|
||||
]),
|
||||
AND: {
|
||||
...filterStatus(activeOnly ? Status.ACTIVE : status),
|
||||
registeredBranch: {
|
||||
OR: permissionCondCompany(req.user, { activeOnly: true }),
|
||||
},
|
||||
},
|
||||
...whereDateQuery(startDate, endDate),
|
||||
} satisfies Prisma.PropertyWhereInput;
|
||||
const [result, total] = await prisma.$transaction([
|
||||
prisma.property.findMany({
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { Prisma } from "@prisma/client";
|
|||
import { notFoundError } from "../utils/error";
|
||||
import { RequestWithUser } from "../interfaces/user";
|
||||
import { createPermCondition } from "../services/permission";
|
||||
import { whereDateQuery } from "../utils/relation";
|
||||
|
||||
const permissionCondCompany = createPermCondition((_) => true);
|
||||
|
||||
|
|
@ -21,6 +22,8 @@ export class ReceiptController extends Controller {
|
|||
@Query() quotationId?: string,
|
||||
@Query() debitNoteId?: string,
|
||||
@Query() debitNoteOnly?: boolean,
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
) {
|
||||
const where: Prisma.PaymentWhereInput = {
|
||||
paymentStatus: "PaymentSuccess",
|
||||
|
|
@ -33,6 +36,7 @@ export class ReceiptController extends Controller {
|
|||
},
|
||||
},
|
||||
},
|
||||
...whereDateQuery(startDate, endDate),
|
||||
};
|
||||
|
||||
const [result, total] = await prisma.$transaction([
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ import {
|
|||
listFile,
|
||||
setFile,
|
||||
} from "../utils/minio";
|
||||
import { queryOrNot } from "../utils/relation";
|
||||
import { queryOrNot, whereDateQuery } from "../utils/relation";
|
||||
|
||||
const MANAGE_ROLES = [
|
||||
"system",
|
||||
|
|
@ -164,6 +164,8 @@ export class ServiceController extends Controller {
|
|||
@Query() fullDetail?: boolean,
|
||||
@Query() activeOnly?: boolean,
|
||||
@Query() shared?: boolean,
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
) {
|
||||
// NOTE: will be used to scope product within product group that is shared between branch but not company when select shared product if user is system
|
||||
const targetGroup =
|
||||
|
|
@ -179,8 +181,8 @@ export class ServiceController extends Controller {
|
|||
|
||||
const where = {
|
||||
OR: queryOrNot<Prisma.ServiceWhereInput[]>(query, [
|
||||
{ name: { contains: query } },
|
||||
{ detail: { contains: query } },
|
||||
{ name: { contains: query, mode: "insensitive" } },
|
||||
{ detail: { contains: query, mode: "insensitive" } },
|
||||
{ code: { contains: query, mode: "insensitive" } },
|
||||
]),
|
||||
AND: {
|
||||
|
|
@ -219,6 +221,7 @@ export class ServiceController extends Controller {
|
|||
: []),
|
||||
],
|
||||
},
|
||||
...whereDateQuery(startDate, endDate),
|
||||
} satisfies Prisma.ServiceWhereInput;
|
||||
|
||||
const [result, total] = await prisma.$transaction([
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import prisma from "../db";
|
|||
import { RequestWithUser } from "../interfaces/user";
|
||||
import HttpStatus from "../interfaces/http-status";
|
||||
import { isUsedError, notFoundError } from "../utils/error";
|
||||
import { whereDateQuery } from "../utils/relation";
|
||||
|
||||
type WorkCreate = {
|
||||
order: number;
|
||||
|
|
@ -45,9 +46,12 @@ export class WorkController extends Controller {
|
|||
@Query() query: string = "",
|
||||
@Query() page: number = 1,
|
||||
@Query() pageSize: number = 30,
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
) {
|
||||
const where = {
|
||||
OR: [{ name: { contains: query }, serviceId: baseOnly ? null : undefined }],
|
||||
...whereDateQuery(startDate, endDate),
|
||||
} satisfies Prisma.WorkWhereInput;
|
||||
|
||||
const [result, total] = await prisma.$transaction([
|
||||
|
|
|
|||
|
|
@ -105,6 +105,7 @@ export class QuotationPayment extends Controller {
|
|||
async updatePayment(
|
||||
@Path() paymentId: string,
|
||||
@Body() body: { amount?: number; date?: Date; paymentStatus?: PaymentStatus },
|
||||
@Request() req: RequestWithUser,
|
||||
) {
|
||||
const record = await prisma.payment.findUnique({
|
||||
where: { id: paymentId },
|
||||
|
|
@ -164,6 +165,7 @@ export class QuotationPayment extends Controller {
|
|||
code: lastReceipt
|
||||
? `RE${year}${month}${lastReceipt.value.toString().padStart(6, "0")}`
|
||||
: undefined,
|
||||
updatedByUserId: req.user.sub,
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import {
|
|||
import { isSystem } from "../utils/keycloak";
|
||||
import { isUsedError, notFoundError, relationError } from "../utils/error";
|
||||
import { precisionRound } from "../utils/arithmetic";
|
||||
import { queryOrNot } from "../utils/relation";
|
||||
import { queryOrNot, whereDateQuery } from "../utils/relation";
|
||||
import { deleteFile, fileLocation, getFile, getPresigned, listFile, setFile } from "../utils/minio";
|
||||
import HttpError from "../interfaces/http-error";
|
||||
import HttpStatus from "../interfaces/http-status";
|
||||
|
|
@ -55,13 +55,14 @@ type QuotationCreate = {
|
|||
dateOfBirth: Date;
|
||||
gender: string;
|
||||
nationality: string;
|
||||
otherNationality?: string;
|
||||
namePrefix?: string;
|
||||
firstName: string;
|
||||
firstNameEN: string;
|
||||
middleName?: string;
|
||||
middleNameEN?: string;
|
||||
lastName: string;
|
||||
lastNameEN: string;
|
||||
lastNameEN?: string;
|
||||
}
|
||||
)[];
|
||||
|
||||
|
|
@ -112,14 +113,15 @@ type QuotationUpdate = {
|
|||
dateOfBirth: Date;
|
||||
gender: string;
|
||||
nationality: string;
|
||||
otherNationality?: string;
|
||||
|
||||
namePrefix?: string;
|
||||
firstName: string;
|
||||
firstName?: string;
|
||||
firstNameEN: string;
|
||||
middleName?: string;
|
||||
middleNameEN?: string;
|
||||
lastName: string;
|
||||
lastNameEN: string;
|
||||
lastName?: string;
|
||||
lastNameEN?: string;
|
||||
}
|
||||
)[];
|
||||
|
||||
|
|
@ -206,20 +208,22 @@ export class QuotationController extends Controller {
|
|||
@Query() forDebitNote?: boolean,
|
||||
@Query() code?: string,
|
||||
@Query() query = "",
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
) {
|
||||
const where = {
|
||||
OR: queryOrNot<Prisma.QuotationWhereInput[]>(query, [
|
||||
{ code: { contains: query, mode: "insensitive" } },
|
||||
{ workName: { contains: query } },
|
||||
{ workName: { contains: query, mode: "insensitive" } },
|
||||
{
|
||||
customerBranch: {
|
||||
OR: [
|
||||
{ code: { contains: query, mode: "insensitive" } },
|
||||
{ customerName: { contains: query } },
|
||||
{ firstName: { contains: query } },
|
||||
{ firstNameEN: { contains: query } },
|
||||
{ lastName: { contains: query } },
|
||||
{ lastNameEN: { contains: query } },
|
||||
{ customerName: { contains: query, mode: "insensitive" } },
|
||||
{ firstName: { contains: query, mode: "insensitive" } },
|
||||
{ firstNameEN: { contains: query, mode: "insensitive" } },
|
||||
{ lastName: { contains: query, mode: "insensitive" } },
|
||||
{ lastNameEN: { contains: query, mode: "insensitive" } },
|
||||
],
|
||||
},
|
||||
},
|
||||
|
|
@ -253,6 +257,7 @@ export class QuotationController extends Controller {
|
|||
},
|
||||
}
|
||||
: undefined,
|
||||
...whereDateQuery(startDate, endDate),
|
||||
} satisfies Prisma.QuotationWhereInput;
|
||||
|
||||
const [result, total] = await prisma.$transaction([
|
||||
|
|
@ -1005,6 +1010,7 @@ export class QuotationActionController extends Controller {
|
|||
dateOfBirth: Date;
|
||||
gender: string;
|
||||
nationality: string;
|
||||
otherNationality?: string;
|
||||
namePrefix?: string;
|
||||
firstName: string;
|
||||
firstNameEN: string;
|
||||
|
|
@ -1027,6 +1033,7 @@ export class QuotationActionController extends Controller {
|
|||
dateOfBirth: Date;
|
||||
gender: string;
|
||||
nationality: string;
|
||||
otherNationality?: string;
|
||||
namePrefix?: string;
|
||||
firstName: string;
|
||||
firstNameEN: string;
|
||||
|
|
|
|||
|
|
@ -27,11 +27,12 @@ import {
|
|||
createPermCheck,
|
||||
createPermCondition,
|
||||
} from "../services/permission";
|
||||
import { queryOrNot } from "../utils/relation";
|
||||
import { queryOrNot, whereDateQuery } from "../utils/relation";
|
||||
import { notFoundError } from "../utils/error";
|
||||
import { deleteFile, fileLocation, getFile, getPresigned, listFile, setFile } from "../utils/minio";
|
||||
import HttpError from "../interfaces/http-error";
|
||||
import HttpStatus from "../interfaces/http-status";
|
||||
import { getGroupUser } from "../services/keycloak";
|
||||
|
||||
// User in company can edit.
|
||||
const permissionCheck = createPermCheck((_) => true);
|
||||
|
|
@ -80,6 +81,9 @@ export class RequestDataController extends Controller {
|
|||
@Query() requestDataStatus?: RequestDataStatus,
|
||||
@Query() quotationId?: string,
|
||||
@Query() code?: string,
|
||||
@Query() incomplete?: boolean,
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
) {
|
||||
const where = {
|
||||
OR: queryOrNot<Prisma.RequestDataWhereInput[]>(query, [
|
||||
|
|
@ -91,34 +95,40 @@ export class RequestDataController extends Controller {
|
|||
customerBranch: {
|
||||
OR: [
|
||||
{ code: { contains: query, mode: "insensitive" } },
|
||||
{ customerName: { contains: query } },
|
||||
{ registerName: { contains: query } },
|
||||
{ registerNameEN: { contains: query } },
|
||||
{ firstName: { contains: query } },
|
||||
{ firstNameEN: { contains: query } },
|
||||
{ lastName: { contains: query } },
|
||||
{ lastNameEN: { contains: query } },
|
||||
{ customerName: { contains: query, mode: "insensitive" } },
|
||||
{ registerName: { contains: query, mode: "insensitive" } },
|
||||
{ registerNameEN: { contains: query, mode: "insensitive" } },
|
||||
{ firstName: { contains: query, mode: "insensitive" } },
|
||||
{ firstNameEN: { contains: query, mode: "insensitive" } },
|
||||
{ lastName: { contains: query, mode: "insensitive" } },
|
||||
{ lastNameEN: { contains: query, mode: "insensitive" } },
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
employee: {
|
||||
OR: [
|
||||
{
|
||||
employeePassport: {
|
||||
some: { number: { contains: query } },
|
||||
some: { number: { contains: query, mode: "insensitive" } },
|
||||
},
|
||||
},
|
||||
{ code: { contains: query, mode: "insensitive" } },
|
||||
{ firstName: { contains: query } },
|
||||
{ firstNameEN: { contains: query } },
|
||||
{ lastName: { contains: query } },
|
||||
{ lastNameEN: { contains: query } },
|
||||
{ firstName: { contains: query, mode: "insensitive" } },
|
||||
{ firstNameEN: { contains: query, mode: "insensitive" } },
|
||||
{ lastName: { contains: query, mode: "insensitive" } },
|
||||
{ lastNameEN: { contains: query, mode: "insensitive" } },
|
||||
],
|
||||
},
|
||||
},
|
||||
]),
|
||||
code,
|
||||
requestDataStatus,
|
||||
requestDataStatus: incomplete
|
||||
? {
|
||||
notIn: [RequestDataStatus.Completed, RequestDataStatus.Canceled],
|
||||
}
|
||||
: requestDataStatus,
|
||||
requestWork: responsibleOnly
|
||||
? {
|
||||
some: {
|
||||
|
|
@ -127,9 +137,24 @@ export class RequestDataController extends Controller {
|
|||
workflow: {
|
||||
step: {
|
||||
some: {
|
||||
responsiblePerson: {
|
||||
some: { userId: req.user.sub },
|
||||
},
|
||||
OR: [
|
||||
{
|
||||
responsiblePerson: {
|
||||
some: { userId: req.user.sub },
|
||||
},
|
||||
},
|
||||
{
|
||||
responsibleGroup: {
|
||||
some: {
|
||||
group: {
|
||||
in: await getGroupUser(req.user.sub).then((r) =>
|
||||
r.map(({ name }: { name: string }) => name),
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -142,6 +167,7 @@ export class RequestDataController extends Controller {
|
|||
id: quotationId,
|
||||
registeredBranch: { OR: permissionCond(req.user) },
|
||||
},
|
||||
...whereDateQuery(startDate, endDate),
|
||||
} satisfies Prisma.RequestDataWhereInput;
|
||||
|
||||
const [result, total] = await prisma.$transaction([
|
||||
|
|
@ -164,6 +190,7 @@ export class RequestDataController extends Controller {
|
|||
include: { user: true },
|
||||
},
|
||||
responsibleInstitution: true,
|
||||
responsibleGroup: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -182,6 +209,20 @@ export class RequestDataController extends Controller {
|
|||
employeePassport: {
|
||||
orderBy: { expireDate: "desc" },
|
||||
},
|
||||
customerBranch: {
|
||||
include: {
|
||||
province: {
|
||||
include: {
|
||||
employmentOffice: true,
|
||||
},
|
||||
},
|
||||
district: {
|
||||
include: {
|
||||
employmentOffice: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -192,7 +233,24 @@ export class RequestDataController extends Controller {
|
|||
prisma.requestData.count({ where }),
|
||||
]);
|
||||
|
||||
return { result, page, pageSize, total };
|
||||
const dataRequestData = result.map((item) => {
|
||||
const employee = item.employee;
|
||||
const dataOffice =
|
||||
employee.customerBranch.district?.employmentOffice.at(0) ??
|
||||
employee.customerBranch.province?.employmentOffice.at(0);
|
||||
|
||||
return {
|
||||
...item,
|
||||
dataOffice,
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
result: dataRequestData,
|
||||
page,
|
||||
pageSize,
|
||||
total,
|
||||
};
|
||||
}
|
||||
|
||||
@Get("{requestDataId}")
|
||||
|
|
@ -231,7 +289,7 @@ export class RequestDataController extends Controller {
|
|||
return record;
|
||||
}
|
||||
|
||||
@Post("updata-messenger")
|
||||
@Post("update-messenger")
|
||||
@Security("keycloak")
|
||||
async updateRequestData(
|
||||
@Request() req: RequestWithUser,
|
||||
|
|
@ -748,6 +806,7 @@ export class RequestListController extends Controller {
|
|||
include: { user: true },
|
||||
},
|
||||
responsibleInstitution: true,
|
||||
responsibleGroup: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -808,6 +867,7 @@ export class RequestListController extends Controller {
|
|||
include: { user: true },
|
||||
},
|
||||
responsibleInstitution: true,
|
||||
responsibleGroup: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ import {
|
|||
listFile,
|
||||
setFile,
|
||||
} from "../utils/minio";
|
||||
import { queryOrNot } from "../utils/relation";
|
||||
import { queryOrNot, whereDateQuery } from "../utils/relation";
|
||||
|
||||
const MANAGE_ROLES = ["system", "head_of_admin", "admin", "document_checker"];
|
||||
|
||||
|
|
@ -86,6 +86,8 @@ export class TaskController extends Controller {
|
|||
@Query() pageSize = 30,
|
||||
@Query() assignedByUserId?: string,
|
||||
@Query() taskOrderStatus?: TaskOrderStatus,
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
) {
|
||||
return this.getTaskOrderListByCriteria(
|
||||
req,
|
||||
|
|
@ -94,6 +96,8 @@ export class TaskController extends Controller {
|
|||
pageSize,
|
||||
assignedByUserId,
|
||||
taskOrderStatus,
|
||||
startDate,
|
||||
endDate,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -106,6 +110,8 @@ export class TaskController extends Controller {
|
|||
@Query() pageSize = 30,
|
||||
@Query() assignedUserId?: string,
|
||||
@Query() taskOrderStatus?: TaskOrderStatus,
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
@Body() body?: { code?: string[] },
|
||||
) {
|
||||
const where = {
|
||||
|
|
@ -121,10 +127,11 @@ export class TaskController extends Controller {
|
|||
code: body?.code ? { in: body.code } : undefined,
|
||||
OR: queryOrNot(query, [
|
||||
{ code: { contains: query, mode: "insensitive" } },
|
||||
{ taskName: { contains: query } },
|
||||
{ contactName: { contains: query } },
|
||||
{ contactTel: { contains: query } },
|
||||
{ taskName: { contains: query, mode: "insensitive" } },
|
||||
{ contactName: { contains: query, mode: "insensitive" } },
|
||||
{ contactTel: { contains: query, mode: "insensitive" } },
|
||||
]),
|
||||
...whereDateQuery(startDate, endDate),
|
||||
} satisfies Prisma.TaskOrderWhereInput;
|
||||
|
||||
const [result, total] = await prisma.$transaction([
|
||||
|
|
@ -193,6 +200,7 @@ export class TaskController extends Controller {
|
|||
step: {
|
||||
include: {
|
||||
value: true,
|
||||
responsibleGroup: true,
|
||||
responsiblePerson: {
|
||||
include: { user: true },
|
||||
},
|
||||
|
|
@ -690,12 +698,31 @@ export class TaskActionController extends Controller {
|
|||
if (!record) throw notFoundError("Task Order");
|
||||
|
||||
await prisma.$transaction(async (tx) => {
|
||||
const last = await tx.runningNo.upsert({
|
||||
where: {
|
||||
key: "TASK_RI",
|
||||
},
|
||||
create: {
|
||||
key: "TASK_RI",
|
||||
value: 1,
|
||||
},
|
||||
update: {
|
||||
value: { increment: 1 },
|
||||
},
|
||||
});
|
||||
const current = new Date();
|
||||
const year = `${current.getFullYear()}`.padStart(2, "0");
|
||||
const month = `${current.getMonth() + 1}`.padStart(2, "0");
|
||||
|
||||
const code = `RI${year}${month}${last.value.toString().padStart(6, "0")}`;
|
||||
|
||||
await Promise.all([
|
||||
tx.taskOrder.update({
|
||||
where: { id: taskOrderId },
|
||||
data: {
|
||||
urgent: false,
|
||||
taskOrderStatus: TaskOrderStatus.Complete,
|
||||
codeProductReceived: code,
|
||||
userTask: {
|
||||
updateMany: {
|
||||
where: { taskOrderId },
|
||||
|
|
@ -979,6 +1006,8 @@ export class UserTaskController extends Controller {
|
|||
@Query() page = 1,
|
||||
@Query() pageSize = 30,
|
||||
@Query() userTaskStatus?: UserTaskStatus,
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
) {
|
||||
const where = {
|
||||
taskList: {
|
||||
|
|
@ -1021,10 +1050,11 @@ export class UserTaskController extends Controller {
|
|||
: undefined,
|
||||
OR: queryOrNot(query, [
|
||||
{ code: { contains: query, mode: "insensitive" } },
|
||||
{ taskName: { contains: query } },
|
||||
{ contactName: { contains: query } },
|
||||
{ contactTel: { contains: query } },
|
||||
{ taskName: { contains: query, mode: "insensitive" } },
|
||||
{ contactName: { contains: query, mode: "insensitive" } },
|
||||
{ contactTel: { contains: query, mode: "insensitive" } },
|
||||
]),
|
||||
...whereDateQuery(startDate, endDate),
|
||||
} satisfies Prisma.TaskOrderWhereInput;
|
||||
|
||||
const [result, total] = await prisma.$transaction([
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ import {
|
|||
} from "../utils/minio";
|
||||
import { notFoundError } from "../utils/error";
|
||||
import { CreditNotePaybackType, CreditNoteStatus, Prisma, RequestDataStatus } from "@prisma/client";
|
||||
import { queryOrNot } from "../utils/relation";
|
||||
import { queryOrNot, whereDateQuery } from "../utils/relation";
|
||||
import { PaybackStatus, RequestWorkStatus } from "../generated/kysely/types";
|
||||
|
||||
const MANAGE_ROLES = [
|
||||
|
|
@ -121,6 +121,8 @@ export class CreditNoteController extends Controller {
|
|||
@Query() query: string = "",
|
||||
@Query() quotationId?: string,
|
||||
@Query() creditNoteStatus?: CreditNoteStatus,
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
) {
|
||||
return await this.getCreditNoteListByCriteria(
|
||||
req,
|
||||
|
|
@ -129,6 +131,8 @@ export class CreditNoteController extends Controller {
|
|||
query,
|
||||
quotationId,
|
||||
creditNoteStatus,
|
||||
startDate,
|
||||
endDate,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -142,6 +146,8 @@ export class CreditNoteController extends Controller {
|
|||
@Query() query: string = "",
|
||||
@Query() quotationId?: string,
|
||||
@Query() creditNoteStatus?: CreditNoteStatus,
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
@Body() body?: {},
|
||||
) {
|
||||
const where = {
|
||||
|
|
@ -153,17 +159,17 @@ export class CreditNoteController extends Controller {
|
|||
request: {
|
||||
OR: queryOrNot<Prisma.RequestDataWhereInput[]>(query, [
|
||||
{ quotation: { code: { contains: query, mode: "insensitive" } } },
|
||||
{ quotation: { workName: { contains: query } } },
|
||||
{ quotation: { workName: { contains: query, mode: "insensitive" } } },
|
||||
{
|
||||
quotation: {
|
||||
customerBranch: {
|
||||
OR: [
|
||||
{ code: { contains: query, mode: "insensitive" } },
|
||||
{ customerName: { contains: query } },
|
||||
{ firstName: { contains: query } },
|
||||
{ firstNameEN: { contains: query } },
|
||||
{ lastName: { contains: query } },
|
||||
{ lastNameEN: { contains: query } },
|
||||
{ customerName: { contains: query, mode: "insensitive" } },
|
||||
{ firstName: { contains: query, mode: "insensitive" } },
|
||||
{ firstNameEN: { contains: query, mode: "insensitive" } },
|
||||
{ lastName: { contains: query, mode: "insensitive" } },
|
||||
{ lastNameEN: { contains: query, mode: "insensitive" } },
|
||||
],
|
||||
},
|
||||
},
|
||||
|
|
@ -171,14 +177,14 @@ export class CreditNoteController extends Controller {
|
|||
OR: [
|
||||
{
|
||||
employeePassport: {
|
||||
some: { number: { contains: query } },
|
||||
some: { number: { contains: query, mode: "insensitive" } },
|
||||
},
|
||||
},
|
||||
{ code: { contains: query, mode: "insensitive" } },
|
||||
{ firstName: { contains: query } },
|
||||
{ firstNameEN: { contains: query } },
|
||||
{ lastName: { contains: query } },
|
||||
{ lastNameEN: { contains: query } },
|
||||
{ firstName: { contains: query, mode: "insensitive" } },
|
||||
{ firstNameEN: { contains: query, mode: "insensitive" } },
|
||||
{ lastName: { contains: query, mode: "insensitive" } },
|
||||
{ lastNameEN: { contains: query, mode: "insensitive" } },
|
||||
],
|
||||
},
|
||||
},
|
||||
|
|
@ -199,6 +205,7 @@ export class CreditNoteController extends Controller {
|
|||
},
|
||||
},
|
||||
},
|
||||
...whereDateQuery(startDate, endDate),
|
||||
} satisfies Prisma.CreditNoteWhereInput;
|
||||
|
||||
const [result, total] = await prisma.$transaction([
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ import {
|
|||
setFile,
|
||||
} from "../utils/minio";
|
||||
import { isUsedError, notFoundError, relationError } from "../utils/error";
|
||||
import { queryOrNot } from "../utils/relation";
|
||||
import { queryOrNot, whereDateQuery } from "../utils/relation";
|
||||
import { isSystem } from "../utils/keycloak";
|
||||
import { precisionRound } from "../utils/arithmetic";
|
||||
|
||||
|
|
@ -76,6 +76,7 @@ type DebitNoteCreate = {
|
|||
dateOfBirth: Date;
|
||||
gender: string;
|
||||
nationality: string;
|
||||
otherNationality: string;
|
||||
namePrefix?: string;
|
||||
firstName: string;
|
||||
firstNameEN: string;
|
||||
|
|
@ -111,13 +112,14 @@ type DebitNoteUpdate = {
|
|||
dateOfBirth: Date;
|
||||
gender: string;
|
||||
nationality: string;
|
||||
otherNationality: string;
|
||||
namePrefix?: string;
|
||||
firstName: string;
|
||||
firstName?: string;
|
||||
firstNameEN: string;
|
||||
middleName?: string;
|
||||
middleNameEN?: string;
|
||||
lastName: string;
|
||||
lastNameEN: string;
|
||||
lastName?: string;
|
||||
lastNameEN?: string;
|
||||
}
|
||||
)[];
|
||||
|
||||
|
|
@ -168,6 +170,8 @@ export class DebitNoteController extends Controller {
|
|||
@Query() payCondition?: PayCondition,
|
||||
@Query() includeRegisteredBranch?: boolean,
|
||||
@Query() code?: string,
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
) {
|
||||
return await this.getDebitNoteListByCriteria(
|
||||
req,
|
||||
|
|
@ -179,6 +183,8 @@ export class DebitNoteController extends Controller {
|
|||
payCondition,
|
||||
includeRegisteredBranch,
|
||||
code,
|
||||
startDate,
|
||||
endDate,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -195,21 +201,23 @@ export class DebitNoteController extends Controller {
|
|||
@Query() payCondition?: PayCondition,
|
||||
@Query() includeRegisteredBranch?: boolean,
|
||||
@Query() code?: string,
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
@Body() body?: {},
|
||||
) {
|
||||
const where = {
|
||||
OR: queryOrNot<Prisma.QuotationWhereInput[]>(query, [
|
||||
{ code: { contains: query, mode: "insensitive" } },
|
||||
{ workName: { contains: query } },
|
||||
{ workName: { contains: query, mode: "insensitive" } },
|
||||
{
|
||||
customerBranch: {
|
||||
OR: [
|
||||
{ code: { contains: query, mode: "insensitive" } },
|
||||
{ customerName: { contains: query } },
|
||||
{ firstName: { contains: query } },
|
||||
{ firstNameEN: { contains: query } },
|
||||
{ lastName: { contains: query } },
|
||||
{ lastNameEN: { contains: query } },
|
||||
{ customerName: { contains: query, mode: "insensitive" } },
|
||||
{ firstName: { contains: query, mode: "insensitive" } },
|
||||
{ firstNameEN: { contains: query, mode: "insensitive" } },
|
||||
{ lastName: { contains: query, mode: "insensitive" } },
|
||||
{ lastNameEN: { contains: query, mode: "insensitive" } },
|
||||
],
|
||||
},
|
||||
},
|
||||
|
|
@ -220,6 +228,7 @@ export class DebitNoteController extends Controller {
|
|||
debitNoteQuotationId: quotationId,
|
||||
registeredBranch: isSystem(req.user) ? undefined : { OR: permissionCond(req.user) },
|
||||
quotationStatus: status,
|
||||
...whereDateQuery(startDate, endDate),
|
||||
} satisfies Prisma.QuotationWhereInput;
|
||||
|
||||
const [result, total] = await prisma.$transaction([
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import {
|
|||
TaskStatus,
|
||||
RequestWorkStatus,
|
||||
} from "@prisma/client";
|
||||
import { queryOrNot, whereAddressQuery } from "../utils/relation";
|
||||
import { queryOrNot, whereAddressQuery, whereDateQuery } from "../utils/relation";
|
||||
import { filterStatus } from "../services/prisma";
|
||||
// import { RequestWorkStatus } from "../generated/kysely/types";
|
||||
import { deleteFile, fileLocation, getFile, getPresigned, listFile, setFile } from "../utils/minio";
|
||||
|
|
@ -51,6 +51,8 @@ export class LineController extends Controller {
|
|||
@Query() page: number = 1,
|
||||
@Query() pageSize: number = 30,
|
||||
@Query() activeOnly?: boolean,
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
) {
|
||||
const where = {
|
||||
OR: !!query
|
||||
|
|
@ -58,13 +60,13 @@ export class LineController extends Controller {
|
|||
...(queryOrNot<Prisma.EmployeeWhereInput[]>(query, [
|
||||
{
|
||||
employeePassport: {
|
||||
some: { number: { contains: query } },
|
||||
some: { number: { contains: query, mode: "insensitive" } },
|
||||
},
|
||||
},
|
||||
{ firstName: { contains: query } },
|
||||
{ firstNameEN: { contains: query } },
|
||||
{ lastName: { contains: query } },
|
||||
{ lastNameEN: { contains: query } },
|
||||
{ firstName: { contains: query, mode: "insensitive" } },
|
||||
{ firstNameEN: { contains: query, mode: "insensitive" } },
|
||||
{ lastName: { contains: query, mode: "insensitive" } },
|
||||
{ lastNameEN: { contains: query, mode: "insensitive" } },
|
||||
...whereAddressQuery(query),
|
||||
]) ?? []),
|
||||
]
|
||||
|
|
@ -87,6 +89,7 @@ export class LineController extends Controller {
|
|||
subDistrict: zipCode ? { zipCode } : undefined,
|
||||
gender,
|
||||
},
|
||||
...whereDateQuery(startDate, endDate),
|
||||
} satisfies Prisma.EmployeeWhereInput;
|
||||
|
||||
const [result, total] = await prisma.$transaction([
|
||||
|
|
@ -173,24 +176,26 @@ export class LineController extends Controller {
|
|||
@Query() requestDataStatus?: RequestDataStatus,
|
||||
@Query() quotationId?: string,
|
||||
@Query() code?: string,
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
) {
|
||||
const where = {
|
||||
OR: queryOrNot<Prisma.RequestDataWhereInput[]>(query, [
|
||||
{ code: { contains: query, mode: "insensitive" } },
|
||||
{ quotation: { code: { contains: query, mode: "insensitive" } } },
|
||||
{ quotation: { workName: { contains: query } } },
|
||||
{ quotation: { workName: { contains: query, mode: "insensitive" } } },
|
||||
{
|
||||
quotation: {
|
||||
customerBranch: {
|
||||
OR: [
|
||||
{ code: { contains: query, mode: "insensitive" } },
|
||||
{ customerName: { contains: query } },
|
||||
{ registerName: { contains: query } },
|
||||
{ registerNameEN: { contains: query } },
|
||||
{ firstName: { contains: query } },
|
||||
{ firstNameEN: { contains: query } },
|
||||
{ lastName: { contains: query } },
|
||||
{ lastNameEN: { contains: query } },
|
||||
{ customerName: { contains: query, mode: "insensitive" } },
|
||||
{ registerName: { contains: query, mode: "insensitive" } },
|
||||
{ registerNameEN: { contains: query, mode: "insensitive" } },
|
||||
{ firstName: { contains: query, mode: "insensitive" } },
|
||||
{ firstNameEN: { contains: query, mode: "insensitive" } },
|
||||
{ lastName: { contains: query, mode: "insensitive" } },
|
||||
{ lastNameEN: { contains: query, mode: "insensitive" } },
|
||||
],
|
||||
},
|
||||
},
|
||||
|
|
@ -198,14 +203,14 @@ export class LineController extends Controller {
|
|||
OR: [
|
||||
{
|
||||
employeePassport: {
|
||||
some: { number: { contains: query } },
|
||||
some: { number: { contains: query, mode: "insensitive" } },
|
||||
},
|
||||
},
|
||||
{ code: { contains: query, mode: "insensitive" } },
|
||||
{ firstName: { contains: query } },
|
||||
{ firstNameEN: { contains: query } },
|
||||
{ lastName: { contains: query } },
|
||||
{ lastNameEN: { contains: query } },
|
||||
{ firstName: { contains: query, mode: "insensitive" } },
|
||||
{ firstNameEN: { contains: query, mode: "insensitive" } },
|
||||
{ lastName: { contains: query, mode: "insensitive" } },
|
||||
{ lastNameEN: { contains: query, mode: "insensitive" } },
|
||||
],
|
||||
},
|
||||
},
|
||||
|
|
@ -247,6 +252,7 @@ export class LineController extends Controller {
|
|||
],
|
||||
},
|
||||
},
|
||||
...whereDateQuery(startDate, endDate),
|
||||
} satisfies Prisma.RequestDataWhereInput;
|
||||
|
||||
const [result, total] = await prisma.$transaction([
|
||||
|
|
@ -604,6 +610,8 @@ export class LineController extends Controller {
|
|||
@Query() includeRegisteredBranch?: boolean,
|
||||
@Query() code?: string,
|
||||
@Query() query = "",
|
||||
@Query() startDate?: Date,
|
||||
@Query() endDate?: Date,
|
||||
) {
|
||||
const where = {
|
||||
OR:
|
||||
|
|
@ -611,16 +619,16 @@ export class LineController extends Controller {
|
|||
? [
|
||||
...(queryOrNot<Prisma.QuotationWhereInput[]>(query, [
|
||||
{ code: { contains: query, mode: "insensitive" } },
|
||||
{ workName: { contains: query } },
|
||||
{ workName: { contains: query, mode: "insensitive" } },
|
||||
{
|
||||
customerBranch: {
|
||||
OR: [
|
||||
{ code: { contains: query, mode: "insensitive" } },
|
||||
{ customerName: { contains: query } },
|
||||
{ firstName: { contains: query } },
|
||||
{ firstNameEN: { contains: query } },
|
||||
{ lastName: { contains: query } },
|
||||
{ lastNameEN: { contains: query } },
|
||||
{ customerName: { contains: query, mode: "insensitive" } },
|
||||
{ firstName: { contains: query, mode: "insensitive" } },
|
||||
{ firstNameEN: { contains: query, mode: "insensitive" } },
|
||||
{ lastName: { contains: query, mode: "insensitive" } },
|
||||
{ lastNameEN: { contains: query, mode: "insensitive" } },
|
||||
],
|
||||
},
|
||||
},
|
||||
|
|
@ -660,6 +668,7 @@ export class LineController extends Controller {
|
|||
},
|
||||
}
|
||||
: undefined,
|
||||
...whereDateQuery(startDate, endDate),
|
||||
} satisfies Prisma.QuotationWhereInput;
|
||||
|
||||
const [result, total] = await prisma.$transaction([
|
||||
|
|
@ -1368,3 +1377,65 @@ export class LineQuotationFileController extends Controller {
|
|||
return await deleteFile(fileLocation.quotation.attachment(quotationId, name));
|
||||
}
|
||||
}
|
||||
|
||||
@Route("api/v1/line/payment/{paymentId}/attachment")
|
||||
@Tags("Line")
|
||||
export class PaymentFileLineController extends Controller {
|
||||
private async checkPermission(_user: RequestWithUser["user"], id: string) {
|
||||
const data = await prisma.payment.findUnique({
|
||||
include: {
|
||||
invoice: {
|
||||
include: {
|
||||
quotation: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
where: { id },
|
||||
});
|
||||
|
||||
if (!data) throw notFoundError("Payment");
|
||||
return { paymentId: id, quotationId: data.invoice.quotationId };
|
||||
}
|
||||
|
||||
@Get()
|
||||
@Security("line")
|
||||
async listAttachment(@Request() req: RequestWithUser, @Path() paymentId: string) {
|
||||
const { quotationId } = await this.checkPermission(req.user, paymentId);
|
||||
return await listFile(fileLocation.quotation.payment(quotationId, paymentId));
|
||||
}
|
||||
|
||||
@Head("{name}")
|
||||
async headAttachment(
|
||||
@Request() req: RequestWithUser,
|
||||
@Path() paymentId: string,
|
||||
@Path() name: string,
|
||||
) {
|
||||
const data = await prisma.payment.findUnique({
|
||||
where: { id: paymentId },
|
||||
include: { invoice: true },
|
||||
});
|
||||
if (!data) throw notFoundError("Payment");
|
||||
return req.res?.redirect(
|
||||
await getPresigned(
|
||||
"head",
|
||||
fileLocation.quotation.payment(data.invoice.quotationId, paymentId, name),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@Get("{name}")
|
||||
async getAttachment(
|
||||
@Request() req: RequestWithUser,
|
||||
@Path() paymentId: string,
|
||||
@Path() name: string,
|
||||
) {
|
||||
const data = await prisma.payment.findUnique({
|
||||
where: { id: paymentId },
|
||||
include: { invoice: true },
|
||||
});
|
||||
if (!data) throw notFoundError("Payment");
|
||||
return req.res?.redirect(
|
||||
await getFile(fileLocation.quotation.payment(data.invoice.quotationId, paymentId, name)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
25
src/controllers/10-troubleshooting-controller.ts
Normal file
25
src/controllers/10-troubleshooting-controller.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import express from "express";
|
||||
import { Controller, Get, Path, Request, Route } from "tsoa";
|
||||
import { getFile } from "../utils/minio";
|
||||
|
||||
@Route("api/v1/troubleshooting")
|
||||
export class TroubleshootingController extends Controller {
|
||||
@Get()
|
||||
async get(@Request() req: express.Request) {
|
||||
return req.res?.redirect(await getFile(".troubleshooting/toc.json"));
|
||||
}
|
||||
|
||||
@Get("{category}/assets/{name}")
|
||||
async getAsset(@Request() req: express.Request, @Path() category: string, @Path() name: string) {
|
||||
return req.res?.redirect(await getFile(`.troubleshooting/${category}/assets/${name}`));
|
||||
}
|
||||
|
||||
@Get("{category}/page/{page}")
|
||||
async getContent(
|
||||
@Request() req: express.Request,
|
||||
@Path() category: string,
|
||||
@Path() page: string,
|
||||
) {
|
||||
return req.res?.redirect(await getFile(`.troubleshooting/${category}/${page}.md`));
|
||||
}
|
||||
}
|
||||
|
|
@ -346,6 +346,64 @@ export async function removeUserRoles(userId: string, roles: { id: string; name:
|
|||
return true;
|
||||
}
|
||||
|
||||
export async function getGroup(query: string) {
|
||||
const res = await fetch(`${KC_URL}/admin/realms/${KC_REALM}/groups?${query}`, {
|
||||
headers: {
|
||||
authorization: `Bearer ${await getToken()}`,
|
||||
"content-type": `application/json`,
|
||||
},
|
||||
method: "GET",
|
||||
});
|
||||
|
||||
const dataMainGroup = await res.json();
|
||||
const fetchSubGroups = async (group: any) => {
|
||||
let fullSubGroup = await Promise.all(
|
||||
group.subGroups.map((subGroupsData: any) => {
|
||||
if (group.subGroupCount > 0) {
|
||||
return fetchSubGroups(subGroupsData);
|
||||
} else {
|
||||
return {
|
||||
id: subGroupsData.id,
|
||||
name: subGroupsData.name,
|
||||
path: subGroupsData.path,
|
||||
subGroupCount: subGroupsData.subGroupCount,
|
||||
subGroups: [],
|
||||
};
|
||||
}
|
||||
}),
|
||||
);
|
||||
return {
|
||||
id: group.id,
|
||||
name: group.name,
|
||||
path: group.path,
|
||||
subGroupCount: group.subGroupCount,
|
||||
subGroups: fullSubGroup,
|
||||
};
|
||||
};
|
||||
|
||||
const fullMainGroup = await Promise.all(dataMainGroup.map(fetchSubGroups));
|
||||
return fullMainGroup;
|
||||
}
|
||||
|
||||
export async function getGroupUser(userId: string) {
|
||||
const res = await fetch(`${KC_URL}/admin/realms/${KC_REALM}/users/${userId}/groups`, {
|
||||
headers: {
|
||||
authorization: `Bearer ${await getToken()}`,
|
||||
"content-type": `application/json`,
|
||||
},
|
||||
method: "GET",
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
return data.map((item: any) => {
|
||||
return {
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
path: item.path,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
createUser,
|
||||
listRole,
|
||||
|
|
|
|||
|
|
@ -10,26 +10,35 @@ export function connectOrDisconnect(id?: string | null) {
|
|||
|
||||
export function whereAddressQuery(query: string) {
|
||||
return [
|
||||
{ address: { contains: query } },
|
||||
{ addressEN: { contains: query } },
|
||||
{ soi: { contains: query } },
|
||||
{ soiEN: { contains: query } },
|
||||
{ moo: { contains: query } },
|
||||
{ mooEN: { contains: query } },
|
||||
{ street: { contains: query } },
|
||||
{ streetEN: { contains: query } },
|
||||
{ province: { name: { contains: query } } },
|
||||
{ province: { nameEN: { contains: query } } },
|
||||
{ district: { name: { contains: query } } },
|
||||
{ district: { nameEN: { contains: query } } },
|
||||
{ subDistrict: { name: { contains: query } } },
|
||||
{ subDistrict: { nameEN: { contains: query } } },
|
||||
{ subDistrict: { zipCode: { contains: query } } },
|
||||
];
|
||||
{ address: { contains: query, mode: "insensitive" } },
|
||||
{ addressEN: { contains: query, mode: "insensitive" } },
|
||||
{ soi: { contains: query, mode: "insensitive" } },
|
||||
{ soiEN: { contains: query, mode: "insensitive" } },
|
||||
{ moo: { contains: query, mode: "insensitive" } },
|
||||
{ mooEN: { contains: query, mode: "insensitive" } },
|
||||
{ street: { contains: query, mode: "insensitive" } },
|
||||
{ streetEN: { contains: query, mode: "insensitive" } },
|
||||
{ province: { name: { contains: query, mode: "insensitive" } } },
|
||||
{ province: { nameEN: { contains: query, mode: "insensitive" } } },
|
||||
{ district: { name: { contains: query, mode: "insensitive" } } },
|
||||
{ district: { nameEN: { contains: query, mode: "insensitive" } } },
|
||||
{ subDistrict: { name: { contains: query, mode: "insensitive" } } },
|
||||
{ subDistrict: { nameEN: { contains: query, mode: "insensitive" } } },
|
||||
{ subDistrict: { zipCode: { contains: query, mode: "insensitive" } } },
|
||||
] as const;
|
||||
}
|
||||
|
||||
export function queryOrNot<T>(query: string | boolean, where: T): T | undefined;
|
||||
export function queryOrNot<T, U>(query: string | boolean, where: T, fallback: U): T | U;
|
||||
export function queryOrNot<T, U>(query: string | boolean, where: T, fallback?: U) {
|
||||
export function queryOrNot<T>(query: any, where: T): T | undefined;
|
||||
export function queryOrNot<T, U>(query: any, where: T, fallback: U): T | U;
|
||||
export function queryOrNot<T, U>(query: any, where: T, fallback?: U) {
|
||||
return !!query ? where : fallback;
|
||||
}
|
||||
|
||||
export function whereDateQuery(startDate: Date | undefined, endDate: Date | undefined) {
|
||||
return {
|
||||
createdAt: {
|
||||
gte: startDate,
|
||||
lte: endDate,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
|||
105
src/utils/spreadsheet.ts
Normal file
105
src/utils/spreadsheet.ts
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
import Excel from "exceljs";
|
||||
|
||||
export default class spreadsheet {
|
||||
static async readCsv() {
|
||||
// TODO: read csv
|
||||
}
|
||||
|
||||
/**
|
||||
* This function read data from excel file.
|
||||
*
|
||||
* @param buffer - Excel file.
|
||||
* @param opts.header - Interprets the first row as the names of the fields.
|
||||
* @param opts.worksheet - Specifies the worksheet to read. Can be the worksheet's name or its 1-based index.
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
static async readExcel<T extends unknown>(
|
||||
buffer: Excel.Buffer,
|
||||
opts?: { header?: boolean; worksheet?: number | string },
|
||||
): Promise<T[]> {
|
||||
const workbook = new Excel.Workbook();
|
||||
await workbook.xlsx.load(buffer);
|
||||
const worksheet = workbook.getWorksheet(opts?.worksheet ?? 1);
|
||||
|
||||
if (!worksheet) return [];
|
||||
|
||||
const header: Record<number, string | number> = {};
|
||||
const values: any[] = [];
|
||||
|
||||
worksheet.eachRow((row, rowId) => {
|
||||
if (rowId === 1 && opts?.header !== false) {
|
||||
row.eachCell((cell, cellId) => {
|
||||
if (typeof cell.value === "string") {
|
||||
header[cellId] = nameValue(cell.value);
|
||||
} else {
|
||||
header[cellId] = cellId.toString();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
const data: Record<string | number, Excel.CellValue> = {};
|
||||
row.eachCell((cell, cellId) => {
|
||||
data[opts?.header !== false ? header[cellId] : cellId - 1] = cell.value;
|
||||
});
|
||||
values.push(opts?.header !== false ? data : Object.values(data));
|
||||
}
|
||||
});
|
||||
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
function nameValue(value: string) {
|
||||
let code: string;
|
||||
switch (value) {
|
||||
case "ชื่อสินค้าและบริการ":
|
||||
code = "name";
|
||||
break;
|
||||
case "ระยะเวลาดำเนินการ":
|
||||
code = "process";
|
||||
break;
|
||||
case "ประเภทค่าใช้จ่าย":
|
||||
code = "expenseType";
|
||||
break;
|
||||
case "รายละเอียด":
|
||||
code = "detail";
|
||||
break;
|
||||
case "หมายเหตุ":
|
||||
code = "remark";
|
||||
break;
|
||||
case "ใช้งานร่วมกัน":
|
||||
code = "shared";
|
||||
break;
|
||||
case "คำนวณภาษีราคาขาย":
|
||||
code = "calcVat";
|
||||
break;
|
||||
case "รวม VAT ราคาขาย":
|
||||
code = "vatIncluded";
|
||||
break;
|
||||
case "ราคาต่อหน่วย (บาท) ราคาขาย":
|
||||
code = "price";
|
||||
break;
|
||||
case "คำนวณภาษีราคาตัวแทน":
|
||||
code = "agentPriceCalcVat";
|
||||
break;
|
||||
case "รวม VAT ราคาตัวแทน":
|
||||
code = "agentPriceVatIncluded";
|
||||
break;
|
||||
case "ราคาต่อหน่วย (บาท) ราคาตัวแทน":
|
||||
code = "agentPrice";
|
||||
break;
|
||||
case "คำนวณภาษีราคาดำเนินการ":
|
||||
code = "serviceChargeCalcVat";
|
||||
break;
|
||||
case "รวม VAT ราคาดำเนินการ":
|
||||
code = "serviceChargeVatIncluded";
|
||||
break;
|
||||
case "ราคาต่อหน่วย (บาท) ราคาดำเนินการ":
|
||||
code = "serviceCharge";
|
||||
break;
|
||||
default:
|
||||
code = "code";
|
||||
break;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue