diff --git a/Dockerfile b/Dockerfile index f29dc9a..951bb52 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,22 +1,33 @@ -FROM node:20-slim +FROM node:23-slim AS base -RUN apt-get update -y \ - && apt-get install -y openssl \ - && npm install -g pnpm \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* +ENV PNPM_HOME="/pnpm" +ENV PATH="$PNPM_HOME:$PATH" + +RUN corepack enable +RUN apt-get update && apt-get install -y openssl +RUN pnpm i -g prisma prisma-kysely WORKDIR /app -COPY package.json pnpm-lock.yaml ./ -RUN pnpm install --frozen-lockfile - COPY . . +FROM base AS deps +RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --prod --frozen-lockfile +RUN pnpm prisma generate + +FROM base AS build +RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile RUN pnpm prisma generate RUN pnpm run build -COPY entrypoint.sh /entrypoint.sh -RUN chmod +x /entrypoint.sh +FROM base AS prod -ENTRYPOINT ["/entrypoint.sh"] +ENV NODE_ENV="production" + +COPY --from=deps /app/node_modules /app/node_modules +COPY --from=build /app/dist /app/dist +COPY --from=base /app/static /app/static + +RUN chmod u+x ./entrypoint.sh + +ENTRYPOINT ["./entrypoint.sh"] diff --git a/package.json b/package.json index 69799c0..b576e46 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,6 @@ "start": "node ./dist/app.js", "dev": "nodemon", "check": "tsc --noEmit", - "test": "vitest", "format": "prettier --write .", "debug": "nodemon", "build": "tsoa spec-and-routes && tsc", @@ -25,45 +24,35 @@ "@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", - "@vitest/ui": "^3.1.4", "nodemon": "^3.1.9", "prettier": "^3.4.2", - "prisma": "6.16.2", + "prisma": "^6.3.0", "prisma-kysely": "^1.8.0", "ts-node": "^10.9.2", - "typescript": "^5.7.2", - "vitest": "^3.1.4" + "typescript": "^5.7.2" }, "dependencies": { "@elastic/elasticsearch": "^8.17.0", "@fast-csv/parse": "^5.0.2", - "@prisma/client": "6.16.2", + "@prisma/client": "^6.3.0", "@scalar/express-api-reference": "^0.4.182", "@tsoa/runtime": "^6.6.0", - "@types/html-to-text": "^9.0.4", - "canvas": "^3.1.0", + "barcode": "^0.1.0", "cors": "^2.8.5", "cron": "^3.3.1", - "csv-parse": "^6.1.0", "dayjs": "^1.11.13", "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", - "html-to-text": "^9.0.5", - "jsbarcode": "^3.11.6", "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", - "pnpm": "^10.18.3", "prisma-extension-kysely": "^3.0.0", "promise.any": "^2.0.6", "thai-baht-text": "^2.0.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d724159..bb7ddd5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,29 +15,23 @@ importers: specifier: ^5.0.2 version: 5.0.2 '@prisma/client': - specifier: 6.16.2 - version: 6.16.2(prisma@6.16.2(typescript@5.7.2))(typescript@5.7.2) + specifier: ^6.3.0 + version: 6.3.0(prisma@6.3.0(typescript@5.7.2))(typescript@5.7.2) '@scalar/express-api-reference': specifier: ^0.4.182 version: 0.4.182 '@tsoa/runtime': specifier: ^6.6.0 version: 6.6.0 - '@types/html-to-text': - specifier: ^9.0.4 - version: 9.0.4 - canvas: - specifier: ^3.1.0 - version: 3.1.0 + barcode: + specifier: ^0.1.0 + version: 0.1.0 cors: specifier: ^2.8.5 version: 2.8.5 cron: specifier: ^3.3.1 version: 3.3.1 - csv-parse: - specifier: ^6.1.0 - version: 6.1.0 dayjs: specifier: ^1.11.13 version: 1.11.13 @@ -50,21 +44,12 @@ 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 fast-jwt: specifier: ^5.0.5 version: 5.0.5 - html-to-text: - specifier: ^9.0.5 - version: 9.0.5 - jsbarcode: - specifier: ^3.11.6 - version: 3.11.6 json-2-csv: specifier: ^5.5.8 version: 5.5.8 @@ -77,18 +62,12 @@ 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 - pnpm: - specifier: ^10.18.3 - version: 10.28.0 prisma-extension-kysely: specifier: ^3.0.0 - version: 3.0.0(@prisma/client@6.16.2(prisma@6.16.2(typescript@5.7.2))(typescript@5.7.2)) + version: 3.0.0(@prisma/client@6.3.0(prisma@6.3.0(typescript@5.7.2))(typescript@5.7.2)) promise.any: specifier: ^2.0.6 version: 2.0.6 @@ -120,18 +99,12 @@ 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 '@types/nodemailer': specifier: ^6.4.17 version: 6.4.17 - '@vitest/ui': - specifier: ^3.1.4 - version: 3.1.4(vitest@3.1.4) nodemon: specifier: ^3.1.9 version: 3.1.9 @@ -139,8 +112,8 @@ importers: specifier: ^3.4.2 version: 3.4.2 prisma: - specifier: 6.16.2 - version: 6.16.2(typescript@5.7.2) + specifier: ^6.3.0 + version: 6.3.0(typescript@5.7.2) prisma-kysely: specifier: ^1.8.0 version: 1.8.0(encoding@0.1.13) @@ -150,9 +123,6 @@ importers: typescript: specifier: ^5.7.2 version: 5.7.2 - vitest: - specifier: ^3.1.4 - version: 3.1.4(@types/node@20.17.10)(@vitest/ui@3.1.4)(jiti@2.5.1)(yaml@2.6.1) packages: @@ -207,162 +177,6 @@ packages: resolution: {integrity: sha512-jasKNQeOb1vNf9aEYg+8zXmetaFjApDTSCC4QTl6aTixvyiRiSLcCiB8P6Q0lY9JIII/BhqNl8WbpFnsKitntw==} engines: {node: '>=18'} - '@esbuild/aix-ppc64@0.25.4': - resolution: {integrity: sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.25.4': - resolution: {integrity: sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.25.4': - resolution: {integrity: sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.25.4': - resolution: {integrity: sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.25.4': - resolution: {integrity: sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.25.4': - resolution: {integrity: sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.25.4': - resolution: {integrity: sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.25.4': - resolution: {integrity: sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.25.4': - resolution: {integrity: sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.25.4': - resolution: {integrity: sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.25.4': - resolution: {integrity: sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.25.4': - resolution: {integrity: sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.25.4': - resolution: {integrity: sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.25.4': - resolution: {integrity: sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.25.4': - resolution: {integrity: sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.25.4': - resolution: {integrity: sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.25.4': - resolution: {integrity: sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-arm64@0.25.4': - resolution: {integrity: sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.25.4': - resolution: {integrity: sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-arm64@0.25.4': - resolution: {integrity: sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.25.4': - resolution: {integrity: sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - - '@esbuild/sunos-x64@0.25.4': - resolution: {integrity: sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.25.4': - resolution: {integrity: sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.25.4': - resolution: {integrity: sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.25.4': - resolution: {integrity: sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - - '@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==} @@ -525,11 +339,8 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@polka/url@1.0.0-next.29': - resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} - - '@prisma/client@6.16.2': - resolution: {integrity: sha512-E00PxBcalMfYO/TWnXobBVUai6eW/g5OsifWQsQDzJYm7yaY+IRLo7ZLsaefi0QkTpxfuhFcQ/w180i6kX3iJw==} + '@prisma/client@6.3.0': + resolution: {integrity: sha512-BY3Fi28PUSk447Bpv22LhZp4HgNPo7NsEN+EteM1CLDnLjig5863jpW+3c3HHLFmml+nB/eJv1CjSriFZ8z7Cg==} engines: {node: '>=18.18'} peerDependencies: prisma: '*' @@ -540,29 +351,26 @@ packages: typescript: optional: true - '@prisma/config@6.16.2': - resolution: {integrity: sha512-mKXSUrcqXj0LXWPmJsK2s3p9PN+aoAbyMx7m5E1v1FufofR1ZpPoIArjjzOIm+bJRLLvYftoNYLx1tbHgF9/yg==} - '@prisma/debug@5.3.1': resolution: {integrity: sha512-eYrxqslEKf+wpMFIIHgbcNYuZBXUdiJLA85Or3TwOhgPIN1ZoXT9CwJph3ynW8H1Xg0LkdYLwVmuULCwiMoU5A==} - '@prisma/debug@6.16.2': - resolution: {integrity: sha512-bo4/gA/HVV6u8YK2uY6glhNsJ7r+k/i5iQ9ny/3q5bt9ijCj7WMPUwfTKPvtEgLP+/r26Z686ly11hhcLiQ8zA==} + '@prisma/debug@6.3.0': + resolution: {integrity: sha512-m1lQv//0Rc5RG8TBpNUuLCxC35Ghi5XfpPmL83Gh04/GICHD2J5H2ndMlaljrUNaQDF9dOxIuFAYP1rE9wkXkg==} - '@prisma/engines-version@6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43': - resolution: {integrity: sha512-ThvlDaKIVrnrv97ujNFDYiQbeMQpLa0O86HFA2mNoip4mtFqM7U5GSz2ie1i2xByZtvPztJlNRgPsXGeM/kqAA==} + '@prisma/engines-version@6.3.0-17.acc0b9dd43eb689cbd20c9470515d719db10d0b0': + resolution: {integrity: sha512-R/ZcMuaWZT2UBmgX3Ko6PAV3f8//ZzsjRIG1eKqp3f2rqEqVtCv+mtzuH2rBPUC9ujJ5kCb9wwpxeyCkLcHVyA==} '@prisma/engines@5.3.1': resolution: {integrity: sha512-6QkILNyfeeN67BNEPEtkgh3Xo2tm6D7V+UhrkBbRHqKw9CTaz/vvTP/ROwYSP/3JT2MtIutZm/EnhxUiuOPVDA==} - '@prisma/engines@6.16.2': - resolution: {integrity: sha512-7yf3AjfPUgsg/l7JSu1iEhsmZZ/YE00yURPjTikqm2z4btM0bCl2coFtTGfeSOWbQMmq45Jab+53yGUIAT1sjA==} + '@prisma/engines@6.3.0': + resolution: {integrity: sha512-RXqYhlZb9sx/xkUfYIZuEPn7sT0WgTxNOuEYQ7AGw3IMpP9QGVEDVsluc/GcNkM8NTJszeqk8AplJzI9lm7Jxw==} '@prisma/fetch-engine@5.3.1': resolution: {integrity: sha512-w1yk1YiK8N82Pobdq58b85l6e8akyrkxuzwV9DoiUTRf3gpsuhJJesHc4Yi0WzUC9/3znizl1UfCsI6dhkj3Vw==} - '@prisma/fetch-engine@6.16.2': - resolution: {integrity: sha512-wPnZ8DMRqpgzye758ZvfAMiNJRuYpz+rhgEBZi60ZqDIgOU2694oJxiuu3GKFeYeR/hXxso4/2oBC243t/whxQ==} + '@prisma/fetch-engine@6.3.0': + resolution: {integrity: sha512-GBy0iT4f1mH31ePzfcpVSUa7JLRTeq4914FG2vR3LqDwRweSm4ja1o5flGDz+eVIa/BNYfkBvRRxv4D6ve6Eew==} '@prisma/generator-helper@5.3.1': resolution: {integrity: sha512-zrYS0iHLgPlOJjYnd5KvVMMvSS+ktOL39EwooS5EnyvfzwfzxlKCeOUgxTfiKYs0WUWqzEvyNAYtramYgSknsQ==} @@ -570,8 +378,8 @@ packages: '@prisma/get-platform@5.3.1': resolution: {integrity: sha512-3IiZY2BUjKnAuZ0569zppZE6/rZbVAM09//c2nvPbbkGG9MqrirA8fbhhF7tfVmhyVfdmVCHnf/ujWPHJ8B46Q==} - '@prisma/get-platform@6.16.2': - resolution: {integrity: sha512-U/P36Uke5wS7r1+omtAgJpEB94tlT4SdlgaeTc6HVTTT93pXj7zZ+B/cZnmnvjcNPfWddgoDx8RLjmQwqGDYyA==} + '@prisma/get-platform@6.3.0': + resolution: {integrity: sha512-V8zZ1d0xfyi6FjpNP4AcYuwSpGcdmu35OXWnTPm8IW594PYALzKXHwIa9+o0f+Lo9AecFWrwrwaoYe56UNfTtQ==} '@prisma/internals@5.3.1': resolution: {integrity: sha512-zkW73hPHHNrMD21PeYgCTBfMu71vzJf+WtfydtJbS0JVJKyLfOel0iWSQg7wjNeQfccKp+NdHJ/5rTJ4NEUzgA==} @@ -579,106 +387,6 @@ packages: '@prisma/prisma-schema-wasm@5.3.1-2.61e140623197a131c2a6189271ffee05a7aa9a59': resolution: {integrity: sha512-+zUI7NQDXfcNnU8HgrAj4jRMv8yRfITLzcfv0Urf0adKimM+hkkVG4rX38i9zWMlxekkEBw7NLFx3Gxxy8d3iQ==} - '@rollup/rollup-android-arm-eabi@4.41.0': - resolution: {integrity: sha512-KxN+zCjOYHGwCl4UCtSfZ6jrq/qi88JDUtiEFk8LELEHq2Egfc/FgW+jItZiOLRuQfb/3xJSgFuNPC9jzggX+A==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.41.0': - resolution: {integrity: sha512-yDvqx3lWlcugozax3DItKJI5j05B0d4Kvnjx+5mwiUpWramVvmAByYigMplaoAQ3pvdprGCTCE03eduqE/8mPQ==} - cpu: [arm64] - os: [android] - - '@rollup/rollup-darwin-arm64@4.41.0': - resolution: {integrity: sha512-2KOU574vD3gzcPSjxO0eyR5iWlnxxtmW1F5CkNOHmMlueKNCQkxR6+ekgWyVnz6zaZihpUNkGxjsYrkTJKhkaw==} - cpu: [arm64] - os: [darwin] - - '@rollup/rollup-darwin-x64@4.41.0': - resolution: {integrity: sha512-gE5ACNSxHcEZyP2BA9TuTakfZvULEW4YAOtxl/A/YDbIir/wPKukde0BNPlnBiP88ecaN4BJI2TtAd+HKuZPQQ==} - cpu: [x64] - os: [darwin] - - '@rollup/rollup-freebsd-arm64@4.41.0': - resolution: {integrity: sha512-GSxU6r5HnWij7FoSo7cZg3l5GPg4HFLkzsFFh0N/b16q5buW1NAWuCJ+HMtIdUEi6XF0qH+hN0TEd78laRp7Dg==} - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.41.0': - resolution: {integrity: sha512-KGiGKGDg8qLRyOWmk6IeiHJzsN/OYxO6nSbT0Vj4MwjS2XQy/5emsmtoqLAabqrohbgLWJ5GV3s/ljdrIr8Qjg==} - cpu: [x64] - os: [freebsd] - - '@rollup/rollup-linux-arm-gnueabihf@4.41.0': - resolution: {integrity: sha512-46OzWeqEVQyX3N2/QdiU/CMXYDH/lSHpgfBkuhl3igpZiaB3ZIfSjKuOnybFVBQzjsLwkus2mjaESy8H41SzvA==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm-musleabihf@4.41.0': - resolution: {integrity: sha512-lfgW3KtQP4YauqdPpcUZHPcqQXmTmH4nYU0cplNeW583CMkAGjtImw4PKli09NFi2iQgChk4e9erkwlfYem6Lg==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm64-gnu@4.41.0': - resolution: {integrity: sha512-nn8mEyzMbdEJzT7cwxgObuwviMx6kPRxzYiOl6o/o+ChQq23gfdlZcUNnt89lPhhz3BYsZ72rp0rxNqBSfqlqw==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-arm64-musl@4.41.0': - resolution: {integrity: sha512-l+QK99je2zUKGd31Gh+45c4pGDAqZSuWQiuRFCdHYC2CSiO47qUWsCcenrI6p22hvHZrDje9QjwSMAFL3iwXwQ==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-loongarch64-gnu@4.41.0': - resolution: {integrity: sha512-WbnJaxPv1gPIm6S8O/Wg+wfE/OzGSXlBMbOe4ie+zMyykMOeqmgD1BhPxZQuDqwUN+0T/xOFtL2RUWBspnZj3w==} - cpu: [loong64] - os: [linux] - - '@rollup/rollup-linux-powerpc64le-gnu@4.41.0': - resolution: {integrity: sha512-eRDWR5t67/b2g8Q/S8XPi0YdbKcCs4WQ8vklNnUYLaSWF+Cbv2axZsp4jni6/j7eKvMLYCYdcsv8dcU+a6QNFg==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-riscv64-gnu@4.41.0': - resolution: {integrity: sha512-TWrZb6GF5jsEKG7T1IHwlLMDRy2f3DPqYldmIhnA2DVqvvhY2Ai184vZGgahRrg8k9UBWoSlHv+suRfTN7Ua4A==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-riscv64-musl@4.41.0': - resolution: {integrity: sha512-ieQljaZKuJpmWvd8gW87ZmSFwid6AxMDk5bhONJ57U8zT77zpZ/TPKkU9HpnnFrM4zsgr4kiGuzbIbZTGi7u9A==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-s390x-gnu@4.41.0': - resolution: {integrity: sha512-/L3pW48SxrWAlVsKCN0dGLB2bi8Nv8pr5S5ocSM+S0XCn5RCVCXqi8GVtHFsOBBCSeR+u9brV2zno5+mg3S4Aw==} - cpu: [s390x] - os: [linux] - - '@rollup/rollup-linux-x64-gnu@4.41.0': - resolution: {integrity: sha512-XMLeKjyH8NsEDCRptf6LO8lJk23o9wvB+dJwcXMaH6ZQbbkHu2dbGIUindbMtRN6ux1xKi16iXWu6q9mu7gDhQ==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-linux-x64-musl@4.41.0': - resolution: {integrity: sha512-m/P7LycHZTvSQeXhFmgmdqEiTqSV80zn6xHaQ1JSqwCtD1YGtwEK515Qmy9DcB2HK4dOUVypQxvhVSy06cJPEg==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-win32-arm64-msvc@4.41.0': - resolution: {integrity: sha512-4yodtcOrFHpbomJGVEqZ8fzD4kfBeCbpsUy5Pqk4RluXOdsWdjLnjhiKy2w3qzcASWd04fp52Xz7JKarVJ5BTg==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.41.0': - resolution: {integrity: sha512-tmazCrAsKzdkXssEc65zIE1oC6xPHwfy9d5Ta25SRCDOZS+I6RypVVShWALNuU9bxIfGA0aqrmzlzoM5wO5SPQ==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.41.0': - resolution: {integrity: sha512-h1J+Yzjo/X+0EAvR2kIXJDuTuyT7drc+t2ALY0nIcGPbTatNOf0VWdhEA2Z4AAjv6X1NJV7SYo5oCTYRJhSlVA==} - cpu: [x64] - os: [win32] - '@scalar/express-api-reference@0.4.182': resolution: {integrity: sha512-T8y+/FM24H1C13GMDkjmM62obEhfGclIPwR2tn2JK+TY6LhKuHAF0xPzaBkfiRjlSEnrJigJSJxb8lwGxHWr9A==} engines: {node: '>=18'} @@ -691,12 +399,6 @@ packages: resolution: {integrity: sha512-4mQYkQJO0HHaoFd8Z+vSdQAvYcCJ2bRLN9ewE+GneB8kvoLG/oM3ynroqzGQdoytH8BmhnJwD3aEUagfbK2x5g==} engines: {node: '>=18'} - '@selderee/plugin-htmlparser2@0.11.0': - resolution: {integrity: sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==} - - '@standard-schema/spec@1.0.0': - resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} - '@swc/helpers@0.5.15': resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} @@ -754,18 +456,12 @@ packages: '@types/debug@4.1.8': resolution: {integrity: sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==} - '@types/estree@1.0.7': - resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} - '@types/express-serve-static-core@4.19.6': resolution: {integrity: sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==} '@types/express@4.17.21': resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==} - '@types/html-to-text@9.0.4': - resolution: {integrity: sha512-pUY3cKH/Nm2yYrEmDlPR1mR7yszjGx4DrwPjQ702C4/D5CwHuZTgZdIdwPkRbcuhs7BAh2L5rg3CL5cbRiGTCQ==} - '@types/http-assert@1.5.6': resolution: {integrity: sha512-TTEwmtjgVbYAzZYWyeHPrrtWnfVkm8tQkP8P21uQifPgMRgjrow3XDEYqucuC8SKZJT7pUnhU/JymvjggxO9vw==} @@ -796,9 +492,6 @@ 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==} @@ -829,40 +522,6 @@ packages: '@unhead/schema@1.11.14': resolution: {integrity: sha512-V9W9u5tF1/+TiLqxu+Qvh1ShoMDkPEwHoEo4DKdDG6ko7YlbzFfDxV6el9JwCren45U/4Vy/4Xi7j8OH02wsiA==} - '@vitest/expect@3.1.4': - resolution: {integrity: sha512-xkD/ljeliyaClDYqHPNCiJ0plY5YIcM0OlRiZizLhlPmpXWpxnGMyTZXOHFhFeG7w9P5PBeL4IdtJ/HeQwTbQA==} - - '@vitest/mocker@3.1.4': - resolution: {integrity: sha512-8IJ3CvwtSw/EFXqWFL8aCMu+YyYXG2WUSrQbViOZkWTKTVicVwZ/YiEZDSqD00kX+v/+W+OnxhNWoeVKorHygA==} - peerDependencies: - msw: ^2.4.9 - vite: ^5.0.0 || ^6.0.0 - peerDependenciesMeta: - msw: - optional: true - vite: - optional: true - - '@vitest/pretty-format@3.1.4': - resolution: {integrity: sha512-cqv9H9GvAEoTaoq+cYqUTCGscUjKqlJZC7PRwY5FMySVj5J+xOm1KQcCiYHJOEzOKRUhLH4R2pTwvFlWCEScsg==} - - '@vitest/runner@3.1.4': - resolution: {integrity: sha512-djTeF1/vt985I/wpKVFBMWUlk/I7mb5hmD5oP8K9ACRmVXgKTae3TUOtXAEBfslNKPzUQvnKhNd34nnRSYgLNQ==} - - '@vitest/snapshot@3.1.4': - resolution: {integrity: sha512-JPHf68DvuO7vilmvwdPr9TS0SuuIzHvxeaCkxYcCD4jTk67XwL45ZhEHFKIuCm8CYstgI6LZ4XbwD6ANrwMpFg==} - - '@vitest/spy@3.1.4': - resolution: {integrity: sha512-Xg1bXhu+vtPXIodYN369M86K8shGLouNjoVI78g8iAq2rFoHFdajNvJJ5A/9bPMFcfQqdaCpOgWKEoMQg/s0Yg==} - - '@vitest/ui@3.1.4': - resolution: {integrity: sha512-CFc2Bpb3sz4Sdt53kdNGq+qZKLftBwX4qZLC03CBUc0N1LJrOoL0ZeK0oq/708mtnpwccL0BZCY9d1WuiBSr7Q==} - peerDependencies: - vitest: 3.1.4 - - '@vitest/utils@3.1.4': - resolution: {integrity: sha512-yriMuO1cfFhmiGc8ataN51+9ooHRuURdfAZfwFd3usWynjzpLslZdYnRegTv32qdgtJTsj15FoeZe2g15fY1gg==} - '@zxing/text-encoding@0.9.0': resolution: {integrity: sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==} @@ -928,9 +587,6 @@ 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'} @@ -964,6 +620,12 @@ packages: array-flatten@1.1.1: resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} + array-parallel@0.1.3: + resolution: {integrity: sha512-TDPTwSWW5E4oiFiKmz6RGJ/a80Y91GuLgUYuLd49+XBS75tYo8PNgaT2K/OxuQYqkoI852MDGBorg9OcUSTQ8w==} + + array-series@0.1.5: + resolution: {integrity: sha512-L0XlBwfx9QetHOsbLDrE/vh2t018w9462HM3iaFfxRiK83aJjAt/Ja3NMkOW7FICwWTlQBa3ZbL5FKhuQWkDrg==} + array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} @@ -982,10 +644,6 @@ packages: asn1.js@5.4.1: resolution: {integrity: sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==} - assertion-error@2.0.1: - resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} - engines: {node: '>=12'} - astral-regex@2.0.0: resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} engines: {node: '>=8'} @@ -1014,6 +672,9 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + barcode@0.1.0: + resolution: {integrity: sha512-GslbXakjG61fwHnIN/vrUkPsa61WVAJDnb7jAwmbjRW5bZdwINymo1+FgjYJrGf2MDHxAt3bUWgmEMF8ETZxHQ==} + base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} @@ -1021,10 +682,6 @@ 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'} @@ -1032,18 +689,12 @@ 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==} @@ -1074,40 +725,13 @@ 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'} - c12@3.1.0: - resolution: {integrity: sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==} - peerDependencies: - magicast: ^0.3.5 - peerDependenciesMeta: - magicast: - optional: true - - cac@6.7.14: - resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} - engines: {node: '>=8'} - call-bind-apply-helpers@1.0.1: resolution: {integrity: sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==} engines: {node: '>= 0.4'} @@ -1120,17 +744,6 @@ packages: resolution: {integrity: sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==} engines: {node: '>= 0.4'} - canvas@3.1.0: - resolution: {integrity: sha512-tTj3CqqukVJ9NgSahykNwtGda7V33VLObwrHfzT0vqJXu7J4d4C/7kQQW3fOEGDfZZoILPut5H00gOjyttPGyg==} - engines: {node: ^18.12.0 || >= 20.9.0} - - chai@5.2.0: - resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==} - engines: {node: '>=12'} - - chainsaw@0.1.0: - resolution: {integrity: sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==} - chalk-template@0.4.0: resolution: {integrity: sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==} engines: {node: '>=12'} @@ -1139,10 +752,6 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} - check-error@2.1.1: - resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} - engines: {node: '>= 16'} - checkpoint-client@1.1.27: resolution: {integrity: sha512-xstymfUalJOv6ZvTtmkwP4ORJN36ikT4PvrIoLe3wstbYf87XIXCcZrSmbFQOjyB0v1qbBnCsAscDpfdZlCkFA==} @@ -1153,20 +762,10 @@ packages: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} - chokidar@4.0.3: - resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} - engines: {node: '>= 14.16.0'} - - chownr@1.1.4: - resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} - ci-info@3.8.0: resolution: {integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==} engines: {node: '>=8'} - citty@0.1.6: - resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} - cjs-module-lexer@1.4.1: resolution: {integrity: sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==} @@ -1222,17 +821,6 @@ 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} - - confbox@0.2.2: - resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==} - - consola@3.4.2: - resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} - engines: {node: ^14.18.0 || >=16.10.0} - console-log-level@1.4.1: resolution: {integrity: sha512-VZzbIORbP+PPcN/gg3DXClTLPLg5Slwd5fL2MIc+o1qZ4BXBvWyc6QxPk6T/Mkr6IVjRpoAGf32XxP3ZWMVRcQ==} @@ -1289,9 +877,6 @@ packages: resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} engines: {node: '>=8'} - csv-parse@6.1.0: - resolution: {integrity: sha512-CEE+jwpgLn+MmtCpVcPtiCZpVtB6Z2OKPTr34pycYYoL7sxdOkXDdQ4lRiw6ioC0q6BLqhc6cKweCVvral8yhw==} - data-view-buffer@1.0.1: resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} engines: {node: '>= 0.4'} @@ -1310,6 +895,14 @@ packages: dayjs@1.11.13: resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} + debug@0.7.0: + resolution: {integrity: sha512-UWZnvGiX9tQgtrsA+mhGLKnUFvr1moempl9IvqQKyFnEgN0T4kpCE+KJcqTLcVxQjRVRnLF3VSE1Hchki5N98g==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -1340,30 +933,10 @@ packages: resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} engines: {node: '>=0.10'} - decompress-response@6.0.0: - resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} - engines: {node: '>=10'} - deeks@3.1.0: resolution: {integrity: sha512-e7oWH1LzIdv/prMQ7pmlDlaVoL64glqzvNgkgQNgyec9ORPHrT2jaOqMtRyqJuwWjtfb6v+2rk9pmaHj+F137A==} engines: {node: '>= 16'} - deep-eql@5.0.2: - resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} - engines: {node: '>=6'} - - deep-extend@0.6.0: - resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} - engines: {node: '>=4.0.0'} - - deepmerge-ts@7.1.5: - resolution: {integrity: sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==} - engines: {node: '>=16.0.0'} - - deepmerge@4.3.1: - resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} - engines: {node: '>=0.10.0'} - define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} @@ -1372,9 +945,6 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} - defu@6.1.4: - resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} - del@6.1.1: resolution: {integrity: sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==} engines: {node: '>=10'} @@ -1383,17 +953,10 @@ packages: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} - destr@2.0.5: - resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} - destroy@1.2.0: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - detect-libc@2.0.4: - resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} - engines: {node: '>=8'} - diff@4.0.2: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} engines: {node: '>=0.3.1'} @@ -1410,19 +973,6 @@ packages: resolution: {integrity: sha512-tTmR3WhROYctuyVReQ+PfCU3zprmC45/VuSVzn8EjovzpRkXYUdXiDatB9M8pasj0V+wuuOyY8bcSHvlQ2GNag==} engines: {node: '>=6'} - dom-serializer@2.0.0: - resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} - - domelementtype@2.3.0: - resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} - - domhandler@5.0.3: - resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} - engines: {node: '>= 4'} - - domutils@3.2.2: - resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} - dotenv@16.0.3: resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==} engines: {node: '>=12'} @@ -1431,17 +981,10 @@ packages: resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==} engines: {node: '>=12'} - dotenv@16.6.1: - resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} - engines: {node: '>=12'} - dunder-proto@1.0.0: 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==} @@ -1451,9 +994,6 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - effect@3.16.12: - resolution: {integrity: sha512-N39iBk0K71F9nb442TLbTkjl24FLUzuvx2i1I2RsEAQsdAdUTuUoW0vlfUXgkMTUOnYqKnWcFfqw4hK4Pw27hg==} - elastic-apm-node@3.52.2: resolution: {integrity: sha512-NVFthDcoBOpTwtppF7b+BIeIu4Xon3RBNpddIaJv+DtjL6Q61x4j7ClYdiXjv3XKgyp7yUlOnLjU6PY/EYXwLQ==} engines: {node: '>=8.6.0'} @@ -1464,10 +1004,6 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - empathic@2.0.0: - resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} - engines: {node: '>=14'} - enabled@2.0.0: resolution: {integrity: sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==} @@ -1485,10 +1021,6 @@ packages: end-of-stream@1.4.4: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} - entities@4.5.0: - resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} - engines: {node: '>=0.12'} - env-paths@2.2.1: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} @@ -1525,9 +1057,6 @@ packages: es-get-iterator@1.1.3: resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==} - es-module-lexer@1.7.0: - resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} - es-object-atoms@1.0.0: resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} engines: {node: '>= 0.4'} @@ -1540,11 +1069,6 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} - esbuild@0.25.4: - resolution: {integrity: sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==} - engines: {node: '>=18'} - hasBin: true - escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -1556,9 +1080,6 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} - estree-walker@3.0.3: - resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - etag@1.8.1: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} @@ -1566,37 +1087,14 @@ 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'} - expand-template@2.0.3: - resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} - engines: {node: '>=6'} - - expect-type@1.2.1: - resolution: {integrity: sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==} - engines: {node: '>=12.0.0'} - express@4.21.2: resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} engines: {node: '>= 0.10.0'} - exsolve@1.0.7: - resolution: {integrity: sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==} - - fast-check@3.23.2: - resolution: {integrity: sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==} - engines: {node: '>=8.0.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'} @@ -1622,20 +1120,9 @@ packages: fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} - fdir@6.4.4: - resolution: {integrity: sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - fecha@4.2.3: resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==} - fflate@0.8.2: - resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} - fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -1670,9 +1157,6 @@ packages: flatstr@1.0.12: resolution: {integrity: sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw==} - flatted@3.3.3: - resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} - fn.name@1.1.0: resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==} @@ -1719,11 +1203,6 @@ 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==} @@ -1750,13 +1229,6 @@ packages: resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} engines: {node: '>= 0.4'} - giget@2.0.0: - resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==} - hasBin: true - - github-from-package@0.0.0: - resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} - glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -1786,6 +1258,11 @@ packages: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} + gm@1.16.0: + resolution: {integrity: sha512-b5oVGr8wCI7VNfjzeXiFocCZrcpkRUxSoVYfksBMEp/jo2nYwRKhcfOURarxFwjXyW1GvEY2EmmupVLnh0vXjg==} + engines: {node: '>= 0.8.0'} + deprecated: The gm module has been sunset. Please migrate to an alternative. https://github.com/aheckmann/gm?tab=readme-ov-file#2025-02-24-this-project-is-not-maintained + gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -1842,13 +1319,6 @@ packages: resolution: {integrity: sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA==} engines: {node: '>=14'} - html-to-text@9.0.5: - resolution: {integrity: sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==} - engines: {node: '>=14'} - - htmlparser2@8.0.2: - resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} - http-errors@2.0.0: resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} engines: {node: '>= 0.8'} @@ -1910,9 +1380,6 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - ini@1.3.8: - resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - ini@2.0.0: resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==} engines: {node: '>=10'} @@ -2107,16 +1574,9 @@ packages: jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - jiti@2.5.1: - resolution: {integrity: sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==} - hasBin: true - js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - jsbarcode@3.11.6: - resolution: {integrity: sha512-G5TKGyKY1zJo0ZQKFM1IIMfy0nF2rs92BLlCz+cU4/TazIc4ZH+X1GYeDRt7TKjrYqmPfTjwTBkU/QnQlsYiuA==} - json-2-csv@5.5.8: resolution: {integrity: sha512-eMQHOwV+av8Sgo+fkbEbQWOw/kwh89AZ5fNA8TYfcooG6TG1ZOL2WcPUrngIMIK8dBJitQ8QEU0zbncQ0CX4CQ==} engines: {node: '>= 16'} @@ -2153,9 +1613,6 @@ packages: resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} engines: {node: '>= 0.6.3'} - leac@0.6.0: - resolution: {integrity: sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==} - lie@3.3.0: resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} @@ -2166,9 +1623,6 @@ 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'} @@ -2195,13 +1649,6 @@ 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==} @@ -2233,9 +1680,6 @@ packages: resolution: {integrity: sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==} engines: {node: '>= 12.0.0'} - loupe@3.1.3: - resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==} - lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} @@ -2250,9 +1694,6 @@ packages: resolution: {integrity: sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==} engines: {node: '>=12'} - magic-string@0.30.17: - resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} - make-dir@3.1.0: resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} engines: {node: '>=8'} @@ -2326,10 +1767,6 @@ packages: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} - mimic-response@3.1.0: - resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} - engines: {node: '>=10'} - min-indent@1.0.1: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} @@ -2359,13 +1796,6 @@ packages: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} - mkdirp-classic@0.5.3: - resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} - - mkdirp@0.5.6: - resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} - hasBin: true - mnemonist@0.39.8: resolution: {integrity: sha512-vyWo2K3fjrUw8YeeZ1zF0fy6Mu59RHokURlld8ymdUPjMlD9EC9ov1/YPqTgqRvUN9nTr3Gqfz29LYAmu0PHPQ==} @@ -2379,10 +1809,6 @@ packages: resolution: {integrity: sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==} engines: {node: '>= 0.8.0'} - mrmime@2.0.1: - resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} - engines: {node: '>=10'} - ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} @@ -2392,18 +1818,6 @@ 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'} - - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - napi-build-utils@2.0.0: - resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} - negotiator@0.6.3: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} @@ -2418,16 +1832,6 @@ packages: next-line@1.1.0: resolution: {integrity: sha512-+I10J3wKNoKddNxn0CNpoZ3eTZuqxjNM3b1GImVx22+ePI+Y15P8g/j3WsbP0fhzzrFzrtjOAoq5NCCucswXOQ==} - node-abi@3.75.0: - resolution: {integrity: sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg==} - engines: {node: '>=10'} - - node-addon-api@7.1.1: - resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} - - node-fetch-native@1.6.7: - resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} - node-fetch@2.6.12: resolution: {integrity: sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==} engines: {node: 4.x || >=6.0.0} @@ -2479,11 +1883,6 @@ packages: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} - nypm@0.6.1: - resolution: {integrity: sha512-hlacBiRiv1k9hZFiphPUkfSQ/ZfQzZDzC+8z0wL3lvDAOUu/2NnChkKuMoMjNur/9OpKuz2QsIeiPVN0xM5Q0w==} - engines: {node: ^14.16.0 || >=16.10.0} - hasBin: true - object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -2513,9 +1912,6 @@ packages: obliterator@2.0.4: resolution: {integrity: sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==} - ohash@2.0.11: - resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} - on-finished@2.3.0: resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} engines: {node: '>= 0.8'} @@ -2594,9 +1990,6 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} - parseley@0.12.1: - resolution: {integrity: sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==} - parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} @@ -2627,19 +2020,6 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} - pathe@2.0.3: - resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - - pathval@2.0.0: - resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} - engines: {node: '>= 14.16'} - - peberminta@0.9.0: - resolution: {integrity: sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==} - - perfect-debounce@1.0.0: - resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} - picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -2647,10 +2027,6 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - picomatch@4.0.2: - resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} - engines: {node: '>=12'} - pino-std-serializers@3.2.0: resolution: {integrity: sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg==} @@ -2662,27 +2038,10 @@ packages: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} - pkg-types@2.3.0: - resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} - - pnpm@10.28.0: - resolution: {integrity: sha512-Bd9x0UIfITmeBT/eVnzqNNRG+gLHZXFEG/wceVbpjjYwiJgtlARl/TRIDU2QoGaLwSNi+KqIAApk6D0LDke+SA==} - engines: {node: '>=18.12'} - hasBin: true - possible-typed-array-names@1.0.0: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} - postcss@8.5.3: - resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} - engines: {node: ^10 || ^12 || >=14} - - prebuild-install@7.1.3: - resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} - engines: {node: '>=10'} - hasBin: true - prettier@3.4.2: resolution: {integrity: sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==} engines: {node: '>=14'} @@ -2697,8 +2056,8 @@ packages: resolution: {integrity: sha512-VpNpolZ8RXRgfU+j4R+fPZmX8EE95w3vJ2tt7+FwuiQc0leNTfLK5QLf3KbbPDes2rfjh3g20AjDxefQIo5GIA==} hasBin: true - prisma@6.16.2: - resolution: {integrity: sha512-aRvldGE5UUJTtVmFiH3WfNFNiqFlAtePUxcI0UEGlnXCX7DqhiMT5TRYwncHFeA/Reca5W6ToXXyCMTeFPdSXA==} + prisma@6.3.0: + resolution: {integrity: sha512-y+Zh3Qg+xGCWyyrNUUNaFW/OltaV/yXYuTa0WRgYkz5LGyifmAsgpv94I47+qGRocZrMGcbF2A/78/oO2zgifA==} engines: {node: '>=18.18'} hasBin: true peerDependencies: @@ -2738,16 +2097,10 @@ packages: pstree.remy@1.1.8: resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} - pump@3.0.2: - resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} - punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - pure-rand@6.1.0: - resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} - qs@6.13.0: resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} engines: {node: '>=0.6'} @@ -2770,13 +2123,6 @@ packages: resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} engines: {node: '>= 0.8'} - rc9@2.1.2: - resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} - - rc@1.2.8: - resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} - hasBin: true - read-pkg-up@7.0.1: resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} engines: {node: '>=8'} @@ -2799,10 +2145,6 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} - readdirp@4.1.2: - resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} - engines: {node: '>= 14.18.0'} - reflect-metadata@0.2.2: resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} @@ -2848,21 +2190,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 hasBin: true - rollup@4.41.0: - resolution: {integrity: sha512-HqMFpUbWlf/tvcxBFNKnJyzc7Lk+XO3FGc3pbNBLqEbOz0gPLRgcrlS3UF4MfUrVlstOaP/q0kM6GVvi+LrLRg==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -2893,16 +2225,9 @@ 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==} - selderee@0.11.0: - resolution: {integrity: sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==} - semver@5.7.2: resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} hasBin: true @@ -2965,9 +2290,6 @@ packages: resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} engines: {node: '>= 0.4'} - siginfo@2.0.0: - resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -2975,12 +2297,6 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - simple-concat@1.0.1: - resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} - - simple-get@4.0.1: - resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} - simple-swizzle@0.2.2: resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} @@ -2988,10 +2304,6 @@ packages: resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} engines: {node: '>=10'} - sirv@3.0.1: - resolution: {integrity: sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==} - engines: {node: '>=18'} - sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} @@ -3006,10 +2318,6 @@ packages: sonic-boom@1.4.1: resolution: {integrity: sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg==} - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} @@ -3040,9 +2348,6 @@ packages: stack-trace@0.0.10: resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} - stackback@0.0.2: - resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - stackframe@1.3.4: resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==} @@ -3050,9 +2355,6 @@ packages: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} - std-env@3.9.0: - resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} - stop-iteration-iterator@1.1.0: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} @@ -3066,9 +2368,9 @@ packages: stream-json@1.9.1: resolution: {integrity: sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw==} - streamsearch@1.1.0: - resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} - engines: {node: '>=10.0.0'} + stream-to-buffer@0.0.1: + resolution: {integrity: sha512-LsvisgE3iThboRqA+XLmtnY9ktPLVPOj3zZxXMhlezeCcAh0RhomquXJgB8H+lb/RR/pPcbNVGHVKFUwjpoRtw==} + engines: {node: '>= 0.8'} strict-uri-encode@2.0.0: resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==} @@ -3116,10 +2418,6 @@ packages: resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} engines: {node: '>=8'} - strip-json-comments@2.0.1: - resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} - engines: {node: '>=0.10.0'} - strnum@1.0.5: resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} @@ -3143,9 +2441,6 @@ packages: resolution: {integrity: sha512-iK5/YhZxq5GO5z8wb0bY1317uDF3Zjpha0QFFLA8/trAoiLbQD0HUbMesEaxyzUgDxi2QlcbM8IvqOlEjgoXBA==} engines: {node: '>=12.17'} - tar-fs@2.1.2: - resolution: {integrity: sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==} - tar-stream@2.2.0: resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} engines: {node: '>=6'} @@ -3171,30 +2466,8 @@ packages: through2@4.0.2: resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} - tinybench@2.9.0: - resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - - tinyexec@0.3.2: - resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - - tinyexec@1.0.1: - resolution: {integrity: sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==} - - tinyglobby@0.2.13: - resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==} - engines: {node: '>=12.0.0'} - - tinypool@1.0.2: - resolution: {integrity: sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==} - engines: {node: ^18.0.0 || >=20.0.0} - - tinyrainbow@2.0.0: - resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} - engines: {node: '>=14.0.0'} - - tinyspy@3.0.2: - resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} - engines: {node: '>=14.0.0'} + through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} tmp@0.2.1: resolution: {integrity: sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==} @@ -3215,10 +2488,6 @@ packages: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} - totalist@3.0.1: - resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} - engines: {node: '>=6'} - touch@3.1.1: resolution: {integrity: sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==} hasBin: true @@ -3229,9 +2498,6 @@ 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'} @@ -3265,9 +2531,6 @@ packages: engines: {node: '>=18.0.0', yarn: '>=1.9.4'} hasBin: true - tunnel-agent@0.6.0: - resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} - type-fest@0.16.0: resolution: {integrity: sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==} engines: {node: '>=10'} @@ -3304,9 +2567,6 @@ 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'} @@ -3356,9 +2616,6 @@ 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==} @@ -3369,10 +2626,6 @@ 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 @@ -3391,79 +2644,6 @@ packages: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} - vite-node@3.1.4: - resolution: {integrity: sha512-6enNwYnpyDo4hEgytbmc6mYWHXDHYEn0D1/rw4Q+tnHUGtKTJsn8T1YkX6Q18wI5LCrS8CTYlBaiCqxOy2kvUA==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true - - vite@6.3.5: - resolution: {integrity: sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true - peerDependencies: - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - jiti: '>=1.21.0' - less: '*' - lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - - vitest@3.1.4: - resolution: {integrity: sha512-Ta56rT7uWxCSJXlBtKgIlApJnT6e6IGmTYxYcmxjJ4ujuZDI59GUQgVDObXXJujOmPDBYXHK1qmaGtneu6TNIQ==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@types/debug': ^4.1.12 - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - '@vitest/browser': 3.1.4 - '@vitest/ui': 3.1.4 - happy-dom: '*' - jsdom: '*' - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@types/debug': - optional: true - '@types/node': - optional: true - '@vitest/browser': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true - web-encoding@1.1.5: resolution: {integrity: sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==} @@ -3500,11 +2680,6 @@ packages: engines: {node: '>= 8'} hasBin: true - why-is-node-running@2.3.0: - resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} - engines: {node: '>=8'} - hasBin: true - winston-elasticsearch@0.19.0: resolution: {integrity: sha512-yD+Wi/NmMsKCSkWvzdmk2RZ2KSHJ+ox5PM/480nsahWFtiLESI90ESXnS8Yfvc0N4NFnCXNaIj2FERIgjImjoQ==} engines: {node: '>= 8.0.0'} @@ -3543,13 +2718,6 @@ 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'} @@ -3658,100 +2826,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@esbuild/aix-ppc64@0.25.4': - optional: true - - '@esbuild/android-arm64@0.25.4': - optional: true - - '@esbuild/android-arm@0.25.4': - optional: true - - '@esbuild/android-x64@0.25.4': - optional: true - - '@esbuild/darwin-arm64@0.25.4': - optional: true - - '@esbuild/darwin-x64@0.25.4': - optional: true - - '@esbuild/freebsd-arm64@0.25.4': - optional: true - - '@esbuild/freebsd-x64@0.25.4': - optional: true - - '@esbuild/linux-arm64@0.25.4': - optional: true - - '@esbuild/linux-arm@0.25.4': - optional: true - - '@esbuild/linux-ia32@0.25.4': - optional: true - - '@esbuild/linux-loong64@0.25.4': - optional: true - - '@esbuild/linux-mips64el@0.25.4': - optional: true - - '@esbuild/linux-ppc64@0.25.4': - optional: true - - '@esbuild/linux-riscv64@0.25.4': - optional: true - - '@esbuild/linux-s390x@0.25.4': - optional: true - - '@esbuild/linux-x64@0.25.4': - optional: true - - '@esbuild/netbsd-arm64@0.25.4': - optional: true - - '@esbuild/netbsd-x64@0.25.4': - optional: true - - '@esbuild/openbsd-arm64@0.25.4': - optional: true - - '@esbuild/openbsd-x64@0.25.4': - optional: true - - '@esbuild/sunos-x64@0.25.4': - optional: true - - '@esbuild/win32-arm64@0.25.4': - optional: true - - '@esbuild/win32-ia32@0.25.4': - optional: true - - '@esbuild/win32-x64@0.25.4': - optional: true - - '@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 @@ -3991,22 +3065,11 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@polka/url@1.0.0-next.29': {} - - '@prisma/client@6.16.2(prisma@6.16.2(typescript@5.7.2))(typescript@5.7.2)': + '@prisma/client@6.3.0(prisma@6.3.0(typescript@5.7.2))(typescript@5.7.2)': optionalDependencies: - prisma: 6.16.2(typescript@5.7.2) + prisma: 6.3.0(typescript@5.7.2) typescript: 5.7.2 - '@prisma/config@6.16.2': - dependencies: - c12: 3.1.0 - deepmerge-ts: 7.1.5 - effect: 3.16.12 - empathic: 2.0.0 - transitivePeerDependencies: - - magicast - '@prisma/debug@5.3.1': dependencies: '@types/debug': 4.1.8 @@ -4015,18 +3078,18 @@ snapshots: transitivePeerDependencies: - supports-color - '@prisma/debug@6.16.2': {} + '@prisma/debug@6.3.0': {} - '@prisma/engines-version@6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43': {} + '@prisma/engines-version@6.3.0-17.acc0b9dd43eb689cbd20c9470515d719db10d0b0': {} '@prisma/engines@5.3.1': {} - '@prisma/engines@6.16.2': + '@prisma/engines@6.3.0': dependencies: - '@prisma/debug': 6.16.2 - '@prisma/engines-version': 6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43 - '@prisma/fetch-engine': 6.16.2 - '@prisma/get-platform': 6.16.2 + '@prisma/debug': 6.3.0 + '@prisma/engines-version': 6.3.0-17.acc0b9dd43eb689cbd20c9470515d719db10d0b0 + '@prisma/fetch-engine': 6.3.0 + '@prisma/get-platform': 6.3.0 '@prisma/fetch-engine@5.3.1(encoding@0.1.13)': dependencies: @@ -4051,11 +3114,11 @@ snapshots: - encoding - supports-color - '@prisma/fetch-engine@6.16.2': + '@prisma/fetch-engine@6.3.0': dependencies: - '@prisma/debug': 6.16.2 - '@prisma/engines-version': 6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43 - '@prisma/get-platform': 6.16.2 + '@prisma/debug': 6.3.0 + '@prisma/engines-version': 6.3.0-17.acc0b9dd43eb689cbd20c9470515d719db10d0b0 + '@prisma/get-platform': 6.3.0 '@prisma/generator-helper@5.3.1': dependencies: @@ -4081,9 +3144,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@prisma/get-platform@6.16.2': + '@prisma/get-platform@6.3.0': dependencies: - '@prisma/debug': 6.16.2 + '@prisma/debug': 6.3.0 '@prisma/internals@5.3.1(encoding@0.1.13)': dependencies: @@ -4135,66 +3198,6 @@ snapshots: '@prisma/prisma-schema-wasm@5.3.1-2.61e140623197a131c2a6189271ffee05a7aa9a59': {} - '@rollup/rollup-android-arm-eabi@4.41.0': - optional: true - - '@rollup/rollup-android-arm64@4.41.0': - optional: true - - '@rollup/rollup-darwin-arm64@4.41.0': - optional: true - - '@rollup/rollup-darwin-x64@4.41.0': - optional: true - - '@rollup/rollup-freebsd-arm64@4.41.0': - optional: true - - '@rollup/rollup-freebsd-x64@4.41.0': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.41.0': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.41.0': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.41.0': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.41.0': - optional: true - - '@rollup/rollup-linux-loongarch64-gnu@4.41.0': - optional: true - - '@rollup/rollup-linux-powerpc64le-gnu@4.41.0': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.41.0': - optional: true - - '@rollup/rollup-linux-riscv64-musl@4.41.0': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.41.0': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.41.0': - optional: true - - '@rollup/rollup-linux-x64-musl@4.41.0': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.41.0': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.41.0': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.41.0': - optional: true - '@scalar/express-api-reference@0.4.182': dependencies: '@scalar/types': 0.0.33 @@ -4206,13 +3209,6 @@ snapshots: '@scalar/openapi-types': 0.1.7 '@unhead/schema': 1.11.14 - '@selderee/plugin-htmlparser2@0.11.0': - dependencies: - domhandler: 5.0.3 - selderee: 0.11.0 - - '@standard-schema/spec@1.0.0': {} - '@swc/helpers@0.5.15': dependencies: tslib: 2.8.1 @@ -4296,8 +3292,6 @@ snapshots: dependencies: '@types/ms': 0.7.34 - '@types/estree@1.0.7': {} - '@types/express-serve-static-core@4.19.6': dependencies: '@types/node': 20.17.10 @@ -4312,8 +3306,6 @@ snapshots: '@types/qs': 6.9.17 '@types/serve-static': 1.15.7 - '@types/html-to-text@9.0.4': {} - '@types/http-assert@1.5.6': {} '@types/http-errors@2.0.4': {} @@ -4349,8 +3341,6 @@ snapshots: dependencies: '@types/express': 4.17.21 - '@types/node@14.18.63': {} - '@types/node@20.17.10': dependencies: undici-types: 6.19.8 @@ -4385,57 +3375,6 @@ snapshots: hookable: 5.5.3 zhead: 2.2.4 - '@vitest/expect@3.1.4': - dependencies: - '@vitest/spy': 3.1.4 - '@vitest/utils': 3.1.4 - chai: 5.2.0 - tinyrainbow: 2.0.0 - - '@vitest/mocker@3.1.4(vite@6.3.5(@types/node@20.17.10)(jiti@2.5.1)(yaml@2.6.1))': - dependencies: - '@vitest/spy': 3.1.4 - estree-walker: 3.0.3 - magic-string: 0.30.17 - optionalDependencies: - vite: 6.3.5(@types/node@20.17.10)(jiti@2.5.1)(yaml@2.6.1) - - '@vitest/pretty-format@3.1.4': - dependencies: - tinyrainbow: 2.0.0 - - '@vitest/runner@3.1.4': - dependencies: - '@vitest/utils': 3.1.4 - pathe: 2.0.3 - - '@vitest/snapshot@3.1.4': - dependencies: - '@vitest/pretty-format': 3.1.4 - magic-string: 0.30.17 - pathe: 2.0.3 - - '@vitest/spy@3.1.4': - dependencies: - tinyspy: 3.0.2 - - '@vitest/ui@3.1.4(vitest@3.1.4)': - dependencies: - '@vitest/utils': 3.1.4 - fflate: 0.8.2 - flatted: 3.3.3 - pathe: 2.0.3 - sirv: 3.0.1 - tinyglobby: 0.2.13 - tinyrainbow: 2.0.0 - vitest: 3.1.4(@types/node@20.17.10)(@vitest/ui@3.1.4)(jiti@2.5.1)(yaml@2.6.1) - - '@vitest/utils@3.1.4': - dependencies: - '@vitest/pretty-format': 3.1.4 - loupe: 3.1.3 - tinyrainbow: 2.0.0 - '@zxing/text-encoding@0.9.0': optional: true @@ -4501,8 +3440,6 @@ 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 @@ -4554,6 +3491,10 @@ snapshots: array-flatten@1.1.1: {} + array-parallel@0.1.3: {} + + array-series@0.1.5: {} + array-union@2.1.0: {} array.prototype.map@1.0.7: @@ -4584,8 +3525,6 @@ snapshots: minimalistic-assert: 1.0.1 safer-buffer: 2.1.2 - assertion-error@2.0.1: {} - astral-regex@2.0.0: {} async-cache@1.1.0: @@ -4612,24 +3551,23 @@ snapshots: balanced-match@1.0.2: {} + barcode@0.1.0: + dependencies: + gm: 1.16.0 + transitivePeerDependencies: + - supports-color + base64-js@1.5.1: {} basic-auth@2.0.1: 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 @@ -4640,8 +3578,6 @@ snapshots: dependencies: readable-stream: 3.6.2 - bluebird@3.4.7: {} - bn.js@4.12.1: {} body-parser@1.20.3: @@ -4685,40 +3621,13 @@ 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: {} - c12@3.1.0: - dependencies: - chokidar: 4.0.3 - confbox: 0.2.2 - defu: 6.1.4 - dotenv: 16.6.1 - exsolve: 1.0.7 - giget: 2.0.0 - jiti: 2.5.1 - ohash: 2.0.11 - pathe: 2.0.3 - perfect-debounce: 1.0.0 - pkg-types: 2.3.0 - rc9: 2.1.2 - - cac@6.7.14: {} - call-bind-apply-helpers@1.0.1: dependencies: es-errors: 1.3.0 @@ -4736,23 +3645,6 @@ snapshots: call-bind-apply-helpers: 1.0.1 get-intrinsic: 1.2.6 - canvas@3.1.0: - dependencies: - node-addon-api: 7.1.1 - prebuild-install: 7.1.3 - - chai@5.2.0: - dependencies: - assertion-error: 2.0.1 - check-error: 2.1.1 - deep-eql: 5.0.2 - loupe: 3.1.3 - pathval: 2.0.0 - - chainsaw@0.1.0: - dependencies: - traverse: 0.3.9 - chalk-template@0.4.0: dependencies: chalk: 4.1.2 @@ -4762,8 +3654,6 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 - check-error@2.1.1: {} - checkpoint-client@1.1.27(encoding@0.1.13): dependencies: ci-info: 3.8.0 @@ -4796,18 +3686,8 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - chokidar@4.0.3: - dependencies: - readdirp: 4.1.2 - - chownr@1.1.4: {} - ci-info@3.8.0: {} - citty@0.1.6: - dependencies: - consola: 3.4.2 - cjs-module-lexer@1.4.1: optional: true @@ -4876,17 +3756,6 @@ 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 - - confbox@0.2.2: {} - - consola@3.4.2: {} - console-log-level@1.4.1: optional: true @@ -4938,8 +3807,6 @@ snapshots: crypto-random-string@2.0.0: {} - csv-parse@6.1.0: {} - data-view-buffer@1.0.1: dependencies: call-bind: 1.0.8 @@ -4962,6 +3829,8 @@ snapshots: dayjs@1.11.13: {} + debug@0.7.0: {} + debug@2.6.9: dependencies: ms: 2.0.0 @@ -4978,20 +3847,8 @@ snapshots: decode-uri-component@0.2.2: {} - decompress-response@6.0.0: - dependencies: - mimic-response: 3.1.0 - deeks@3.1.0: {} - deep-eql@5.0.2: {} - - deep-extend@0.6.0: {} - - deepmerge-ts@7.1.5: {} - - deepmerge@4.3.1: {} - define-data-property@1.1.4: dependencies: es-define-property: 1.0.1 @@ -5004,8 +3861,6 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 - defu@6.1.4: {} - del@6.1.1: dependencies: globby: 11.1.0 @@ -5019,12 +3874,8 @@ snapshots: depd@2.0.0: {} - destr@2.0.5: {} - destroy@1.2.0: {} - detect-libc@2.0.4: {} - diff@4.0.2: {} dir-glob@3.0.1: @@ -5038,40 +3889,16 @@ snapshots: jszip: 3.10.1 sax: 1.3.0 - dom-serializer@2.0.0: - dependencies: - domelementtype: 2.3.0 - domhandler: 5.0.3 - entities: 4.5.0 - - domelementtype@2.3.0: {} - - domhandler@5.0.3: - dependencies: - domelementtype: 2.3.0 - - domutils@3.2.2: - dependencies: - dom-serializer: 2.0.0 - domelementtype: 2.3.0 - domhandler: 5.0.3 - dotenv@16.0.3: {} dotenv@16.4.7: {} - dotenv@16.6.1: {} - dunder-proto@1.0.0: dependencies: call-bind-apply-helpers: 1.0.1 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: @@ -5080,11 +3907,6 @@ snapshots: ee-first@1.1.1: {} - effect@3.16.12: - dependencies: - '@standard-schema/spec': 1.0.0 - fast-check: 3.23.2 - elastic-apm-node@3.52.2: dependencies: '@elastic/ecs-pino-format': 1.5.0 @@ -5133,8 +3955,6 @@ snapshots: emoji-regex@9.2.2: {} - empathic@2.0.0: {} - enabled@2.0.0: {} encodeurl@1.0.2: {} @@ -5150,8 +3970,6 @@ snapshots: dependencies: once: 1.4.0 - entities@4.5.0: {} - env-paths@2.2.1: {} error-callsites@2.0.4: @@ -5244,8 +4062,6 @@ snapshots: isarray: 2.0.5 stop-iteration-iterator: 1.1.0 - es-module-lexer@1.7.0: {} - es-object-atoms@1.0.0: dependencies: es-errors: 1.3.0 @@ -5262,60 +4078,16 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 - esbuild@0.25.4: - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.4 - '@esbuild/android-arm': 0.25.4 - '@esbuild/android-arm64': 0.25.4 - '@esbuild/android-x64': 0.25.4 - '@esbuild/darwin-arm64': 0.25.4 - '@esbuild/darwin-x64': 0.25.4 - '@esbuild/freebsd-arm64': 0.25.4 - '@esbuild/freebsd-x64': 0.25.4 - '@esbuild/linux-arm': 0.25.4 - '@esbuild/linux-arm64': 0.25.4 - '@esbuild/linux-ia32': 0.25.4 - '@esbuild/linux-loong64': 0.25.4 - '@esbuild/linux-mips64el': 0.25.4 - '@esbuild/linux-ppc64': 0.25.4 - '@esbuild/linux-riscv64': 0.25.4 - '@esbuild/linux-s390x': 0.25.4 - '@esbuild/linux-x64': 0.25.4 - '@esbuild/netbsd-arm64': 0.25.4 - '@esbuild/netbsd-x64': 0.25.4 - '@esbuild/openbsd-arm64': 0.25.4 - '@esbuild/openbsd-x64': 0.25.4 - '@esbuild/sunos-x64': 0.25.4 - '@esbuild/win32-arm64': 0.25.4 - '@esbuild/win32-ia32': 0.25.4 - '@esbuild/win32-x64': 0.25.4 - escalade@3.2.0: {} escape-html@1.0.3: {} escape-string-regexp@4.0.0: {} - estree-walker@3.0.3: - dependencies: - '@types/estree': 1.0.7 - etag@1.8.1: {} 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 @@ -5328,10 +4100,6 @@ snapshots: signal-exit: 3.0.7 strip-final-newline: 2.0.0 - expand-template@2.0.3: {} - - expect-type@1.2.1: {} - express@4.21.2: dependencies: accepts: 1.3.8 @@ -5368,17 +4136,6 @@ snapshots: transitivePeerDependencies: - supports-color - exsolve@1.0.7: {} - - fast-check@3.23.2: - dependencies: - pure-rand: 6.1.0 - - 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 @@ -5413,14 +4170,8 @@ snapshots: dependencies: reusify: 1.0.4 - fdir@6.4.4(picomatch@4.0.2): - optionalDependencies: - picomatch: 4.0.2 - fecha@4.2.3: {} - fflate@0.8.2: {} - fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -5464,8 +4215,6 @@ snapshots: flatstr@1.0.12: optional: true - flatted@3.3.3: {} - fn.name@1.1.0: {} for-each@0.3.3: @@ -5509,13 +4258,6 @@ 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: @@ -5551,17 +4293,6 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.2.6 - giget@2.0.0: - dependencies: - citty: 0.1.6 - consola: 3.4.2 - defu: 6.1.4 - node-fetch-native: 1.6.7 - nypm: 0.6.1 - pathe: 2.0.3 - - github-from-package@0.0.0: {} - glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -5610,6 +4341,16 @@ snapshots: merge2: 1.4.1 slash: 3.0.0 + gm@1.16.0: + dependencies: + array-parallel: 0.1.3 + array-series: 0.1.5 + debug: 0.7.0 + stream-to-buffer: 0.0.1 + through: 2.3.8 + transitivePeerDependencies: + - supports-color + gopd@1.2.0: {} graceful-fs@4.2.11: {} @@ -5658,21 +4399,6 @@ snapshots: hpagent@1.2.0: {} - html-to-text@9.0.5: - dependencies: - '@selderee/plugin-htmlparser2': 0.11.0 - deepmerge: 4.3.1 - dom-serializer: 2.0.0 - htmlparser2: 8.0.2 - selderee: 0.11.0 - - htmlparser2@8.0.2: - dependencies: - domelementtype: 2.3.0 - domhandler: 5.0.3 - domutils: 3.2.2 - entities: 4.5.0 - http-errors@2.0.0: dependencies: depd: 2.0.0 @@ -5745,8 +4471,6 @@ snapshots: inherits@2.0.4: {} - ini@1.3.8: {} - ini@2.0.0: {} internal-slot@1.1.0: @@ -5925,12 +4649,8 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 - jiti@2.5.1: {} - js-tokens@4.0.0: {} - jsbarcode@3.11.6: {} - json-2-csv@5.5.8: dependencies: deeks: 3.1.0 @@ -5965,8 +4685,6 @@ snapshots: dependencies: readable-stream: 2.3.8 - leac@0.6.0: {} - lie@3.3.0: dependencies: immediate: 3.0.6 @@ -5975,8 +4693,6 @@ snapshots: lines-and-columns@1.2.4: {} - listenercount@1.0.1: {} - locate-path@5.0.0: dependencies: p-locate: 4.1.0 @@ -5997,10 +4713,6 @@ 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: {} @@ -6029,8 +4741,6 @@ snapshots: safe-stable-stringify: 2.5.0 triple-beam: 1.4.1 - loupe@3.1.3: {} - lru-cache@10.4.3: {} lru-cache@4.1.5: @@ -6046,10 +4756,6 @@ snapshots: luxon@3.5.0: {} - magic-string@0.30.17: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.0 - make-dir@3.1.0: dependencies: semver: 6.3.1 @@ -6110,8 +4816,6 @@ snapshots: mimic-fn@2.1.0: {} - mimic-response@3.1.0: {} - min-indent@1.0.1: {} minimalistic-assert@1.0.1: {} @@ -6149,12 +4853,6 @@ snapshots: minipass@7.1.2: {} - mkdirp-classic@0.5.3: {} - - mkdirp@0.5.6: - dependencies: - minimist: 1.2.8 - mnemonist@0.39.8: dependencies: obliterator: 2.0.4 @@ -6175,28 +4873,12 @@ snapshots: transitivePeerDependencies: - supports-color - mrmime@2.0.1: {} - ms@2.0.0: {} ms@2.1.2: {} 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 - - nanoid@3.3.11: {} - - napi-build-utils@2.0.0: {} - negotiator@0.6.3: {} neo-async@2.6.2: {} @@ -6206,14 +4888,6 @@ snapshots: next-line@1.1.0: optional: true - node-abi@3.75.0: - dependencies: - semver: 7.6.3 - - node-addon-api@7.1.1: {} - - node-fetch-native@1.6.7: {} - node-fetch@2.6.12(encoding@0.1.13): dependencies: whatwg-url: 5.0.0 @@ -6267,14 +4941,6 @@ snapshots: dependencies: path-key: 3.1.1 - nypm@0.6.1: - dependencies: - citty: 0.1.6 - consola: 3.4.2 - pathe: 2.0.3 - pkg-types: 2.3.0 - tinyexec: 1.0.1 - object-assign@4.1.1: {} object-filter-sequence@1.0.0: @@ -6305,8 +4971,6 @@ snapshots: obliterator@2.0.4: {} - ohash@2.0.11: {} - on-finished@2.3.0: dependencies: ee-first: 1.1.1 @@ -6386,11 +5050,6 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 - parseley@0.12.1: - dependencies: - leac: 0.6.0 - peberminta: 0.9.0 - parseurl@1.3.3: {} path-exists@4.0.0: {} @@ -6410,20 +5069,10 @@ snapshots: path-type@4.0.0: {} - pathe@2.0.3: {} - - pathval@2.0.0: {} - - peberminta@0.9.0: {} - - perfect-debounce@1.0.0: {} - picocolors@1.1.1: {} picomatch@2.3.1: {} - picomatch@4.0.2: {} - pino-std-serializers@3.2.0: optional: true @@ -6442,42 +5091,13 @@ snapshots: dependencies: find-up: 4.1.0 - pkg-types@2.3.0: - dependencies: - confbox: 0.2.2 - exsolve: 1.0.7 - pathe: 2.0.3 - - pnpm@10.28.0: {} - possible-typed-array-names@1.0.0: {} - postcss@8.5.3: - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - prebuild-install@7.1.3: - dependencies: - detect-libc: 2.0.4 - expand-template: 2.0.3 - github-from-package: 0.0.0 - minimist: 1.2.8 - mkdirp-classic: 0.5.3 - napi-build-utils: 2.0.0 - node-abi: 3.75.0 - pump: 3.0.2 - rc: 1.2.8 - simple-get: 4.0.1 - tar-fs: 2.1.2 - tunnel-agent: 0.6.0 - prettier@3.4.2: {} - prisma-extension-kysely@3.0.0(@prisma/client@6.16.2(prisma@6.16.2(typescript@5.7.2))(typescript@5.7.2)): + prisma-extension-kysely@3.0.0(@prisma/client@6.3.0(prisma@6.3.0(typescript@5.7.2))(typescript@5.7.2)): dependencies: - '@prisma/client': 6.16.2(prisma@6.16.2(typescript@5.7.2))(typescript@5.7.2) + '@prisma/client': 6.3.0(prisma@6.3.0(typescript@5.7.2))(typescript@5.7.2) prisma-kysely@1.8.0(encoding@0.1.13): dependencies: @@ -6490,14 +5110,12 @@ snapshots: - encoding - supports-color - prisma@6.16.2(typescript@5.7.2): + prisma@6.3.0(typescript@5.7.2): dependencies: - '@prisma/config': 6.16.2 - '@prisma/engines': 6.16.2 + '@prisma/engines': 6.3.0 optionalDependencies: + fsevents: 2.3.3 typescript: 5.7.2 - transitivePeerDependencies: - - magicast process-nextick-args@2.0.1: {} @@ -6535,16 +5153,9 @@ snapshots: pstree.remy@1.1.8: {} - pump@3.0.2: - dependencies: - end-of-stream: 1.4.4 - once: 1.4.0 - punycode@2.3.1: optional: true - pure-rand@6.1.0: {} - qs@6.13.0: dependencies: side-channel: 1.1.0 @@ -6570,18 +5181,6 @@ snapshots: iconv-lite: 0.4.24 unpipe: 1.0.0 - rc9@2.1.2: - dependencies: - defu: 6.1.4 - destr: 2.0.5 - - rc@1.2.8: - dependencies: - deep-extend: 0.6.0 - ini: 1.3.8 - minimist: 1.2.8 - strip-json-comments: 2.0.1 - read-pkg-up@7.0.1: dependencies: find-up: 4.1.0 @@ -6619,8 +5218,6 @@ snapshots: dependencies: picomatch: 2.3.1 - readdirp@4.1.2: {} - reflect-metadata@0.2.2: {} reflect.getprototypeof@1.0.8: @@ -6676,40 +5273,10 @@ snapshots: reusify@1.0.4: {} - rimraf@2.7.1: - dependencies: - glob: 7.2.3 - rimraf@3.0.2: dependencies: glob: 7.2.3 - rollup@4.41.0: - dependencies: - '@types/estree': 1.0.7 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.41.0 - '@rollup/rollup-android-arm64': 4.41.0 - '@rollup/rollup-darwin-arm64': 4.41.0 - '@rollup/rollup-darwin-x64': 4.41.0 - '@rollup/rollup-freebsd-arm64': 4.41.0 - '@rollup/rollup-freebsd-x64': 4.41.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.41.0 - '@rollup/rollup-linux-arm-musleabihf': 4.41.0 - '@rollup/rollup-linux-arm64-gnu': 4.41.0 - '@rollup/rollup-linux-arm64-musl': 4.41.0 - '@rollup/rollup-linux-loongarch64-gnu': 4.41.0 - '@rollup/rollup-linux-powerpc64le-gnu': 4.41.0 - '@rollup/rollup-linux-riscv64-gnu': 4.41.0 - '@rollup/rollup-linux-riscv64-musl': 4.41.0 - '@rollup/rollup-linux-s390x-gnu': 4.41.0 - '@rollup/rollup-linux-x64-gnu': 4.41.0 - '@rollup/rollup-linux-x64-musl': 4.41.0 - '@rollup/rollup-win32-arm64-msvc': 4.41.0 - '@rollup/rollup-win32-ia32-msvc': 4.41.0 - '@rollup/rollup-win32-x64-msvc': 4.41.0 - fsevents: 2.3.3 - run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 @@ -6740,16 +5307,8 @@ snapshots: sax@1.4.1: {} - saxes@5.0.1: - dependencies: - xmlchars: 2.2.0 - secure-json-parse@2.7.0: {} - selderee@0.11.0: - dependencies: - parseley: 0.12.1 - semver@5.7.2: {} semver@6.3.1: {} @@ -6840,20 +5399,10 @@ snapshots: side-channel-map: 1.0.1 side-channel-weakmap: 1.0.2 - siginfo@2.0.0: {} - signal-exit@3.0.7: {} signal-exit@4.1.0: {} - simple-concat@1.0.1: {} - - simple-get@4.0.1: - dependencies: - decompress-response: 6.0.0 - once: 1.4.0 - simple-concat: 1.0.1 - simple-swizzle@0.2.2: dependencies: is-arrayish: 0.3.2 @@ -6862,12 +5411,6 @@ snapshots: dependencies: semver: 7.6.3 - sirv@3.0.1: - dependencies: - '@polka/url': 1.0.0-next.29 - mrmime: 2.0.1 - totalist: 3.0.1 - sisteransi@1.0.5: {} slash@3.0.0: {} @@ -6884,8 +5427,6 @@ snapshots: flatstr: 1.0.12 optional: true - source-map-js@1.2.1: {} - source-map@0.6.1: {} source-map@0.8.0-beta.0: @@ -6914,15 +5455,11 @@ snapshots: stack-trace@0.0.10: {} - stackback@0.0.2: {} - stackframe@1.3.4: optional: true statuses@2.0.1: {} - std-env@3.9.0: {} - stop-iteration-iterator@1.1.0: dependencies: es-errors: 1.3.0 @@ -6939,7 +5476,7 @@ snapshots: dependencies: stream-chain: 2.2.5 - streamsearch@1.1.0: {} + stream-to-buffer@0.0.1: {} strict-uri-encode@2.0.0: {} @@ -7000,8 +5537,6 @@ snapshots: dependencies: min-indent: 1.0.1 - strip-json-comments@2.0.1: {} - strnum@1.0.5: {} supports-color@5.5.0: @@ -7024,13 +5559,6 @@ snapshots: array-back: 6.2.2 wordwrapjs: 5.1.0 - tar-fs@2.1.2: - dependencies: - chownr: 1.1.4 - mkdirp-classic: 0.5.3 - pump: 3.0.2 - tar-stream: 2.2.0 - tar-stream@2.2.0: dependencies: bl: 4.1.0 @@ -7062,22 +5590,7 @@ snapshots: dependencies: readable-stream: 3.6.2 - tinybench@2.9.0: {} - - tinyexec@0.3.2: {} - - tinyexec@1.0.1: {} - - tinyglobby@0.2.13: - dependencies: - fdir: 6.4.4(picomatch@4.0.2) - picomatch: 4.0.2 - - tinypool@1.0.2: {} - - tinyrainbow@2.0.0: {} - - tinyspy@3.0.2: {} + through@2.3.8: {} tmp@0.2.1: dependencies: @@ -7096,8 +5609,6 @@ snapshots: toidentifier@1.0.1: {} - totalist@3.0.1: {} - touch@3.1.1: {} tr46@0.0.3: {} @@ -7107,8 +5618,6 @@ snapshots: punycode: 2.3.1 optional: true - traverse@0.3.9: {} - triple-beam@1.4.1: {} ts-deepmerge@7.0.2: {} @@ -7142,10 +5651,6 @@ snapshots: transitivePeerDependencies: - supports-color - tunnel-agent@0.6.0: - dependencies: - safe-buffer: 5.2.1 - type-fest@0.16.0: {} type-fest@0.21.3: {} @@ -7192,8 +5697,6 @@ 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: {} @@ -7233,19 +5736,6 @@ 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: @@ -7258,8 +5748,6 @@ snapshots: utils-merge@1.0.1: {} - uuid@8.3.2: {} - uuid@9.0.0: {} v8-compile-cache-lib@3.0.1: {} @@ -7273,81 +5761,6 @@ snapshots: vary@1.1.2: {} - vite-node@3.1.4(@types/node@20.17.10)(jiti@2.5.1)(yaml@2.6.1): - dependencies: - cac: 6.7.14 - debug: 4.4.0(supports-color@5.5.0) - es-module-lexer: 1.7.0 - pathe: 2.0.3 - vite: 6.3.5(@types/node@20.17.10)(jiti@2.5.1)(yaml@2.6.1) - transitivePeerDependencies: - - '@types/node' - - jiti - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - - vite@6.3.5(@types/node@20.17.10)(jiti@2.5.1)(yaml@2.6.1): - dependencies: - esbuild: 0.25.4 - fdir: 6.4.4(picomatch@4.0.2) - picomatch: 4.0.2 - postcss: 8.5.3 - rollup: 4.41.0 - tinyglobby: 0.2.13 - optionalDependencies: - '@types/node': 20.17.10 - fsevents: 2.3.3 - jiti: 2.5.1 - yaml: 2.6.1 - - vitest@3.1.4(@types/node@20.17.10)(@vitest/ui@3.1.4)(jiti@2.5.1)(yaml@2.6.1): - dependencies: - '@vitest/expect': 3.1.4 - '@vitest/mocker': 3.1.4(vite@6.3.5(@types/node@20.17.10)(jiti@2.5.1)(yaml@2.6.1)) - '@vitest/pretty-format': 3.1.4 - '@vitest/runner': 3.1.4 - '@vitest/snapshot': 3.1.4 - '@vitest/spy': 3.1.4 - '@vitest/utils': 3.1.4 - chai: 5.2.0 - debug: 4.4.0(supports-color@5.5.0) - expect-type: 1.2.1 - magic-string: 0.30.17 - pathe: 2.0.3 - std-env: 3.9.0 - tinybench: 2.9.0 - tinyexec: 0.3.2 - tinyglobby: 0.2.13 - tinypool: 1.0.2 - tinyrainbow: 2.0.0 - vite: 6.3.5(@types/node@20.17.10)(jiti@2.5.1)(yaml@2.6.1) - vite-node: 3.1.4(@types/node@20.17.10)(jiti@2.5.1)(yaml@2.6.1) - why-is-node-running: 2.3.0 - optionalDependencies: - '@types/node': 20.17.10 - '@vitest/ui': 3.1.4(vitest@3.1.4) - transitivePeerDependencies: - - jiti - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - web-encoding@1.1.5: dependencies: util: 0.12.5 @@ -7414,11 +5827,6 @@ snapshots: dependencies: isexe: 2.0.0 - why-is-node-running@2.3.0: - dependencies: - siginfo: 2.0.0 - stackback: 0.0.2 - winston-elasticsearch@0.19.0: dependencies: '@elastic/elasticsearch': 8.17.0 @@ -7480,10 +5888,6 @@ snapshots: xmlbuilder@11.0.1: {} - xmlchars@2.2.0: {} - - xtend@4.0.2: {} - y18n@5.0.8: {} yallist@2.1.2: diff --git a/prisma/migrations/20250410102415_add/migration.sql b/prisma/migrations/20250410102415_add/migration.sql deleted file mode 100644 index eaf0561..0000000 --- a/prisma/migrations/20250410102415_add/migration.sql +++ /dev/null @@ -1,3 +0,0 @@ --- AlterTable -ALTER TABLE "User" ADD COLUMN "contactName" TEXT, -ADD COLUMN "contactTel" TEXT; diff --git a/prisma/migrations/20250410104307_change/migration.sql b/prisma/migrations/20250410104307_change/migration.sql deleted file mode 100644 index 3239108..0000000 --- a/prisma/migrations/20250410104307_change/migration.sql +++ /dev/null @@ -1,3 +0,0 @@ --- AlterTable -ALTER TABLE "User" ALTER COLUMN "firstName" DROP NOT NULL, -ALTER COLUMN "lastName" DROP NOT NULL; diff --git a/prisma/migrations/20250418095201_add/migration.sql b/prisma/migrations/20250418095201_add/migration.sql deleted file mode 100644 index be3e4d0..0000000 --- a/prisma/migrations/20250418095201_add/migration.sql +++ /dev/null @@ -1,2 +0,0 @@ --- AlterTable -ALTER TABLE "TaskOrder" ADD COLUMN "codeProductReceived" TEXT; diff --git a/prisma/migrations/20250418103300_add/migration.sql b/prisma/migrations/20250418103300_add/migration.sql deleted file mode 100644 index 2e63034..0000000 --- a/prisma/migrations/20250418103300_add/migration.sql +++ /dev/null @@ -1,18 +0,0 @@ --- 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; diff --git a/prisma/migrations/20250422024534_remove_lastname_requirement_employee/migration.sql b/prisma/migrations/20250422024534_remove_lastname_requirement_employee/migration.sql deleted file mode 100644 index bd03e24..0000000 --- a/prisma/migrations/20250422024534_remove_lastname_requirement_employee/migration.sql +++ /dev/null @@ -1,2 +0,0 @@ --- AlterTable -ALTER TABLE "Employee" ALTER COLUMN "lastNameEN" DROP NOT NULL; diff --git a/prisma/migrations/20250424042834_add/migration.sql b/prisma/migrations/20250424042834_add/migration.sql deleted file mode 100644 index 13999bc..0000000 --- a/prisma/migrations/20250424042834_add/migration.sql +++ /dev/null @@ -1,11 +0,0 @@ --- 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; diff --git a/prisma/migrations/20250424094947_change_import_nationality_to_relation/migration.sql b/prisma/migrations/20250424094947_change_import_nationality_to_relation/migration.sql deleted file mode 100644 index c961d96..0000000 --- a/prisma/migrations/20250424094947_change_import_nationality_to_relation/migration.sql +++ /dev/null @@ -1,20 +0,0 @@ -/* - 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; diff --git a/prisma/migrations/20250425040315_add/migration.sql b/prisma/migrations/20250425040315_add/migration.sql deleted file mode 100644 index 9393a9a..0000000 --- a/prisma/migrations/20250425040315_add/migration.sql +++ /dev/null @@ -1,2 +0,0 @@ --- AlterTable -ALTER TABLE "Employee" ADD COLUMN "otherNationality" TEXT; diff --git a/prisma/migrations/20250425041426_add/migration.sql b/prisma/migrations/20250425041426_add/migration.sql deleted file mode 100644 index a004873..0000000 --- a/prisma/migrations/20250425041426_add/migration.sql +++ /dev/null @@ -1,2 +0,0 @@ --- AlterTable -ALTER TABLE "EmployeePassport" ADD COLUMN "otherNationality" TEXT; diff --git a/prisma/migrations/20250513084929_add/migration.sql b/prisma/migrations/20250513084929_add/migration.sql deleted file mode 100644 index f982e5b..0000000 --- a/prisma/migrations/20250513084929_add/migration.sql +++ /dev/null @@ -1,3 +0,0 @@ --- AlterTable -ALTER TABLE "QuotationWorker" ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, -ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP; diff --git a/prisma/migrations/20250630091430_update_constraint/migration.sql b/prisma/migrations/20250630091430_update_constraint/migration.sql deleted file mode 100644 index 5bd662c..0000000 --- a/prisma/migrations/20250630091430_update_constraint/migration.sql +++ /dev/null @@ -1,5 +0,0 @@ --- DropForeignKey -ALTER TABLE "UserImportNationality" DROP CONSTRAINT "UserImportNationality_userId_fkey"; - --- AddForeignKey -ALTER TABLE "UserImportNationality" ADD CONSTRAINT "UserImportNationality_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/migrations/20250704070342_add_relation_seller_in_quotation/migration.sql b/prisma/migrations/20250704070342_add_relation_seller_in_quotation/migration.sql deleted file mode 100644 index ef63931..0000000 --- a/prisma/migrations/20250704070342_add_relation_seller_in_quotation/migration.sql +++ /dev/null @@ -1,5 +0,0 @@ --- AlterTable -ALTER TABLE "Quotation" ADD COLUMN "sellerId" TEXT; - --- AddForeignKey -ALTER TABLE "Quotation" ADD CONSTRAINT "Quotation_sellerId_fkey" FOREIGN KEY ("sellerId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/migrations/20250709082027_add_business_type_add_delect_customer_name/migration.sql b/prisma/migrations/20250709082027_add_business_type_add_delect_customer_name/migration.sql deleted file mode 100644 index 50f8cd1..0000000 --- a/prisma/migrations/20250709082027_add_business_type_add_delect_customer_name/migration.sql +++ /dev/null @@ -1,36 +0,0 @@ -/* - Warnings: - - - You are about to drop the column `businessType` on the `CustomerBranch` table. All the data in the column will be lost. - - You are about to drop the column `customerName` on the `CustomerBranch` table. All the data in the column will be lost. - -*/ --- AlterTable -ALTER TABLE "CustomerBranch" DROP COLUMN "businessType", -DROP COLUMN "customerName", -ADD COLUMN "businessTypeId" TEXT; - --- AlterTable -ALTER TABLE "EmployeeVisa" ADD COLUMN "reportDate" DATE; - --- CreateTable -CREATE TABLE "BusinessType" ( - "id" TEXT NOT NULL, - "name" TEXT NOT NULL, - "nameEN" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "createdByUserId" TEXT, - "updatedAt" TIMESTAMP(3) NOT NULL, - "updatedByUserId" TEXT, - - CONSTRAINT "BusinessType_pkey" PRIMARY KEY ("id") -); - --- AddForeignKey -ALTER TABLE "CustomerBranch" ADD CONSTRAINT "CustomerBranch_businessTypeId_fkey" FOREIGN KEY ("businessTypeId") REFERENCES "BusinessType"("id") ON DELETE SET NULL ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "BusinessType" ADD CONSTRAINT "BusinessType_createdByUserId_fkey" FOREIGN KEY ("createdByUserId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "BusinessType" ADD CONSTRAINT "BusinessType_updatedByUserId_fkey" FOREIGN KEY ("updatedByUserId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/prisma/migrations/20250716023822_allow_foreign_address/migration.sql b/prisma/migrations/20250716023822_allow_foreign_address/migration.sql deleted file mode 100644 index a255d89..0000000 --- a/prisma/migrations/20250716023822_allow_foreign_address/migration.sql +++ /dev/null @@ -1,6 +0,0 @@ --- AlterTable -ALTER TABLE "User" ADD COLUMN "addressForeign" BOOLEAN NOT NULL DEFAULT false, -ADD COLUMN "districtText" TEXT, -ADD COLUMN "provinceText" TEXT, -ADD COLUMN "subDistrictText" TEXT, -ADD COLUMN "zipCodeText" TEXT; diff --git a/prisma/migrations/20250716024423_add_address_text_en/migration.sql b/prisma/migrations/20250716024423_add_address_text_en/migration.sql deleted file mode 100644 index e55a4d0..0000000 --- a/prisma/migrations/20250716024423_add_address_text_en/migration.sql +++ /dev/null @@ -1,4 +0,0 @@ --- AlterTable -ALTER TABLE "User" ADD COLUMN "districtTextEN" TEXT, -ADD COLUMN "provinceTextEN" TEXT, -ADD COLUMN "subDistrictTextEN" TEXT; diff --git a/prisma/migrations/20250814060937_add_updated_at_to_work_step/migration.sql b/prisma/migrations/20250814060937_add_updated_at_to_work_step/migration.sql deleted file mode 100644 index d1bf6c5..0000000 --- a/prisma/migrations/20250814060937_add_updated_at_to_work_step/migration.sql +++ /dev/null @@ -1,2 +0,0 @@ --- AlterTable -ALTER TABLE "RequestWorkStepStatus" ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP; diff --git a/prisma/migrations/20250911021745_add_more_payment_metadata/migration.sql b/prisma/migrations/20250911021745_add_more_payment_metadata/migration.sql deleted file mode 100644 index 27036c0..0000000 --- a/prisma/migrations/20250911021745_add_more_payment_metadata/migration.sql +++ /dev/null @@ -1,4 +0,0 @@ --- AlterTable -ALTER TABLE "Payment" ADD COLUMN "account" TEXT, -ADD COLUMN "channel" TEXT, -ADD COLUMN "reference" TEXT; diff --git a/prisma/migrations/20250911092303_add_flow_account_product_id_sell_price_and_flow_account_product_id_agent_price_field_in_product_table/migration.sql b/prisma/migrations/20250911092303_add_flow_account_product_id_sell_price_and_flow_account_product_id_agent_price_field_in_product_table/migration.sql deleted file mode 100644 index 0ef2494..0000000 --- a/prisma/migrations/20250911092303_add_flow_account_product_id_sell_price_and_flow_account_product_id_agent_price_field_in_product_table/migration.sql +++ /dev/null @@ -1,3 +0,0 @@ --- AlterTable -ALTER TABLE "public"."Product" ADD COLUMN "flowAccountProductIdAgentPrice" TEXT, -ADD COLUMN "flowAccountProductIdSellPrice" TEXT; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 2f25bb2..cb38c88 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -366,24 +366,16 @@ enum UserType { AGENCY } -model UserImportNationality { - id String @id @default(cuid()) - name String - - user User @relation(fields: [userId], references: [id], onDelete: Cascade) - 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 @@ -398,24 +390,14 @@ model User { street String? streetEN String? - addressForeign Boolean @default(false) + province Province? @relation(fields: [provinceId], references: [id], onDelete: SetNull) + provinceId String? - provinceText String? - provinceTextEN String? - province Province? @relation(fields: [provinceId], references: [id], onDelete: SetNull) - provinceId String? + district District? @relation(fields: [districtId], references: [id], onDelete: SetNull) + districtId String? - districtText String? - districtTextEN String? - district District? @relation(fields: [districtId], references: [id], onDelete: SetNull) - districtId String? - - subDistrictText String? - subDistrictTextEN String? - subDistrict SubDistrict? @relation(fields: [subDistrictId], references: [id], onDelete: SetNull) - subDistrictId String? - - zipCodeText String? + subDistrict SubDistrict? @relation(fields: [subDistrictId], references: [id], onDelete: SetNull) + subDistrictId String? email String telephoneNo String @@ -442,7 +424,7 @@ model User { licenseExpireDate DateTime? @db.Date sourceNationality String? - importNationality UserImportNationality[] + importNationality String? trainingPlace String? responsibleArea UserResponsibleArea[] @@ -502,17 +484,12 @@ model User { flowCreated WorkflowTemplate[] @relation("FlowCreatedByUser") flowUpdated WorkflowTemplate[] @relation("FlowUpdatedByUser") invoiceCreated Invoice[] - paymentCreated Payment[] @relation("PaymentCreatedByUser") - paymentUpdated Payment[] @relation("PaymentUpdatedByUser") + paymentCreated Payment[] 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") - businessTypeCreated BusinessType[] @relation("BusinessTypeCreatedByUser") - businessTypeUpdated BusinessType[] @relation("BusinessTypeUpdatedByUser") requestWorkStepStatus RequestWorkStepStatus[] userTask UserTask[] @@ -520,10 +497,6 @@ model User { remark String? agencyStatus String? - - contactName String? - contactTel String? - quotation Quotation[] } model UserResponsibleArea { @@ -562,9 +535,10 @@ model Customer { } model CustomerBranch { - id String @id @default(cuid()) - customer Customer @relation(fields: [customerId], references: [id], onDelete: Cascade) - customerId String + id String @id @default(cuid()) + customer Customer @relation(fields: [customerId], references: [id], onDelete: Cascade) + customerId String + customerName String? code String codeCustomer String @@ -626,8 +600,7 @@ model CustomerBranch { agentUser User? @relation(fields: [agentUserId], references: [id], onDelete: SetNull) // NOTE: Business - businessTypeId String? - businessType BusinessType? @relation(fields: [businessTypeId], references: [id], onDelete: SetNull) + businessType String jobPosition String jobDescription String payDate String @@ -786,21 +759,6 @@ model CustomerBranchVatRegis { customerBranch CustomerBranch @relation(fields: [customerBranchId], references: [id], onDelete: Cascade) } -model BusinessType { - id String @id @default(cuid()) - name String - nameEN String - - createdAt DateTime @default(now()) - createdBy User? @relation(name: "BusinessTypeCreatedByUser", fields: [createdByUserId], references: [id], onDelete: SetNull) - createdByUserId String? - updatedAt DateTime @updatedAt - updatedBy User? @relation(name: "BusinessTypeUpdatedByUser", fields: [updatedByUserId], references: [id], onDelete: SetNull) - updatedByUserId String? - - customerBranch CustomerBranch[] -} - model Employee { id String @id @default(cuid()) @@ -813,12 +771,11 @@ model Employee { middleName String? middleNameEN String? lastName String? - lastNameEN String? + lastNameEN String - dateOfBirth DateTime? @db.Date - gender String - nationality String - otherNationality String? + dateOfBirth DateTime? @db.Date + gender String + nationality String address String? addressEN String? @@ -893,19 +850,18 @@ model EmployeePassport { issuePlace String previousPassportRef 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? + workerStatus String? + nationality 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 @@ -922,9 +878,8 @@ model EmployeeVisa { entryCount Int issueCountry String issuePlace String - issueDate DateTime @db.Date - expireDate DateTime @db.Date - reportDate DateTime? @db.Date + issueDate DateTime @db.Date + expireDate DateTime @db.Date mrz String? remark String? @@ -1057,13 +1012,6 @@ 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[] } @@ -1128,15 +1076,6 @@ 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()) @@ -1147,7 +1086,6 @@ model WorkflowTemplateStep { value WorkflowTemplateStepValue[] // NOTE: For enum or options type responsiblePerson WorkflowTemplateStepUser[] responsibleInstitution WorkflowTemplateStepInstitution[] - responsibleGroup WorkflowTemplateStepGroup[] messengerByArea Boolean @default(false) attributes Json? @@ -1243,9 +1181,6 @@ model Product { productGroup ProductGroup @relation(fields: [productGroupId], references: [id], onDelete: Cascade) productGroupId String - flowAccountProductIdSellPrice String? - flowAccountProductIdAgentPrice String? - workProduct WorkProduct[] quotationProductServiceList QuotationProductServiceList[] taskProduct TaskProduct[] @@ -1418,9 +1353,6 @@ model Quotation { invoice Invoice[] creditNote CreditNote[] - - seller User? @relation(fields: [sellerId], references: [id], onDelete: Cascade) - sellerId String? } model QuotationPaySplit { @@ -1445,9 +1377,6 @@ model QuotationWorker { employeeId String quotation Quotation @relation(fields: [quotationId], references: [id], onDelete: Cascade) quotationId String - - createdAt DateTime @default(now()) - updatedAt DateTime @default(now()) @updatedAt } model QuotationProductServiceList { @@ -1527,19 +1456,12 @@ model Payment { paymentStatus PaymentStatus - amount Float - date DateTime? - channel String? - account String? - reference String? + amount Float + date DateTime? createdAt DateTime @default(now()) - createdBy User? @relation(name: "PaymentCreatedByUser", fields: [createdByUserId], references: [id], onDelete: SetNull) + createdBy User? @relation(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 { @@ -1618,7 +1540,6 @@ model RequestWork { model RequestWorkStepStatus { step Int workStatus RequestWorkStatus @default(Pending) - updatedAt DateTime @default(now()) @updatedAt requestWork RequestWork @relation(fields: [requestWorkId], references: [id], onDelete: Cascade) requestWorkId String @@ -1693,8 +1614,7 @@ model TaskProduct { model TaskOrder { id String @id @default(cuid()) - code String - codeProductReceived String? + code String taskName String taskOrderStatus TaskOrderStatus @default(Pending) diff --git a/src/controllers/00-doc-template-controller.ts b/src/controllers/00-doc-template-controller.ts index 09dab18..1b9f70d 100644 --- a/src/controllers/00-doc-template-controller.ts +++ b/src/controllers/00-doc-template-controller.ts @@ -1,5 +1,4 @@ -import { createCanvas } from "canvas"; -import JsBarcode from "jsbarcode"; +import barcode from "barcode"; import createReport from "docx-templates"; import ThaiBahtText from "thai-baht-text"; import { District, Province, SubDistrict } from "@prisma/client"; @@ -34,14 +33,8 @@ const quotationData = (id: string) => }, }, customerBranch: { - omit: { - otpCode: true, - otpExpires: true, - userId: true, - }, include: { customer: true, - businessType: true, province: true, district: true, subDistrict: true, @@ -118,12 +111,12 @@ export class DocTemplateController extends Controller { ) { const ret = await edmList( "file", - templateGroup ? [...DOCUMENT_PATH, templateGroup] : DOCUMENT_PATH, + templateGroup ? [templateGroup, ...DOCUMENT_PATH] : DOCUMENT_PATH, ); if (ret) return ret.map((v) => v.fileName); } return await listFile( - (templateGroup ? [...DOCUMENT_PATH, templateGroup] : DOCUMENT_PATH).join("/") + "/", + (templateGroup ? [templateGroup, ...DOCUMENT_PATH] : DOCUMENT_PATH).join("/") + "/", ); } @@ -260,23 +253,13 @@ export class DocTemplateController extends Controller { thaiBahtText: (input: string | number) => { ThaiBahtText(typeof input === "string" ? input.replaceAll(",", "") : input); }, - barcode: async (data: string, width?: number, height?: number) => - new Promise<{ - width: number; - height: number; - data: string; - extension: string; - }>((resolve) => { - const canvas = createCanvas(400, 100); - JsBarcode(canvas, data); - - resolve({ - width: width ?? 8, - height: height ?? 3, - data: canvas.toDataURL("image/jpeg").slice("data:image/jpeg;base64".length), - extension: ".jpeg", - }); - }), + barcode: async (data: string) => + new Promise((resolve, reject) => + barcode("code39", { data, width: 400, height: 100 }).getBase64((err, data) => { + if (!err) return resolve(data); + return reject(err); + }), + ), }, }).then(Buffer.from); @@ -293,7 +276,6 @@ function replaceEmptyField(data: T): T { } type FullAddress = { - addressForeign?: boolean; address: string; addressEN: string; moo?: string; @@ -302,14 +284,8 @@ type FullAddress = { soiEN?: string; street?: string; streetEN?: string; - provinceText?: string | null; - provinceTextEN?: string | null; province?: Province | null; - districtText?: string | null; - districtTextEN?: string | null; district?: District | null; - subDistrictText?: string | null; - subDistrictTextEN?: string | null; subDistrict?: SubDistrict | null; en?: boolean; }; @@ -343,22 +319,13 @@ function addressFull(addr: FullAddress, lang: "th" | "en" = "en") { if (addr.soi) fragments.push(`ซอย ${addr.soi},`); if (addr.street) fragments.push(`ถนน${addr.street},`); - if (!addr.addressForeign && addr.subDistrict) { - fragments.push(`${addr.province?.id === "10" ? "แขวง" : "ตำบล"}${addr.subDistrict.name}`); + if (addr.subDistrict) { + fragments.push(`${addr.province?.id === "10" ? "แขวง" : "ตำบล"}${addr.subDistrict.name},`); } - if (addr.addressForeign && addr.subDistrictText) { - fragments.push(`ตำบล${addr.subDistrictText}`); + if (addr.district) { + fragments.push(`${addr.province?.id === "10" ? "เขต" : "อำเภอ"}${addr.district.name},`); } - - if (!addr.addressForeign && addr.district) { - fragments.push(`${addr.province?.id === "10" ? "เขต" : "อำเภอ"}${addr.district.name}`); - } - if (addr.addressForeign && addr.districtText) { - fragments.push(`อำเภอ${addr.districtText}`); - } - - if (!addr.addressForeign && addr.province) fragments.push(`จังหวัด${addr.province.name}`); - if (addr.addressForeign && addr.provinceText) fragments.push(`จังหวัด${addr.provinceText}`); + if (addr.province) fragments.push(`จังหวัด${addr.province.name},`); break; default: @@ -367,31 +334,14 @@ function addressFull(addr: FullAddress, lang: "th" | "en" = "en") { if (addr.soiEN) fragments.push(`Soi ${addr.soiEN},`); if (addr.streetEN) fragments.push(`${addr.streetEN} Rd.`); - if (!addr.addressForeign && addr.subDistrict) { + if (addr.subDistrict) { fragments.push(`${addr.subDistrict.nameEN} sub-district,`); } - if (addr.addressForeign && addr.subDistrictTextEN) { - fragments.push(`${addr.subDistrictTextEN} sub-district,`); - } - - if (!addr.addressForeign && addr.district) { - fragments.push(`${addr.district.nameEN} district,`); - } - if (addr.addressForeign && addr.districtTextEN) { - fragments.push(`${addr.districtTextEN} district,`); - } - - if (!addr.addressForeign && addr.province) { - fragments.push(`${addr.province.nameEN},`); - } - if (addr.addressForeign && addr.provinceTextEN) { - fragments.push(`${addr.provinceTextEN} district,`); - } + if (addr.district) fragments.push(`${addr.district.nameEN} district,`); + if (addr.province) fragments.push(`${addr.province.nameEN},`); break; } - if (addr.subDistrict) fragments.push(addr.subDistrict.zipCode); - return fragments.join(" "); } @@ -404,9 +354,6 @@ function gender(text: string, lang: "th" | "en" = "en") { } } -/** - * @deprecated - */ function businessType(text: string, lang: "th" | "en" = "en") { switch (lang) { case "th": diff --git a/src/controllers/00-employment-office-controller.ts b/src/controllers/00-employment-office-controller.ts index 9c6995b..95adc5a 100644 --- a/src/controllers/00-employment-office-controller.ts +++ b/src/controllers/00-employment-office-controller.ts @@ -12,39 +12,6 @@ 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, diff --git a/src/controllers/00-keycloak-controller.ts b/src/controllers/00-keycloak-controller.ts index 1d5d9b9..87ca8d0 100644 --- a/src/controllers/00-keycloak-controller.ts +++ b/src/controllers/00-keycloak-controller.ts @@ -1,5 +1,5 @@ -import { Body, Controller, Delete, Get, Path, Post, Query, Route, Security, Tags } from "tsoa"; -import { addUserRoles, getGroup, listRole, removeUserRoles } from "../services/keycloak"; +import { Body, Controller, Delete, Get, Path, Post, Route, Security, Tags } from "tsoa"; +import { addUserRoles, listRole, removeUserRoles } from "../services/keycloak"; @Route("api/v1/keycloak") @Tags("Single-Sign On") @@ -44,13 +44,4 @@ 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; - } } diff --git a/src/controllers/00-stats-controller.ts b/src/controllers/00-stats-controller.ts index 47e803e..b4aef31 100644 --- a/src/controllers/00-stats-controller.ts +++ b/src/controllers/00-stats-controller.ts @@ -618,22 +618,9 @@ export class StatsController extends Controller { startDate = dayjs(startDate).startOf("month").add(1, "month").toDate(); } - const invoices = await tx.invoice.findMany({ - select: { id: true }, - where: { - quotation: { - quotationStatus: { notIn: [QuotationStatus.Canceled] }, - registeredBranch: { OR: permissionCondCompany(req.user) }, - }, - }, - }); - - if (invoices.length === 0) return []; - return await Promise.all( months.map(async (v) => { const date = dayjs(v); - return { month: date.format("MM"), year: date.format("YYYY"), @@ -642,7 +629,11 @@ export class StatsController extends Controller { _sum: { amount: true }, where: { createdAt: { gte: v, lte: date.endOf("month").toDate() }, - invoiceId: { in: invoices.map((v) => v.id) }, + invoice: { + quotation: { + registeredBranch: { OR: permissionCondCompany(req.user) }, + }, + }, }, by: "paymentStatus", }) diff --git a/src/controllers/01-branch-controller.ts b/src/controllers/01-branch-controller.ts index 943413b..f0cc512 100644 --- a/src/controllers/01-branch-controller.ts +++ b/src/controllers/01-branch-controller.ts @@ -39,7 +39,6 @@ import { connectOrNot, queryOrNot, whereAddressQuery, - whereDateQuery, } from "../utils/relation"; import { isUsedError, notFoundError, relationError } from "../utils/error"; @@ -47,20 +46,16 @@ if (!process.env.MINIO_BUCKET) { throw Error("Require MinIO bucket."); } -const MANAGE_ROLES = [ - "system", - "head_of_admin", - "admin", - "executive", - "accountant", - "branch_admin", - "branch_manager", - "branch_accountant", -]; +const MANAGE_ROLES = ["system", "head_of_admin"]; function globalAllow(user: RequestWithUser["user"]) { - const listAllowed = ["system", "head_of_admin", "admin", "executive", "accountant"]; - return user.roles?.some((v) => listAllowed.includes(v)) || false; + return MANAGE_ROLES.some((v) => user.roles?.includes(v)); +} + +function globalAllowView(user: RequestWithUser["user"]) { + return MANAGE_ROLES.concat("head_of_accountant", "head_of_sale").some((v) => + user.roles?.includes(v), + ); } type BranchCreate = { @@ -151,7 +146,7 @@ type BranchUpdate = { }[]; }; -const permissionCond = createPermCondition(globalAllow); +const permissionCond = createPermCondition(globalAllowView); const permissionCheck = createPermCheck(globalAllow); @Route("api/v1/branch") @@ -255,8 +250,6 @@ 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: { @@ -292,7 +285,6 @@ export class BranchController extends Controller { }, }, ]), - ...whereDateQuery(startDate, endDate), } satisfies Prisma.BranchWhereInput; const [result, total] = await prisma.$transaction([ @@ -323,14 +315,13 @@ export class BranchController extends Controller { { telephoneNo: { contains: query, mode: "insensitive" } }, ...whereAddressQuery(query), ], - ...whereDateQuery(startDate, endDate), }, include: { province: true, district: true, subDistrict: true, }, - orderBy: [{ statusOrder: "asc" }, { code: "asc" }], + orderBy: { code: "asc" }, } : false, bank: true, @@ -374,7 +365,7 @@ export class BranchController extends Controller { bank: true, contact: includeContact, }, - orderBy: [{ statusOrder: "asc" }, { code: "asc" }], + orderBy: { code: "asc" }, }, bank: true, contact: includeContact, @@ -387,14 +378,6 @@ export class BranchController extends Controller { return record; } - @Get("{branchId}/bank") - @Security("keycloak") - async getBranchBankById(@Path() branchId: string) { - return await prisma.branchBank.findMany({ - where: { branchId }, - }); - } - @Post() @Security("keycloak", MANAGE_ROLES) async createBranch(@Request() req: RequestWithUser, @Body() body: BranchCreate) { diff --git a/src/controllers/01-branch-user-controller.ts b/src/controllers/01-branch-user-controller.ts index d74742f..99d77a4 100644 --- a/src/controllers/01-branch-user-controller.ts +++ b/src/controllers/01-branch-user-controller.ts @@ -18,21 +18,12 @@ 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, whereDateQuery } from "../utils/relation"; +import { queryOrNot } from "../utils/relation"; -const MANAGE_ROLES = [ - "system", - "head_of_admin", - "admin", - "executive", - "accountant", - "branch_admin", - "branch_manager", - "branch_accountant", -]; +const MANAGE_ROLES = ["system", "head_of_admin", "admin", "branch_manager"]; function globalAllow(user: RequestWithUser["user"]) { - const listAllowed = ["system", "head_of_admin", "admin", "executive", "accountant"]; + const listAllowed = ["system", "head_of_admin", "admin"]; return user.roles?.some((v) => listAllowed.includes(v)) || false; } @@ -106,8 +97,6 @@ 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: { @@ -118,7 +107,6 @@ export class UserBranchController extends Controller { { branch: { name: { contains: query, mode: "insensitive" } } }, { branch: { nameEN: { contains: query, mode: "insensitive" } } }, ]), - ...whereDateQuery(startDate, endDate), } satisfies Prisma.BranchUserWhereInput; const [result, total] = await prisma.$transaction([ @@ -162,8 +150,6 @@ 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: { @@ -178,7 +164,6 @@ export class BranchUserController extends Controller { { user: { email: { contains: query, mode: "insensitive" } } }, { user: { telephoneNo: { contains: query, mode: "insensitive" } } }, ], - ...whereDateQuery(startDate, endDate), } satisfies Prisma.BranchUserWhereInput; const [result, total] = await prisma.$transaction([ diff --git a/src/controllers/02-user-controller.ts b/src/controllers/02-user-controller.ts index e05fcd1..7ba34e6 100644 --- a/src/controllers/02-user-controller.ts +++ b/src/controllers/02-user-controller.ts @@ -27,7 +27,6 @@ import { listRole, getUserRoles, removeUserRoles, - getGroupUser, } from "../services/keycloak"; import { isSystem } from "../utils/keycloak"; import { @@ -52,7 +51,6 @@ import { connectOrNot, queryOrNot, whereAddressQuery, - whereDateQuery, } from "../utils/relation"; import { isUsedError, notFoundError, relationError } from "../utils/error"; import { retry } from "../utils/func"; @@ -61,17 +59,10 @@ if (!process.env.MINIO_BUCKET) { throw Error("Require MinIO bucket."); } -const MANAGE_ROLES = [ - "system", - "head_of_admin", - "admin", - "executive", - "branch_admin", - "branch_manager", -]; +const MANAGE_ROLES = ["system", "head_of_admin", "admin", "branch_manager"]; function globalAllow(user: RequestWithUser["user"]) { - const listAllowed = ["system", "head_of_admin", "admin", "executive"]; + const listAllowed = ["system", "head_of_admin"]; return user.roles?.some((v) => listAllowed.includes(v)) || false; } @@ -88,11 +79,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; @@ -106,12 +97,11 @@ 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; - addressForeign?: boolean; address: string; addressEN: string; soi?: string | null; @@ -123,16 +113,9 @@ type UserCreate = { email: string; telephoneNo: string; - subDistrictText?: string | null; - subDistrictTextEN?: string | null; subDistrictId?: string | null; - districtText?: string | null; - districtTextEN?: string | null; districtId?: string | null; - provinceText?: string | null; - provinceTextEN?: string | null; provinceId?: string | null; - zipCodeText?: string | null; selectedImage?: string; @@ -140,9 +123,6 @@ type UserCreate = { remark?: string; agencyStatus?: string; - - contactName?: string | null; - contactTel?: string | null; }; type UserUpdate = { @@ -176,12 +156,11 @@ 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; - addressForeign?: boolean; address?: string; addressEN?: string; soi?: string | null; @@ -195,24 +174,14 @@ type UserUpdate = { selectedImage?: string; - subDistrictText?: string | null; - subDistrictTextEN?: string | null; subDistrictId?: string | null; - districtText?: string | null; - districtTextEN?: string | null; districtId?: string | null; - provinceText?: string | null; - provinceTextEN?: string | null; provinceId?: string | null; - zipCodeText?: string | null; branchId?: string | string[]; remark?: string; agencyStatus?: string; - - contactName?: string | null; - contactTel?: string | null; }; const permissionCondCompany = createPermCondition((_) => true); @@ -304,8 +273,6 @@ export class UserController extends Controller { @Query() status?: Status, @Query() responsibleDistrictId?: string, @Query() activeBranchOnly?: boolean, - @Query() startDate?: Date, - @Query() endDate?: Date, ) { return this.getUserByCriteria( req, @@ -317,8 +284,6 @@ export class UserController extends Controller { status, responsibleDistrictId, activeBranchOnly, - startDate, - endDate, ); } @@ -334,8 +299,6 @@ export class UserController extends Controller { @Query() status?: Status, @Query() responsibleDistrictId?: string, @Query() activeBranchOnly?: boolean, - @Query() startDate?: Date, - @Query() endDate?: Date, @Body() body?: { userId?: string[]; @@ -399,14 +362,12 @@ 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, @@ -425,7 +386,6 @@ 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, })), @@ -440,7 +400,6 @@ 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, @@ -452,11 +411,7 @@ export class UserController extends Controller { if (!record) throw notFoundError("User"); - const { importNationality, ...rest } = record; - - return Object.assign(rest, { - importNationality: importNationality.map((v) => v.name), - }); + return record; } @Post() @@ -522,8 +477,8 @@ export class UserController extends Controller { } const userId = await createUser(username, username, { - firstName: body.firstNameEN, - lastName: body.lastNameEN, + firstName: body.firstName, + lastName: body.lastName, email: body.email, requiredActions: ["UPDATE_PASSWORD"], enabled: rest.status !== "INACTIVE", @@ -558,9 +513,6 @@ 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, @@ -716,7 +668,6 @@ export class UserController extends Controller { const record = await prisma.user.update({ include: { - importNationality: true, province: true, district: true, subDistrict: true, @@ -731,10 +682,6 @@ 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), @@ -986,17 +933,3 @@ 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; - } -} diff --git a/src/controllers/03-customer-branch-citizen-controller.ts b/src/controllers/03-customer-branch-citizen-controller.ts index ad7127d..75110c3 100644 --- a/src/controllers/03-customer-branch-citizen-controller.ts +++ b/src/controllers/03-customer-branch-citizen-controller.ts @@ -23,16 +23,15 @@ const MANAGE_ROLES = [ "system", "head_of_admin", "admin", - "executive", + "head_of_accountant", "accountant", - "branch_admin", - "branch_manager", - "branch_accountant", + "head_of_sale", + "sale", ]; function globalAllow(user: RequestWithUser["user"]) { - const listAllowed = MANAGE_ROLES; - return user.roles?.some((v) => listAllowed.includes(v)) || false; + const allowList = ["system", "head_of_admin", "admin", "head_of_accountant", "head_of_sale"]; + return allowList.some((v) => user.roles?.includes(v)); } type CustomerBranchCitizenPayload = { diff --git a/src/controllers/03-customer-branch-controller.ts b/src/controllers/03-customer-branch-controller.ts index a4d87e4..7818bef 100644 --- a/src/controllers/03-customer-branch-controller.ts +++ b/src/controllers/03-customer-branch-controller.ts @@ -30,7 +30,6 @@ import { connectOrNot, queryOrNot, whereAddressQuery, - whereDateQuery, } from "../utils/relation"; import { isUsedError, notFoundError, relationError } from "../utils/error"; import { @@ -47,18 +46,15 @@ const MANAGE_ROLES = [ "system", "head_of_admin", "admin", - "executive", + "head_of_accountant", "accountant", - "branch_admin", - "branch_manager", - "branch_accountant", "head_of_sale", "sale", ]; function globalAllow(user: RequestWithUser["user"]) { - const listAllowed = MANAGE_ROLES; - return user.roles?.some((v) => listAllowed.includes(v)) || false; + const allowList = ["system", "head_of_admin", "head_of_accountant", "head_of_sale"]; + return allowList.some((v) => user.roles?.includes(v)); } const permissionCondCompany = createPermCondition((_) => true); @@ -87,6 +83,7 @@ export type CustomerBranchCreate = { authorizedCapital?: string; authorizedName?: string; authorizedNameEN?: string; + customerName?: string; telephoneNo: string; @@ -110,7 +107,7 @@ export type CustomerBranchCreate = { contactName: string; agentUserId?: string; - businessTypeId?: string; + businessType: string; jobPosition: string; jobDescription: string; payDate: string; @@ -144,6 +141,7 @@ export type CustomerBranchUpdate = { authorizedCapital?: string; authorizedName?: string; authorizedNameEN?: string; + customerName?: string; telephoneNo: string; @@ -167,7 +165,7 @@ export type CustomerBranchUpdate = { contactName?: string; agentUserId?: string; - businessTypeId?: string; + businessType?: string; jobPosition?: string; jobDescription?: string; payDate?: string; @@ -197,11 +195,10 @@ 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(query, [ + { customerName: { contains: query, mode: "insensitive" } }, { registerName: { contains: query, mode: "insensitive" } }, { registerNameEN: { contains: query, mode: "insensitive" } }, { email: { contains: query, mode: "insensitive" } }, @@ -232,17 +229,11 @@ 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([ prisma.customerBranch.findMany({ orderBy: [{ code: "asc" }, { statusOrder: "asc" }, { createdAt: "asc" }], - omit: { - otpCode: true, - otpExpires: true, - userId: true, - }, include: { customer: includeCustomer, province: true, @@ -251,7 +242,6 @@ export class CustomerBranchController extends Controller { createdBy: true, updatedBy: true, _count: true, - businessType: true, }, where, take: pageSize, @@ -267,11 +257,6 @@ export class CustomerBranchController extends Controller { @Security("keycloak") async getById(@Path() branchId: string) { const record = await prisma.customerBranch.findFirst({ - omit: { - otpCode: true, - otpExpires: true, - userId: true, - }, include: { customer: true, province: true, @@ -279,7 +264,6 @@ export class CustomerBranchController extends Controller { subDistrict: true, createdBy: true, updatedBy: true, - businessType: true, }, where: { id: branchId }, }); @@ -301,8 +285,6 @@ 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(query, [ @@ -318,7 +300,6 @@ export class CustomerBranchController extends Controller { subDistrict: zipCode ? { zipCode } : undefined, gender, }, - ...whereDateQuery(startDate, endDate), } satisfies Prisma.EmployeeWhereInput; const [result, total] = await prisma.$transaction([ @@ -362,11 +343,6 @@ export class CustomerBranchController extends Controller { include: branchRelationPermInclude(req.user), }, branch: { - omit: { - otpCode: true, - otpExpires: true, - userId: true, - }, take: 1, orderBy: { createdAt: "asc" }, }, @@ -395,15 +371,7 @@ export class CustomerBranchController extends Controller { (v) => (v.headOffice || v).code, ); - const { - provinceId, - districtId, - subDistrictId, - customerId, - agentUserId, - businessTypeId, - ...rest - } = body; + const { provinceId, districtId, subDistrictId, customerId, agentUserId, ...rest } = body; const record = await prisma.$transaction( async (tx) => { @@ -446,7 +414,6 @@ export class CustomerBranchController extends Controller { subDistrict: true, createdBy: true, updatedBy: true, - businessType: true, }, data: { ...rest, @@ -458,7 +425,6 @@ export class CustomerBranchController extends Controller { province: connectOrNot(provinceId), district: connectOrNot(districtId), subDistrict: connectOrNot(subDistrictId), - businessType: connectOrNot(businessTypeId), createdBy: { connect: { id: req.user.sub } }, updatedBy: { connect: { id: req.user.sub } }, }, @@ -489,7 +455,6 @@ export class CustomerBranchController extends Controller { }, }, }, - businessType: true, }, }); @@ -534,15 +499,7 @@ export class CustomerBranchController extends Controller { await permissionCheck(req.user, customer.registeredBranch); } - const { - provinceId, - districtId, - subDistrictId, - customerId, - agentUserId, - businessTypeId, - ...rest - } = body; + const { provinceId, districtId, subDistrictId, customerId, agentUserId, ...rest } = body; return await prisma.customerBranch.update({ where: { id: branchId }, @@ -552,7 +509,6 @@ export class CustomerBranchController extends Controller { subDistrict: true, createdBy: true, updatedBy: true, - businessType: true, }, data: { ...rest, @@ -562,7 +518,6 @@ export class CustomerBranchController extends Controller { province: connectOrDisconnect(provinceId), district: connectOrDisconnect(districtId), subDistrict: connectOrDisconnect(subDistrictId), - businessType: connectOrNot(businessTypeId), updatedBy: { connect: { id: req.user.sub } }, }, }); @@ -581,7 +536,6 @@ export class CustomerBranchController extends Controller { }, }, }, - businessType: true, }, }); @@ -634,11 +588,10 @@ export class CustomerBranchFileController extends Controller { }, }, }, - businessType: true, }, }); if (!data) throw notFoundError("Customer Branch"); - await permissionCheckCompany(user, data.customer.registeredBranch); + await permissionCheck(user, data.customer.registeredBranch); } @Get("attachment") diff --git a/src/controllers/03-customer-controller.ts b/src/controllers/03-customer-controller.ts index bd3bc4d..8cac3d9 100644 --- a/src/controllers/03-customer-controller.ts +++ b/src/controllers/03-customer-controller.ts @@ -36,25 +36,21 @@ import { setFile, } from "../utils/minio"; import { isUsedError, notFoundError, relationError } from "../utils/error"; -import { connectOrNot, queryOrNot, whereDateQuery } from "../utils/relation"; -import { json2csv } from "json-2-csv"; +import { connectOrNot, queryOrNot } from "../utils/relation"; const MANAGE_ROLES = [ "system", "head_of_admin", "admin", - "executive", + "head_of_accountant", "accountant", - "branch_admin", - "branch_manager", - "branch_accountant", "head_of_sale", "sale", ]; function globalAllow(user: RequestWithUser["user"]) { - const listAllowed = MANAGE_ROLES; - return user.roles?.some((v) => listAllowed.includes(v)) || false; + const allowList = ["system", "head_of_admin", "head_of_accountant", "head_of_sale"]; + return allowList.some((v) => user.roles?.includes(v)); } const permissionCondCompany = createPermCondition((_) => true); @@ -86,6 +82,7 @@ export type CustomerCreate = { authorizedCapital?: string; authorizedName?: string; authorizedNameEN?: string; + customerName?: string; telephoneNo: string; @@ -109,7 +106,7 @@ export type CustomerCreate = { contactName: string; agentUserId?: string; - businessTypeId?: string | null; + businessType: string; jobPosition: string; jobDescription: string; payDate: string; @@ -168,16 +165,11 @@ export class CustomerController extends Controller { @Query() includeBranch: boolean = false, @Query() company: boolean = false, @Query() activeBranchOnly?: boolean, - @Query() startDate?: Date, - @Query() endDate?: Date, - @Query() businessTypeId?: string, - @Query() provinceId?: string, - @Query() districtId?: string, - @Query() subDistrictId?: string, ) { const where = { OR: queryOrNot(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" } } } }, @@ -196,36 +188,6 @@ export class CustomerController extends Controller { : permissionCond(req.user, { activeOnly: activeBranchOnly }), }, }, - branch: { - some: { - AND: [ - businessTypeId - ? { - OR: [{ businessType: { id: businessTypeId } }], - } - : {}, - - provinceId - ? { - OR: [{ province: { id: provinceId } }], - } - : {}, - - districtId - ? { - OR: [{ district: { id: districtId } }], - } - : {}, - - subDistrictId - ? { - OR: [{ subDistrict: { id: subDistrictId } }], - } - : {}, - ], - }, - }, - ...whereDateQuery(startDate, endDate), } satisfies Prisma.CustomerWhereInput; const [result, total] = await prisma.$transaction([ @@ -235,16 +197,10 @@ export class CustomerController extends Controller { branch: includeBranch ? { include: { - businessType: true, province: true, district: true, subDistrict: true, }, - omit: { - otpCode: true, - otpExpires: true, - userId: true, - }, orderBy: [{ statusOrder: "asc" }, { createdAt: "asc" }], } : { @@ -253,17 +209,11 @@ export class CustomerController extends Controller { district: true, subDistrict: true, }, - omit: { - otpCode: true, - otpExpires: true, - userId: true, - }, take: 1, orderBy: { createdAt: "asc" }, }, createdBy: true, updatedBy: true, - // businessType:true }, orderBy: [{ statusOrder: "asc" }, { createdAt: "asc" }], where, @@ -288,11 +238,6 @@ export class CustomerController extends Controller { district: true, subDistrict: true, }, - omit: { - otpCode: true, - otpExpires: true, - userId: true, - }, orderBy: { createdAt: "asc" }, }, createdBy: true, @@ -364,11 +309,6 @@ export class CustomerController extends Controller { district: true, subDistrict: true, }, - omit: { - otpCode: true, - otpExpires: true, - userId: true, - }, }, createdBy: true, updatedBy: true, @@ -380,8 +320,6 @@ export class CustomerController extends Controller { ...v, code: `${runningKey.replace(`CUSTOMER_BRANCH_${company}_`, "")}-${`${last.value - branch.length + i}`.padStart(2, "0")}`, codeCustomer: runningKey.replace(`CUSTOMER_BRANCH_${company}_`, ""), - businessType: connectOrNot(v.businessTypeId), - businessTypeId: undefined, agentUser: connectOrNot(v.agentUserId), agentUserId: undefined, province: connectOrNot(v.provinceId), @@ -468,11 +406,6 @@ export class CustomerController extends Controller { district: true, subDistrict: true, }, - omit: { - otpCode: true, - otpExpires: true, - userId: true, - }, }, createdBy: true, updatedBy: true, @@ -511,13 +444,7 @@ export class CustomerController extends Controller { await deleteFolder(`customer/${customerId}`); const data = await tx.customer.delete({ include: { - branch: { - omit: { - otpCode: true, - otpExpires: true, - userId: true, - }, - }, + branch: true, registeredBranch: { include: { headOffice: true, @@ -612,52 +539,3 @@ export class CustomerImageController extends Controller { await deleteFile(fileLocation.customer.img(customerId, name)); } } - -@Route("api/v1/customer-export") -@Tags("Customer") -export class CustomerExportController extends CustomerController { - @Get() - @Security("keycloak") - async exportCustomer( - @Request() req: RequestWithUser, - @Query() customerType?: CustomerType, - @Query() query: string = "", - @Query() status?: Status, - @Query() page: number = 1, - @Query() pageSize: number = 30, - @Query() includeBranch: boolean = false, - @Query() company: boolean = false, - @Query() activeBranchOnly?: boolean, - @Query() startDate?: Date, - @Query() endDate?: Date, - @Query() businessTypeId?: string, - @Query() provinceId?: string, - @Query() districtId?: string, - @Query() subDistrictId?: string, - ) { - const ret = await this.list( - req, - customerType, - query, - status, - page, - pageSize, - includeBranch, - company, - activeBranchOnly, - startDate, - endDate, - businessTypeId, - provinceId, - districtId, - subDistrictId, - ); - - this.setHeader("Content-Type", "text/csv"); - - return json2csv( - ret.result.map((v) => Object.assign(v, { branch: v.branch.at(0) ?? null })), - { useDateIso8601Format: true, expandNestedObjects: true }, - ); - } -} diff --git a/src/controllers/03-employee-checkup-controller.ts b/src/controllers/03-employee-checkup-controller.ts index 3fd334d..a72ad2d 100644 --- a/src/controllers/03-employee-checkup-controller.ts +++ b/src/controllers/03-employee-checkup-controller.ts @@ -23,18 +23,14 @@ const MANAGE_ROLES = [ "system", "head_of_admin", "admin", - "executive", + "head_of_accountant", "accountant", - "branch_admin", - "branch_manager", - "branch_accountant", "head_of_sale", - "sale", ]; function globalAllow(user: RequestWithUser["user"]) { - const listAllowed = MANAGE_ROLES; - return user.roles?.some((v) => listAllowed.includes(v)) || false; + const allowList = ["system", "head_of_admin", "head_of_accountant", "head_of_sale"]; + return allowList.some((v) => user.roles?.includes(v)); } type EmployeeCheckupPayload = { diff --git a/src/controllers/03-employee-controller.ts b/src/controllers/03-employee-controller.ts index 303ba15..44629c1 100644 --- a/src/controllers/03-employee-controller.ts +++ b/src/controllers/03-employee-controller.ts @@ -30,7 +30,6 @@ import { connectOrNot, queryOrNot, whereAddressQuery, - whereDateQuery, } from "../utils/relation"; import { isUsedError, notFoundError, relationError } from "../utils/error"; import { @@ -42,7 +41,6 @@ import { listFile, setFile, } from "../utils/minio"; -import { json2csv } from "json-2-csv"; if (!process.env.MINIO_BUCKET) { throw Error("Require MinIO bucket."); @@ -52,23 +50,17 @@ const MANAGE_ROLES = [ "system", "head_of_admin", "admin", - "executive", + "head_of_accountant", "accountant", - "branch_admin", - "branch_manager", - "branch_accountant", "head_of_sale", - "sale", ]; function globalAllow(user: RequestWithUser["user"]) { - const listAllowed = MANAGE_ROLES; - return user.roles?.some((v) => listAllowed.includes(v)) || false; + const allowList = ["system", "head_of_admin", "head_of_accountant", "head_of_sale"]; + return allowList.some((v) => user.roles?.includes(v)); } -const permissionCondCompany = createPermCondition((_) => true); const permissionCond = createPermCondition(globalAllow); -const permissionCheckCompany = createPermCheck((_) => true); const permissionCheck = createPermCheck(globalAllow); type EmployeeCreate = { @@ -81,7 +73,6 @@ type EmployeeCreate = { dateOfBirth?: Date | null; gender: string; nationality: string; - otherNationality?: string | null; namePrefix?: string | null; firstName?: string; @@ -115,10 +106,9 @@ type EmployeeUpdate = { nrcNo?: string | null; - dateOfBirth?: Date | null; + dateOfBirth?: Date; gender?: string; nationality?: string; - otherNationality?: string | null; namePrefix?: string | null; firstName?: string; @@ -126,7 +116,7 @@ type EmployeeUpdate = { middleName?: string | null; middleNameEN?: string | null; lastName?: string; - lastNameEN?: string; + lastNameEN: string; addressEN?: string; address?: string; @@ -151,18 +141,9 @@ type EmployeeUpdate = { export class EmployeeController extends Controller { @Get("stats") @Security("keycloak") - async getEmployeeStats(@Request() req: RequestWithUser, @Query() customerBranchId?: string) { + async getEmployeeStats(@Query() customerBranchId?: string) { return await prisma.employee.count({ - where: { - customerBranchId, - customerBranch: { - customer: isSystem(req.user) - ? undefined - : { - registeredBranch: { OR: permissionCond(req.user) }, - }, - }, - }, + where: { customerBranchId }, }); } @@ -173,8 +154,6 @@ 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({ @@ -204,7 +183,6 @@ export class EmployeeController extends Controller { }, }, }, - ...whereDateQuery(startDate, endDate), }, }) .then((res) => @@ -230,8 +208,6 @@ 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, @@ -246,10 +222,9 @@ export class EmployeeController extends Controller { page, pageSize, activeOnly, - startDate, - endDate, ); } + @Post("list") @Security("keycloak") async listByCriteria( @@ -265,8 +240,6 @@ 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[]; @@ -315,7 +288,6 @@ export class EmployeeController extends Controller { subDistrict: zipCode ? { zipCode } : undefined, gender, }, - ...whereDateQuery(startDate, endDate), } satisfies Prisma.EmployeeWhereInput; const [result, total] = await prisma.$transaction([ @@ -671,7 +643,7 @@ export class EmployeeFileController extends Controller { }, }); if (!data) throw notFoundError("Employee"); - await permissionCheckCompany(user, data.customerBranch.customer.registeredBranch); + await permissionCheck(user, data.customerBranch.customer.registeredBranch); } @Get("image") @@ -927,55 +899,3 @@ export class EmployeeFileController extends Controller { return await deleteFile(fileLocation.employee.inCountryNotice(employeeId, noticeId)); } } - -@Route("api/v1/employee-export") -@Tags("Employee") -export class EmployeeExportController extends EmployeeController { - @Get() - @Security("keycloak") - async exportEmployee( - @Request() req: RequestWithUser, - @Query() zipCode?: string, - @Query() gender?: string, - @Query() status?: Status, - @Query() visa?: boolean, - @Query() passport?: boolean, - @Query() customerId?: string, - @Query() customerBranchId?: string, - @Query() query: string = "", - @Query() page: number = 1, - @Query() pageSize: number = 30, - @Query() activeOnly?: boolean, - @Query() startDate?: Date, - @Query() endDate?: Date, - ) { - const ret = await this.listByCriteria( - req, - zipCode, - gender, - status, - visa, - passport, - customerId, - customerBranchId, - query, - page, - pageSize, - activeOnly, - startDate, - endDate, - ); - - this.setHeader("Content-Type", "text/csv"); - - return json2csv( - ret.result.map((v) => - Object.assign(v, { - employeePassport: v.employeePassport?.at(0) ?? null, - employeeVisa: v.employeeVisa?.at(0) ?? null, - }), - ), - { useDateIso8601Format: true }, - ); - } -} diff --git a/src/controllers/03-employee-other-info-controller.ts b/src/controllers/03-employee-other-info-controller.ts index 83a0a9c..d6b73e7 100644 --- a/src/controllers/03-employee-other-info-controller.ts +++ b/src/controllers/03-employee-other-info-controller.ts @@ -23,18 +23,14 @@ const MANAGE_ROLES = [ "system", "head_of_admin", "admin", - "executive", + "head_of_accountant", "accountant", - "branch_admin", - "branch_manager", - "branch_accountant", "head_of_sale", - "sale", ]; function globalAllow(user: RequestWithUser["user"]) { - const listAllowed = MANAGE_ROLES; - return user.roles?.some((v) => listAllowed.includes(v)) || false; + const allowList = ["system", "head_of_admin", "head_of_accountant", "head_of_sale"]; + return allowList.some((v) => user.roles?.includes(v)); } type EmployeeOtherInfoPayload = { diff --git a/src/controllers/03-employee-passport-controller.ts b/src/controllers/03-employee-passport-controller.ts index c8f5483..8f8c253 100644 --- a/src/controllers/03-employee-passport-controller.ts +++ b/src/controllers/03-employee-passport-controller.ts @@ -22,18 +22,14 @@ const MANAGE_ROLES = [ "system", "head_of_admin", "admin", - "executive", + "head_of_accountant", "accountant", - "branch_admin", - "branch_manager", - "branch_accountant", "head_of_sale", - "sale", ]; function globalAllow(user: RequestWithUser["user"]) { - const listAllowed = MANAGE_ROLES; - return user.roles?.some((v) => listAllowed.includes(v)) || false; + const allowList = ["system", "head_of_admin", "head_of_accountant", "head_of_sale"]; + return allowList.some((v) => user.roles?.includes(v)); } type EmployeePassportPayload = { @@ -47,7 +43,6 @@ type EmployeePassportPayload = { workerStatus: string; nationality: string; - otherNationality?: string | null; namePrefix?: string | null; firstName: string; firstNameEN: string; diff --git a/src/controllers/03-employee-visa-controller.ts b/src/controllers/03-employee-visa-controller.ts index 7c51bf2..b1fe09d 100644 --- a/src/controllers/03-employee-visa-controller.ts +++ b/src/controllers/03-employee-visa-controller.ts @@ -22,18 +22,14 @@ const MANAGE_ROLES = [ "system", "head_of_admin", "admin", - "executive", + "head_of_accountant", "accountant", - "branch_admin", - "branch_manager", - "branch_accountant", "head_of_sale", - "sale", ]; function globalAllow(user: RequestWithUser["user"]) { - const listAllowed = MANAGE_ROLES; - return user.roles?.some((v) => listAllowed.includes(v)) || false; + const allowList = ["system", "head_of_admin", "head_of_accountant", "head_of_sale"]; + return allowList.some((v) => user.roles?.includes(v)); } type EmployeeVisaPayload = { @@ -44,7 +40,6 @@ type EmployeeVisaPayload = { issuePlace: string; issueDate: Date; expireDate: Date; - reportDate?: Date | null; mrz?: string | null; remark?: string | null; diff --git a/src/controllers/03-employee-work-controller.ts b/src/controllers/03-employee-work-controller.ts index 89f8ccf..3704546 100644 --- a/src/controllers/03-employee-work-controller.ts +++ b/src/controllers/03-employee-work-controller.ts @@ -22,18 +22,14 @@ const MANAGE_ROLES = [ "system", "head_of_admin", "admin", - "executive", + "head_of_accountant", "accountant", - "branch_admin", - "branch_manager", - "branch_accountant", "head_of_sale", - "sale", ]; function globalAllow(user: RequestWithUser["user"]) { - const listAllowed = MANAGE_ROLES; - return user.roles?.some((v) => listAllowed.includes(v)) || false; + const allowList = ["system", "head_of_admin", "head_of_accountant", "head_of_sale"]; + return allowList.some((v) => user.roles?.includes(v)); } type EmployeeWorkPayload = { diff --git a/src/controllers/04-flow-template-controller.ts b/src/controllers/04-flow-template-controller.ts index cdb654f..0f80d61 100644 --- a/src/controllers/04-flow-template-controller.ts +++ b/src/controllers/04-flow-template-controller.ts @@ -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, whereDateQuery } from "../utils/relation"; +import { queryOrNot } from "../utils/relation"; type WorkflowPayload = { name: string; @@ -37,37 +37,20 @@ type WorkflowPayload = { attributes?: { [key: string]: any }; responsiblePersonId?: string[]; responsibleInstitution?: string[]; - responsibleGroup?: string[]; messengerByArea?: boolean; }[]; registeredBranchId?: string; status?: Status; }; -const MANAGE_ROLES = [ - "system", - "head_of_admin", - "admin", - "executive", - "accountant", - "branch_admin", - "branch_manager", - "branch_accountant", -]; - -function globalAllow(user: RequestWithUser["user"]) { - const listAllowed = MANAGE_ROLES; - return user.roles?.some((v) => listAllowed.includes(v)) || false; -} - -const permissionCondCompany = createPermCondition(globalAllow); -const permissionCheckCompany = createPermCheck(globalAllow); +const permissionCondCompany = createPermCondition((_) => true); +const permissionCheckCompany = createPermCheck((_) => true); @Route("api/v1/workflow-template") @Tags("Workflow") +@Security("keycloak") export class FlowTemplateController extends Controller { @Get() - @Security("keycloak") async getFlowTemplate( @Request() req: RequestWithUser, @Query() page: number = 1, @@ -75,8 +58,6 @@ export class FlowTemplateController extends Controller { @Query() status?: Status, @Query() query = "", @Query() activeOnly?: boolean, - @Query() startDate?: Date, - @Query() endDate?: Date, ) { const where = { OR: queryOrNot(query, [ @@ -93,7 +74,6 @@ 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({ @@ -106,7 +86,6 @@ export class FlowTemplateController extends Controller { include: { user: true }, }, responsibleInstitution: true, - responsibleGroup: true, }, orderBy: { order: "asc" }, }, @@ -124,7 +103,6 @@ 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, @@ -134,7 +112,6 @@ export class FlowTemplateController extends Controller { } @Get("{templateId}") - @Security("keycloak") async getFlowTemplateById(@Request() _req: RequestWithUser, @Path() templateId: string) { const record = await prisma.workflowTemplate.findFirst({ include: { @@ -146,7 +123,6 @@ export class FlowTemplateController extends Controller { include: { user: true }, }, responsibleInstitution: true, - responsibleGroup: true, }, }, }, @@ -161,13 +137,11 @@ 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), })), }; } @Post() - @Security("keycloak", MANAGE_ROLES) async createFlowTemplate(@Request() req: RequestWithUser, @Body() body: WorkflowPayload) { const where = { OR: [ @@ -238,9 +212,6 @@ export class FlowTemplateController extends Controller { responsibleInstitution: { create: v.responsibleInstitution?.map((group) => ({ group })), }, - responsibleGroup: { - create: v.responsibleGroup?.map((group) => ({ group })), - }, })), }, }, @@ -248,7 +219,6 @@ export class FlowTemplateController extends Controller { } @Put("{templateId}") - @Security("keycloak", MANAGE_ROLES) async updateFlowTemplate( @Request() req: RequestWithUser, @Path() templateId: string, @@ -322,10 +292,6 @@ export class FlowTemplateController extends Controller { deleteMany: {}, create: v.responsibleInstitution?.map((group) => ({ group })), }, - responsibleGroup: { - deleteMany: {}, - create: v.responsibleGroup?.map((group) => ({ group })), - }, }, })), }, @@ -334,7 +300,6 @@ export class FlowTemplateController extends Controller { } @Delete("{templateId}") - @Security("keycloak", MANAGE_ROLES) async deleteFlowTemplateById(@Request() req: RequestWithUser, @Path() templateId: string) { const record = await prisma.workflowTemplate.findUnique({ where: { id: templateId }, diff --git a/src/controllers/04-institution-controller.ts b/src/controllers/04-institution-controller.ts index 7121f3c..76c0fc4 100644 --- a/src/controllers/04-institution-controller.ts +++ b/src/controllers/04-institution-controller.ts @@ -17,7 +17,7 @@ import { } from "tsoa"; import prisma from "../db"; import { isUsedError, notFoundError } from "../utils/error"; -import { queryOrNot, whereDateQuery } from "../utils/relation"; +import { queryOrNot } from "../utils/relation"; import { RequestWithUser } from "../interfaces/user"; import { deleteFile, fileLocation, getFile, getPresigned, listFile, setFile } from "../utils/minio"; import HttpError from "../interfaces/http-error"; @@ -95,17 +95,6 @@ type InstitutionUpdatePayload = { }[]; }; -const MANAGE_ROLES = [ - "system", - "head_of_admin", - "admin", - "executive", - "accountant", - "branch_admin", - "branch_manager", - "branch_accountant", -]; - @Route("api/v1/institution") @Tags("Institution") export class InstitutionController extends Controller { @@ -119,19 +108,8 @@ 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, - startDate, - endDate, - ); + return this.getInstitutionListByCriteria(query, page, pageSize, status, activeOnly, group); } @Post("list") @@ -144,8 +122,6 @@ export class InstitutionController extends Controller { @Query() status?: Status, @Query() activeOnly?: boolean, @Query() group?: string, - @Query() startDate?: Date, - @Query() endDate?: Date, @Body() body?: { group?: string[]; @@ -158,7 +134,6 @@ export class InstitutionController extends Controller { { name: { contains: query, mode: "insensitive" } }, { code: { contains: query, mode: "insensitive" } }, ]), - ...whereDateQuery(startDate, endDate), } satisfies Prisma.InstitutionWhereInput; const [result, total] = await prisma.$transaction([ @@ -196,14 +171,13 @@ export class InstitutionController extends Controller { } @Post() - @Security("keycloak", MANAGE_ROLES) + @Security("keycloak") @OperationId("createInstitution") async createInstitution( @Body() body: InstitutionPayload & { status?: Status; }, - @Request() req: RequestWithUser, ) { return await prisma.$transaction(async (tx) => { const last = await tx.runningNo.upsert({ @@ -220,8 +194,6 @@ export class InstitutionController extends Controller { return await tx.institution.create({ include: { bank: true, - createdBy: true, - updatedBy: true, }, data: { ...body, @@ -232,15 +204,13 @@ export class InstitutionController extends Controller { data: body.bank ?? [], }, }, - createdByUserId: req.user.sub, - updatedByUserId: req.user.sub, }, }); }); } @Put("{institutionId}") - @Security("keycloak", MANAGE_ROLES) + @Security("keycloak") @OperationId("updateInstitution") async updateInstitution( @Path() institutionId: string, @@ -289,7 +259,7 @@ export class InstitutionController extends Controller { } @Delete("{institutionId}") - @Security("keycloak", MANAGE_ROLES) + @Security("keycloak") @OperationId("deleteInstitution") async deleteInstitution(@Path() institutionId: string) { return await prisma.$transaction(async (tx) => { @@ -361,7 +331,7 @@ export class InstitutionFileController extends Controller { } @Put("image/{name}") - @Security("keycloak", MANAGE_ROLES) + @Security("keycloak") async putImage( @Request() req: RequestWithUser, @Path() institutionId: string, @@ -375,7 +345,7 @@ export class InstitutionFileController extends Controller { } @Delete("image/{name}") - @Security("keycloak", MANAGE_ROLES) + @Security("keycloak") async delImage( @Request() req: RequestWithUser, @Path() institutionId: string, @@ -405,7 +375,7 @@ export class InstitutionFileController extends Controller { } @Put("attachment/{name}") - @Security("keycloak", MANAGE_ROLES) + @Security("keycloak") async putAttachment( @Request() req: RequestWithUser, @Path() institutionId: string, @@ -416,7 +386,7 @@ export class InstitutionFileController extends Controller { } @Delete("attachment/{name}") - @Security("keycloak", MANAGE_ROLES) + @Security("keycloak") async delAttachment( @Request() req: RequestWithUser, @Path() institutionId: string, @@ -447,7 +417,7 @@ export class InstitutionFileController extends Controller { } @Put("bank-qr/{bankId}") - @Security("keycloak", MANAGE_ROLES) + @Security("keycloak") async putBankImage( @Request() req: RequestWithUser, @Path() institutionId: string, @@ -461,7 +431,7 @@ export class InstitutionFileController extends Controller { } @Delete("bank-qr/{bankId}") - @Security("keycloak", MANAGE_ROLES) + @Security("keycloak") async delBankImage( @Request() req: RequestWithUser, @Path() institutionId: string, diff --git a/src/controllers/04-invoice-controller.ts b/src/controllers/04-invoice-controller.ts index cff9d20..64efee2 100644 --- a/src/controllers/04-invoice-controller.ts +++ b/src/controllers/04-invoice-controller.ts @@ -21,7 +21,6 @@ import { createPermCondition, } from "../services/permission"; import { PaymentStatus } from "../generated/kysely/types"; -import { whereDateQuery } from "../utils/relation"; type InvoicePayload = { quotationId: string; @@ -29,23 +28,14 @@ type InvoicePayload = { installmentNo: number[]; }; -const MANAGE_ROLES = [ - "system", - "head_of_admin", - "admin", - "executive", - "accountant", - "branch_admin", - "branch_manager", - "branch_accountant", -]; +const MANAGE_ROLES = ["system", "head_of_admin", "admin", "head_of_accountant", "accountant"]; function globalAllow(user: RequestWithUser["user"]) { - const listAllowed = ["system", "head_of_admin", "admin", "executive", "accountant"]; - return user.roles?.some((v) => listAllowed.includes(v)) || false; + const allowList = ["system", "head_of_admin", "head_of_accountant"]; + return allowList.some((v) => user.roles?.includes(v)); } -const permissionCondCompany = createPermCondition(globalAllow); +const permissionCondCompany = createPermCondition((_) => true); const permissionCheck = createPermCheck(globalAllow); @Route("/api/v1/invoice") @@ -105,8 +95,6 @@ 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: [ @@ -117,6 +105,7 @@ export class InvoiceController extends Controller { customerBranch: { OR: [ { code: { contains: query, mode: "insensitive" } }, + { customerName: { contains: query, mode: "insensitive" } }, { registerName: { contains: query, mode: "insensitive" } }, { registerNameEN: { contains: query, mode: "insensitive" } }, { firstName: { contains: query, mode: "insensitive" } }, @@ -143,7 +132,6 @@ export class InvoiceController extends Controller { OR: permissionCondCompany(req.user), }, }, - ...whereDateQuery(startDate, endDate), }; const [result, total] = await prisma.$transaction([ @@ -192,7 +180,7 @@ export class InvoiceController extends Controller { @Post() @OperationId("createInvoice") - @Security("keycloak", MANAGE_ROLES.concat(["head_of_sale", "sale"])) + @Security("keycloak", MANAGE_ROLES) async createInvoice(@Request() req: RequestWithUser, @Body() body: InvoicePayload) { const [quotation] = await prisma.$transaction([ prisma.quotation.findUnique({ @@ -237,7 +225,7 @@ export class InvoiceController extends Controller { title: "ใบแจ้งหนี้ใหม่ / New Invoice", detail: "รหัส / code : " + record.code, registeredBranchId: record.registeredBranchId, - groupReceiver: { create: { name: "branch_accountant" } }, + groupReceiver: { create: { name: "accountant" } }, }, }); diff --git a/src/controllers/04-product-controller.ts b/src/controllers/04-product-controller.ts index 512fff8..8cb8c3e 100644 --- a/src/controllers/04-product-controller.ts +++ b/src/controllers/04-product-controller.ts @@ -11,7 +11,6 @@ import { Security, Tags, Query, - UploadedFile, } from "tsoa"; import { Prisma, Product, Status } from "@prisma/client"; @@ -28,25 +27,20 @@ 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, whereDateQuery } from "../utils/relation"; -import spreadsheet from "../utils/spreadsheet"; -import flowAccount from "../services/flowaccount"; -import { json2csv } from "json-2-csv"; +import { queryOrNot } from "../utils/relation"; const MANAGE_ROLES = [ "system", "head_of_admin", "admin", - "executive", + "head_of_accountant", "accountant", - "branch_admin", - "branch_manager", - "branch_accountant", + "head_of_sale", ]; function globalAllow(user: RequestWithUser["user"]) { - const listAllowed = MANAGE_ROLES; - return user.roles?.some((v) => listAllowed.includes(v)) || false; + const allowList = ["system", "head_of_admin", "head_of_accountant", "head_of_sale"]; + return allowList.some((v) => user.roles?.includes(v)); } const permissionCondCompany = createPermCondition((_) => true); @@ -78,7 +72,6 @@ type ProductCreate = { type ProductUpdate = { status?: "ACTIVE" | "INACTIVE"; - code?: string; name?: string; detail?: string; process?: number; @@ -146,8 +139,6 @@ 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 = @@ -203,7 +194,6 @@ export class ProductController extends Controller { : []), ], }, - ...whereDateQuery(startDate, endDate), } satisfies Prisma.ProductWhereInput; const [result, total] = await prisma.$transaction([ @@ -302,21 +292,13 @@ export class ProductController extends Controller { }, update: { value: { increment: 1 } }, }); - - const listId = await flowAccount.createProducts( - `${body.code.toLocaleUpperCase()}${last.value.toString().padStart(3, "0")}`, - body, - ); - - return await tx.product.create({ + return await prisma.product.create({ include: { createdBy: true, updatedBy: true, }, data: { ...body, - flowAccountProductIdAgentPrice: `${listId.data.productIdAgentPrice}`, - flowAccountProductIdSellPrice: `${listId.data.productIdSellPrice}`, document: body.document ? { createMany: { data: body.document.map((v) => ({ name: v })) }, @@ -390,30 +372,6 @@ export class ProductController extends Controller { await permissionCheck(req.user, productGroup.registeredBranch); } - if ( - product.flowAccountProductIdSellPrice !== null && - product.flowAccountProductIdAgentPrice !== null - ) { - const mergedBody = { - ...body, - code: body.code ?? product.code, - price: body.price ?? product.price, - agentPrice: body.agentPrice ?? product.agentPrice, - serviceCharge: body.serviceCharge ?? product.serviceCharge, - vatIncluded: body.vatIncluded ?? product.vatIncluded, - agentPriceVatIncluded: body.agentPriceVatIncluded ?? product.agentPriceVatIncluded, - serviceChargeVatIncluded: body.serviceChargeVatIncluded ?? product.serviceChargeVatIncluded, - }; - - await flowAccount.editProducts( - product.flowAccountProductIdSellPrice, - product.flowAccountProductIdAgentPrice, - mergedBody, - ); - } else { - throw notFoundError("FlowAccountProductId"); - } - const record = await prisma.product.update({ include: { productGroup: true, @@ -476,18 +434,6 @@ export class ProductController extends Controller { if (record.status !== Status.CREATED) throw isUsedError("Product"); - if ( - record.flowAccountProductIdSellPrice !== null && - record.flowAccountProductIdAgentPrice !== null - ) { - await Promise.all([ - flowAccount.deleteProduct(record.flowAccountProductIdSellPrice), - flowAccount.deleteProduct(record.flowAccountProductIdAgentPrice), - ]); - } else { - throw notFoundError("FlowAccountProductId"); - } - await deleteFolder(fileLocation.product.img(productId)); return await prisma.product.delete({ @@ -498,146 +444,6 @@ 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}") @@ -689,43 +495,3 @@ export class ProductFileController extends Controller { return await deleteFile(fileLocation.product.img(productId, name)); } } - -@Route("api/v1/product-export") -@Tags("Product") -export class ProductExportController extends ProductController { - @Get() - @Security("keycloak") - async exportCustomer( - @Request() req: RequestWithUser, - @Query() status?: Status, - @Query() shared?: boolean, - @Query() productGroupId?: string, - @Query() query: string = "", - @Query() page: number = 1, - @Query() pageSize: number = 30, - @Query() orderField?: keyof Product, - @Query() orderBy?: "asc" | "desc", - @Query() activeOnly?: boolean, - @Query() startDate?: Date, - @Query() endDate?: Date, - ) { - const ret = await this.getProduct( - req, - status, - shared, - productGroupId, - query, - page, - pageSize, - orderField, - orderBy, - activeOnly, - startDate, - endDate, - ); - - this.setHeader("Content-Type", "text/csv"); - - return json2csv(ret.result, { useDateIso8601Format: true, expandNestedObjects: true }); - } -} diff --git a/src/controllers/04-product-group-controller.ts b/src/controllers/04-product-group-controller.ts index e71bd7a..ee27265 100644 --- a/src/controllers/04-product-group-controller.ts +++ b/src/controllers/04-product-group-controller.ts @@ -27,7 +27,7 @@ import { } from "../services/permission"; import { filterStatus } from "../services/prisma"; import { isUsedError, notFoundError, relationError } from "../utils/error"; -import { queryOrNot, whereDateQuery } from "../utils/relation"; +import { queryOrNot } from "../utils/relation"; type ProductGroupCreate = { name: string; @@ -35,7 +35,7 @@ type ProductGroupCreate = { remark: string; status?: Status; shared?: boolean; - registeredBranchId?: string; + registeredBranchId: string; }; type ProductGroupUpdate = { @@ -51,16 +51,14 @@ const MANAGE_ROLES = [ "system", "head_of_admin", "admin", - "executive", + "head_of_accountant", "accountant", - "branch_admin", - "branch_manager", - "branch_accountant", + "head_of_sale", ]; function globalAllow(user: RequestWithUser["user"]) { - const listAllowed = MANAGE_ROLES; - return user.roles?.some((v) => listAllowed.includes(v)) || false; + const allowList = ["system", "head_of_admin", "head_of_accountant", "head_of_sale"]; + return allowList.some((v) => user.roles?.includes(v)); } const permissionCond = createPermCondition((_) => true); @@ -92,8 +90,6 @@ 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(query, [ @@ -109,7 +105,6 @@ export class ProductGroup extends Controller { : { OR: permissionCond(req.user, { activeOnly }) }, }, ], - ...whereDateQuery(startDate, endDate), } satisfies Prisma.ProductGroupWhereInput; const [result, total] = await prisma.$transaction([ @@ -159,23 +154,7 @@ export class ProductGroup extends Controller { @Post() @Security("keycloak", MANAGE_ROLES) async createProductGroup(@Request() req: RequestWithUser, @Body() body: ProductGroupCreate) { - const userAffiliatedBranch = await prisma.branch.findFirst({ - include: branchRelationPermInclude(req.user), - where: body.registeredBranchId - ? { id: body.registeredBranchId } - : { - user: { some: { userId: req.user.sub } }, - }, - }); - if (!userAffiliatedBranch) { - throw new HttpError( - HttpStatus.BAD_REQUEST, - "You must be affilated with at least one branch or specify branch to be registered (System permission required).", - "reqMinAffilatedBranch", - ); - } - - let company = await permissionCheck(req.user, userAffiliatedBranch).then( + let company = await permissionCheck(req.user, body.registeredBranchId).then( (v) => (v.headOffice || v).code, ); @@ -199,7 +178,6 @@ export class ProductGroup extends Controller { }, data: { ...body, - registeredBranchId: userAffiliatedBranch.id, statusOrder: +(body.status === "INACTIVE"), code: `G${last.value.toString().padStart(2, "0")}`, createdByUserId: req.user.sub, diff --git a/src/controllers/04-properties-controller.ts b/src/controllers/04-properties-controller.ts index 6203ec6..35f94a8 100644 --- a/src/controllers/04-properties-controller.ts +++ b/src/controllers/04-properties-controller.ts @@ -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, whereDateQuery } from "../utils/relation"; +import { queryOrNot } from "../utils/relation"; type PropertyPayload = { name: string; @@ -49,8 +49,6 @@ export class PropertiesController extends Controller { @Query() status?: Status, @Query() query = "", @Query() activeOnly?: boolean, - @Query() startDate?: Date, - @Query() endDate?: Date, ) { const where = { OR: queryOrNot(query, [ @@ -63,7 +61,6 @@ export class PropertiesController extends Controller { OR: permissionCondCompany(req.user, { activeOnly: true }), }, }, - ...whereDateQuery(startDate, endDate), } satisfies Prisma.PropertyWhereInput; const [result, total] = await prisma.$transaction([ prisma.property.findMany({ diff --git a/src/controllers/04-receipt-controller.ts b/src/controllers/04-receipt-controller.ts index 55a52c6..caad04b 100644 --- a/src/controllers/04-receipt-controller.ts +++ b/src/controllers/04-receipt-controller.ts @@ -4,7 +4,6 @@ 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); @@ -22,8 +21,6 @@ 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", @@ -36,7 +33,6 @@ export class ReceiptController extends Controller { }, }, }, - ...whereDateQuery(startDate, endDate), }; const [result, total] = await prisma.$transaction([ diff --git a/src/controllers/04-service-controller.ts b/src/controllers/04-service-controller.ts index 82ab2ea..c193fbd 100644 --- a/src/controllers/04-service-controller.ts +++ b/src/controllers/04-service-controller.ts @@ -36,22 +36,20 @@ import { listFile, setFile, } from "../utils/minio"; -import { queryOrNot, whereDateQuery } from "../utils/relation"; +import { queryOrNot } from "../utils/relation"; const MANAGE_ROLES = [ "system", "head_of_admin", "admin", - "executive", + "head_of_accountant", "accountant", - "branch_admin", - "branch_manager", - "branch_accountant", + "head_of_sale", ]; function globalAllow(user: RequestWithUser["user"]) { - const listAllowed = MANAGE_ROLES; - return user.roles?.some((v) => listAllowed.includes(v)) || false; + const allowList = ["system", "head_of_admin", "head_of_accountant", "head_of_sale"]; + return allowList.some((v) => user.roles?.includes(v)); } const permissionCondCompany = createPermCondition((_) => true); @@ -166,8 +164,6 @@ 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 = @@ -223,7 +219,6 @@ export class ServiceController extends Controller { : []), ], }, - ...whereDateQuery(startDate, endDate), } satisfies Prisma.ServiceWhereInput; const [result, total] = await prisma.$transaction([ diff --git a/src/controllers/04-work-controller.ts b/src/controllers/04-work-controller.ts index c8a140b..9b875b6 100644 --- a/src/controllers/04-work-controller.ts +++ b/src/controllers/04-work-controller.ts @@ -18,7 +18,6 @@ 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; @@ -46,12 +45,9 @@ 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([ diff --git a/src/controllers/05-payment-controller.ts b/src/controllers/05-payment-controller.ts index 7ad9584..a4b7339 100644 --- a/src/controllers/05-payment-controller.ts +++ b/src/controllers/05-payment-controller.ts @@ -26,20 +26,11 @@ import flowAccount from "../services/flowaccount"; import HttpError from "../interfaces/http-error"; import HttpStatus from "../interfaces/http-status"; -const MANAGE_ROLES = [ - "system", - "head_of_admin", - "admin", - "executive", - "accountant", - "branch_admin", - "branch_manager", - "branch_accountant", -]; +const MANAGE_ROLES = ["system", "head_of_admin", "admin", "head_of_accountant", "accountant"]; function globalAllow(user: RequestWithUser["user"]) { - const listAllowed = ["system", "head_of_admin", "admin", "executive", "accountant"]; - return user.roles?.some((v) => listAllowed.includes(v)) || false; + const allowList = ["system", "head_of_admin", "head_of_accountant"]; + return allowList.some((v) => user.roles?.includes(v)); } const permissionCondCompany = createPermCondition((_) => true); @@ -110,19 +101,10 @@ export class QuotationPayment extends Controller { } @Put("{paymentId}") - @Security("keycloak", MANAGE_ROLES.concat(["head_of_sale", "sale"])) + @Security("keycloak", MANAGE_ROLES) async updatePayment( @Path() paymentId: string, - @Body() - body: { - amount?: number; - date?: Date; - paymentStatus?: PaymentStatus; - channel?: string | null; - account?: string | null; - reference?: string | null; - }, - @Request() req: RequestWithUser, + @Body() body: { amount?: number; date?: Date; paymentStatus?: PaymentStatus }, ) { const record = await prisma.payment.findUnique({ where: { id: paymentId }, @@ -152,18 +134,7 @@ export class QuotationPayment extends Controller { if (!record) throw notFoundError("Payment"); - if (record.paymentStatus === "PaymentSuccess") { - const { channel, account, reference } = body; - return await prisma.payment.update({ - where: { id: paymentId, invoice: { quotationId: record.invoice.quotationId } }, - data: { - channel, - account, - reference, - updatedByUserId: req.user.sub, - }, - }); - } + if (record.paymentStatus === "PaymentSuccess") return record; return await prisma.$transaction(async (tx) => { const current = new Date(); @@ -193,7 +164,6 @@ export class QuotationPayment extends Controller { code: lastReceipt ? `RE${year}${month}${lastReceipt.value.toString().padStart(6, "0")}` : undefined, - updatedByUserId: req.user.sub, }, }); @@ -209,7 +179,6 @@ export class QuotationPayment extends Controller { await tx.quotation .update({ - include: { requestData: true }, where: { id: quotation.id }, data: { quotationStatus: @@ -267,17 +236,6 @@ export class QuotationPayment extends Controller { receiverId: res.createdByUserId, }, }); - - if (quotation.quotationStatus === "PaymentInProcess") { - await prisma.notification.create({ - data: { - title: "รายการคำขอใหม่ / New Request", - detail: "รหัส / code : " + res.requestData.map((v) => v.code).join(", "), - registeredBranchId: res.registeredBranchId, - groupReceiver: { create: { name: "document_checker" } }, - }, - }); - } }); return payment; diff --git a/src/controllers/05-quotation-controller.ts b/src/controllers/05-quotation-controller.ts index f85b125..fa3d6b3 100644 --- a/src/controllers/05-quotation-controller.ts +++ b/src/controllers/05-quotation-controller.ts @@ -25,7 +25,7 @@ import { import { isSystem } from "../utils/keycloak"; import { isUsedError, notFoundError, relationError } from "../utils/error"; import { precisionRound } from "../utils/arithmetic"; -import { queryOrNot, whereDateQuery } from "../utils/relation"; +import { queryOrNot } 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,14 +55,13 @@ type QuotationCreate = { dateOfBirth: Date; gender: string; nationality: string; - otherNationality?: string | null; namePrefix?: string; firstName: string; firstNameEN: string; middleName?: string; middleNameEN?: string; lastName: string; - lastNameEN?: string; + lastNameEN: string; } )[]; @@ -84,8 +83,6 @@ type QuotationCreate = { installmentNo?: number; workerIndex?: number[]; }[]; - - sellerId?: string; }; type QuotationUpdate = { @@ -115,15 +112,14 @@ type QuotationUpdate = { dateOfBirth: Date; gender: string; nationality: string; - otherNationality?: string | null; namePrefix?: string; - firstName?: string; + firstName: string; firstNameEN: string; middleName?: string; middleNameEN?: string; - lastName?: string; - lastNameEN?: string; + lastName: string; + lastNameEN: string; } )[]; @@ -144,8 +140,6 @@ type QuotationUpdate = { installmentNo?: number; workerIndex?: number[]; }[]; - - sellerId?: string; }; const VAT_DEFAULT = config.vat; @@ -154,16 +148,15 @@ const MANAGE_ROLES = [ "system", "head_of_admin", "admin", - "executive", + "head_of_accountant", "accountant", - "branch_admin", - "branch_manager", - "branch_accountant", + "head_of_sale", + "sale", ]; function globalAllow(user: RequestWithUser["user"]) { - const listAllowed = ["system", "head_of_admin", "admin", "executive", "accountant"]; - return user.roles?.some((v) => listAllowed.includes(v)) || false; + const allowList = ["system", "head_of_admin", "head_of_accountant", "head_of_sale"]; + return allowList.some((v) => user.roles?.includes(v)); } const permissionCheckCompany = createPermCheck((_) => true); @@ -213,9 +206,6 @@ export class QuotationController extends Controller { @Query() forDebitNote?: boolean, @Query() code?: string, @Query() query = "", - @Query() startDate?: Date, - @Query() endDate?: Date, - @Query() sellerId?: string, ) { const where = { OR: queryOrNot(query, [ @@ -225,6 +215,7 @@ export class QuotationController extends Controller { customerBranch: { OR: [ { code: { contains: query, mode: "insensitive" } }, + { customerName: { contains: query, mode: "insensitive" } }, { firstName: { contains: query, mode: "insensitive" } }, { firstNameEN: { contains: query, mode: "insensitive" } }, { lastName: { contains: query, mode: "insensitive" } }, @@ -262,8 +253,6 @@ export class QuotationController extends Controller { }, } : undefined, - ...whereDateQuery(startDate, endDate), - sellerId: sellerId, } satisfies Prisma.QuotationWhereInput; const [result, total] = await prisma.$transaction([ @@ -421,7 +410,7 @@ export class QuotationController extends Controller { } @Post() - @Security("keycloak", MANAGE_ROLES.concat(["head_of_sale", "sale"])) + @Security("keycloak", MANAGE_ROLES) async createQuotation(@Request() req: RequestWithUser, @Body() body: QuotationCreate) { const ids = { employee: body.worker.filter((v) => typeof v === "string"), @@ -527,15 +516,16 @@ export class QuotationController extends Controller { const vatIncluded = body.agentPrice ? p.agentPriceVatIncluded : p.vatIncluded; const originalPrice = body.agentPrice ? p.agentPrice : p.price; - const finalPrice = precisionRound( + const finalPriceWithVat = precisionRound( originalPrice + (vatIncluded ? 0 : originalPrice * VAT_DEFAULT), ); - const pricePerUnit = finalPrice / (1 + VAT_DEFAULT); + + const price = finalPriceWithVat; + const pricePerUnit = price / (1 + VAT_DEFAULT); const vat = (body.agentPrice ? p.agentPriceCalcVat : p.calcVat) - ? ((pricePerUnit * (1 + VAT_DEFAULT) * v.amount - (v.discount || 0)) / - (1 + VAT_DEFAULT)) * - VAT_DEFAULT + ? (pricePerUnit * v.amount - (v.discount || 0)) * VAT_DEFAULT : 0; + return { order: i + 1, productId: v.productId, @@ -556,13 +546,13 @@ export class QuotationController extends Controller { const price = list.reduce( (a, c) => { - const vat = c.vat ? VAT_DEFAULT : 0; - const price = c.pricePerUnit * c.amount * (1 + vat) - c.discount; - - a.totalPrice = precisionRound(a.totalPrice + price / (1 + vat) + c.discount); + a.totalPrice = precisionRound(a.totalPrice + c.pricePerUnit * c.amount); a.totalDiscount = precisionRound(a.totalDiscount + c.discount); a.vat = precisionRound(a.vat + c.vat); - a.vatExcluded = c.vat === 0 ? precisionRound(a.vatExcluded + price) : a.vatExcluded; + a.vatExcluded = + c.vat === 0 + ? precisionRound(a.vatExcluded + (c.pricePerUnit * c.amount - (c.discount || 0))) + : a.vatExcluded; a.finalPrice = precisionRound( Math.max(a.totalPrice - a.totalDiscount + a.vat - (body.discount || 0), 0), ); @@ -663,14 +653,7 @@ export class QuotationController extends Controller { title: "ใบเสนอราคาใหม่ / New Quotation", detail: "รหัส / code : " + ret.code, registeredBranchId: ret.registeredBranchId, - groupReceiver: { - create: [ - { name: "sale" }, - { name: "head_of_sale" }, - { name: "accountant" }, - { name: "branch_accountant" }, - ], - }, + groupReceiver: { create: [{ name: "sale" }, { name: "head_of_sale" }] }, }, }); @@ -678,7 +661,7 @@ export class QuotationController extends Controller { } @Put("{quotationId}") - @Security("keycloak", MANAGE_ROLES.concat(["head_of_sale", "sale"])) + @Security("keycloak", MANAGE_ROLES) async editQuotation( @Request() req: RequestWithUser, @Path() quotationId: string, @@ -814,14 +797,14 @@ export class QuotationController extends Controller { const vatIncluded = record.agentPrice ? p.agentPriceVatIncluded : p.vatIncluded; const originalPrice = record.agentPrice ? p.agentPrice : p.price; - const finalPrice = precisionRound( + const finalPriceWithVat = precisionRound( originalPrice + (vatIncluded ? 0 : originalPrice * VAT_DEFAULT), ); - const pricePerUnit = finalPrice / (1 + VAT_DEFAULT); + + const price = finalPriceWithVat; + const pricePerUnit = price / (1 + VAT_DEFAULT); const vat = (record.agentPrice ? p.agentPriceCalcVat : p.calcVat) - ? ((pricePerUnit * (1 + VAT_DEFAULT) * v.amount - (v.discount || 0)) / - (1 + VAT_DEFAULT)) * - VAT_DEFAULT + ? (pricePerUnit * v.amount - (v.discount || 0)) * VAT_DEFAULT : 0; return { @@ -844,13 +827,15 @@ export class QuotationController extends Controller { const price = list?.reduce( (a, c) => { - const vat = c.vat ? VAT_DEFAULT : 0; - const price = c.pricePerUnit * c.amount * (1 + vat) - c.discount; - - a.totalPrice = precisionRound(a.totalPrice + price / (1 + vat) + c.discount); + a.totalPrice = precisionRound(a.totalPrice + c.pricePerUnit * c.amount); a.totalDiscount = precisionRound(a.totalDiscount + c.discount); a.vat = precisionRound(a.vat + c.vat); - a.vatExcluded = c.vat === 0 ? precisionRound(a.vatExcluded + price) : a.vatExcluded; + a.vatExcluded = + c.vat === 0 + ? precisionRound( + a.vatExcluded + (c.pricePerUnit * c.amount - (c.discount || 0)) * VAT_DEFAULT, + ) + : a.vatExcluded; a.finalPrice = precisionRound( Math.max(a.totalPrice - a.totalDiscount + a.vat - (body.discount || 0), 0), ); @@ -866,7 +851,6 @@ export class QuotationController extends Controller { finalPrice: 0, }, ); - const changed = list?.some((lhs) => { const found = record.productServiceList.find((rhs) => { return ( @@ -900,20 +884,6 @@ export class QuotationController extends Controller { }), ]); - if (customerBranch) { - await tx.customerBranch.update({ - where: { id: customerBranch.id }, - data: { - customer: { - update: { - status: Status.ACTIVE, - }, - }, - status: Status.ACTIVE, - }, - }); - } - return await tx.quotation.update({ include: { productServiceList: { @@ -1035,7 +1005,6 @@ export class QuotationActionController extends Controller { dateOfBirth: Date; gender: string; nationality: string; - otherNationality?: string | null; namePrefix?: string; firstName: string; firstNameEN: string; @@ -1058,7 +1027,6 @@ export class QuotationActionController extends Controller { dateOfBirth: Date; gender: string; nationality: string; - otherNationality?: string | null; namePrefix?: string; firstName: string; firstNameEN: string; diff --git a/src/controllers/06-request-list-controller.ts b/src/controllers/06-request-list-controller.ts index a453716..464b5fc 100644 --- a/src/controllers/06-request-list-controller.ts +++ b/src/controllers/06-request-list-controller.ts @@ -27,12 +27,11 @@ import { createPermCheck, createPermCondition, } from "../services/permission"; -import { queryOrNot, whereDateQuery } from "../utils/relation"; +import { queryOrNot } 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); @@ -81,9 +80,6 @@ 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(query, [ @@ -95,6 +91,7 @@ export class RequestDataController extends Controller { customerBranch: { OR: [ { code: { contains: query, mode: "insensitive" } }, + { customerName: { contains: query, mode: "insensitive" } }, { registerName: { contains: query, mode: "insensitive" } }, { registerNameEN: { contains: query, mode: "insensitive" } }, { firstName: { contains: query, mode: "insensitive" } }, @@ -104,8 +101,6 @@ export class RequestDataController extends Controller { ], }, }, - }, - { employee: { OR: [ { @@ -123,11 +118,7 @@ export class RequestDataController extends Controller { }, ]), code, - requestDataStatus: incomplete - ? { - notIn: [RequestDataStatus.Completed, RequestDataStatus.Canceled], - } - : requestDataStatus, + requestDataStatus, requestWork: responsibleOnly ? { some: { @@ -136,24 +127,9 @@ export class RequestDataController extends Controller { workflow: { step: { some: { - OR: [ - { - responsiblePerson: { - some: { userId: req.user.sub }, - }, - }, - { - responsibleGroup: { - some: { - group: { - in: await getGroupUser(req.user.sub).then((r) => - r.map(({ name }: { name: string }) => name), - ), - }, - }, - }, - }, - ], + responsiblePerson: { + some: { userId: req.user.sub }, + }, }, }, }, @@ -166,7 +142,6 @@ export class RequestDataController extends Controller { id: quotationId, registeredBranch: { OR: permissionCond(req.user) }, }, - ...whereDateQuery(startDate, endDate), } satisfies Prisma.RequestDataWhereInput; const [result, total] = await prisma.$transaction([ @@ -189,7 +164,6 @@ export class RequestDataController extends Controller { include: { user: true }, }, responsibleInstitution: true, - responsibleGroup: true, }, }, }, @@ -208,20 +182,6 @@ export class RequestDataController extends Controller { employeePassport: { orderBy: { expireDate: "desc" }, }, - customerBranch: { - include: { - province: { - include: { - employmentOffice: true, - }, - }, - district: { - include: { - employmentOffice: true, - }, - }, - }, - }, }, }, }, @@ -232,24 +192,7 @@ export class RequestDataController extends Controller { prisma.requestData.count({ where }), ]); - 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, - }; + return { result, page, pageSize, total }; } @Get("{requestDataId}") @@ -288,67 +231,39 @@ export class RequestDataController extends Controller { return record; } - @Post("update-messenger") + @Post("updata-messenger") @Security("keycloak") async updateRequestData( @Request() req: RequestWithUser, @Body() - body: { + boby: { defaultMessengerId: string; requestDataId: string[]; }, ) { - if (body.requestDataId.length === 0) return; - - return await prisma.$transaction(async (tx) => { - const record = await tx.requestData.updateManyAndReturn({ - where: { - id: { in: body.requestDataId }, - quotation: { - registeredBranch: { - OR: permissionCond(req.user), - }, + const record = await prisma.requestData.updateManyAndReturn({ + where: { + id: { in: boby.requestDataId }, + quotation: { + registeredBranch: { + OR: permissionCond(req.user), }, }, - data: { - defaultMessengerId: body.defaultMessengerId, - }, - }); - - if (record.length <= 0) throw notFoundError("Request Data"); - - await tx.requestWorkStepStatus.updateMany({ - where: { - workStatus: { - in: [ - RequestWorkStatus.Pending, - RequestWorkStatus.Waiting, - RequestWorkStatus.InProgress, - ], - }, - requestWork: { - requestDataId: { in: body.requestDataId }, - }, - }, - data: { responsibleUserId: body.defaultMessengerId }, - }); - - return record[0]; + }, + data: { + defaultMessengerId: boby.defaultMessengerId, + }, }); + + if (record.length <= 0) throw notFoundError("Request Data"); + + return record[0]; } } @Route("/api/v1/request-data/{requestDataId}") @Tags("Request List") export class RequestDataActionController extends Controller { - async #getLineToken() { - if (!process.env.LINE_MESSAGING_API_TOKEN) { - console.warn("Line Webhook Activated but LINE_MESSAGING_API_TOKEN not set."); - } - - return process.env.LINE_MESSAGING_API_TOKEN; - } - @Post("reject-request-cancel") @Security("keycloak") async rejectRequestCancel( @@ -423,17 +338,6 @@ export class RequestDataActionController extends Controller { }, }, }, - include: { - quotation: { - include: { - customerBranch: { - include: { - customer: { include: { branch: { where: { userId: { not: null } } } } }, - }, - }, - }, - }, - }, }); if (!result) throw notFoundError("Request Data"); @@ -476,88 +380,23 @@ export class RequestDataActionController extends Controller { data: { quotationStatus: QuotationStatus.Canceled, urgent: false }, }) .then(async (res) => { - await Promise.all( - res.map((v) => - tx.notification.create({ - data: { - title: "สถานะใบเสนอราคาเปลี่ยนแปลง / Quotation Status Updated", - detail: "รหัส / code : " + v.code + " Canceled", - receiverId: v.createdByUserId, - registeredBranchId: v.registeredBranchId, - groupReceiver: { create: { name: "document_checker" } }, - }, - }), - ), - ); + await tx.notification.createMany({ + data: res.map((v) => ({ + title: "สถานะใบเสนอราคาเปลี่ยนแปลง / Quotation Status Updated", + detail: "รหัส / code : " + v.code + " Canceled", + receiverId: v.createdByUserId, + })), + }); }), - tx.taskOrder - .updateManyAndReturn({ - where: { - taskList: { - every: { taskStatus: TaskStatus.Canceled }, - }, + tx.taskOrder.updateMany({ + where: { + taskList: { + every: { taskStatus: TaskStatus.Canceled }, }, - data: { taskOrderStatus: TaskStatus.Canceled }, - }) - .then(async (res) => { - await Promise.all( - res.map((v) => - tx.notification.create({ - data: { - title: "สถานะใบเสนอราคาเปลี่ยนแปลง / Quotation Status Updated", - detail: "รหัส / code : " + v.code + " Canceled", - receiverId: v.createdByUserId, - registeredBranchId: v.registeredBranchId, - groupReceiver: { create: { name: "document_checker" } }, - }, - }), - ), - ); - }), - ]); - - const token = await this.#getLineToken(); - if (!token) return; - - const textHead = "JWS ALERT:"; - - const textAlert = "ขอแจ้งให้ทราบว่าใบเสนอราคา"; - const textAlert2 = "ได้ดำเนินการยกเลิกเรียบร้อยแล้ว"; - const textAlert3 = "หากต้องการข้อมูลเพิ่มเติม กรุณาแจ้งให้ฝ่ายที่เกี่ยวข้องทราบ 🙏"; - let finalTextWork = ""; - let textData = ""; - - let dataCustomerId: string[] = []; - let dataUserId: string[] = []; - - result.quotation.customerBranch.customer.branch.forEach((item) => { - if (!dataCustomerId?.includes(item.id) && item.userId) { - dataCustomerId.push(item.id); - dataUserId.push(item.userId); - } - }); - finalTextWork = `เลขที่ใบเสนอราคา: ${result.code} ${result.quotation.workName}`; - - textData = `${textHead}\n\n${textAlert}\n${finalTextWork}\n${textAlert2}\n\n${textAlert3}`; - - const data = { - to: dataUserId, - messages: [ - { - type: "text", - text: textData, }, - ], - }; - - await fetch("https://api.line.me/v2/bot/message/multicast", { - method: "POST", - headers: { - Authorization: `Bearer ${token}`, - "Content-Type": "application/json", - }, - body: JSON.stringify(data), - }); + data: { taskOrderStatus: TaskStatus.Canceled }, + }), + ]); }); } @@ -689,19 +528,13 @@ export class RequestDataActionController extends Controller { data: { quotationStatus: QuotationStatus.Canceled, urgent: false }, }) .then(async (res) => { - await Promise.all( - res.map((v) => - tx.notification.create({ - data: { - title: "สถานะใบเสนอราคาเปลี่ยนแปลง / Quotation Status Updated", - detail: "รหัส / code : " + v.code + " Canceled", - receiverId: v.createdByUserId, - registeredBranchId: v.registeredBranchId, - groupReceiver: { create: { name: "document_checker" } }, - }, - }), - ), - ); + await tx.notification.createMany({ + data: res.map((v) => ({ + title: "สถานะใบเสนอราคาเปลี่ยนแปลง / Quotation Status Updated", + detail: "รหัส / code : " + v.code + " Canceled", + receiverId: v.createdByUserId, + })), + }); }), tx.taskOrder.updateMany({ where: { @@ -784,83 +617,14 @@ export class RequestDataActionController extends Controller { }, }, data: { quotationStatus: QuotationStatus.ProcessComplete, urgent: false }, - include: { - customerBranch: { - include: { - customer: { - include: { - branch: { - where: { userId: { not: null } }, - }, - }, - }, - }, - }, - }, }) .then(async (res) => { - await Promise.all( - res.map((v) => - tx.notification.create({ - data: { - title: "สถานะใบเสนอราคาเปลี่ยนแปลง / Quotation Status Updated", - detail: "รหัส / code : " + v.code + " Completed", - receiverId: v.createdByUserId, - registeredBranchId: v.registeredBranchId, - groupReceiver: { create: { name: "document_checker" } }, - }, - }), - ), - ); - - const token = await this.#getLineToken(); - if (!token) return; - - const textHead = "JWS ALERT:"; - - const textAlert = "ขอแจ้งให้ทราบว่าใบเสนอราคา"; - const textAlert2 = "ได้ดำเนินการเสร็จสิ้นทุกกระบวนการเรียบร้อยแล้ว"; - const textAlert3 = "หากต้องการข้อมูลเพิ่มเติม กรุณาแจ้งให้ฝ่ายที่เกี่ยวข้องทราบ 🙏"; - let finalTextWork = ""; - let textData = ""; - - let dataCustomerId: string[] = []; - let textWorkList: string[] = []; - let dataUserId: string[] = []; - - if (res) { - res.forEach((data, index) => { - data.customerBranch.customer.branch.forEach((item) => { - if (!dataCustomerId?.includes(item.id) && item.userId) { - dataCustomerId.push(item.id); - dataUserId.push(item.userId); - } - }); - textWorkList.push(`${index + 1}. เลขที่ใบเสนอราคา ${data.code} ${data.workName}`); - }); - - finalTextWork = textWorkList.join("\n"); - } - - textData = `${textHead}\n\n${textAlert}\n${finalTextWork}\n${textAlert2}\n\n${textAlert3}`; - - const data = { - to: dataUserId, - messages: [ - { - type: "text", - text: textData, - }, - ], - }; - - await fetch("https://api.line.me/v2/bot/message/multicast", { - method: "POST", - headers: { - Authorization: `Bearer ${token}`, - "Content-Type": "application/json", - }, - body: JSON.stringify(data), + await tx.notification.createMany({ + data: res.map((v) => ({ + title: "สถานะใบเสนอราคาเปลี่ยนแปลง / Quotation Status Updated", + detail: "รหัส / code : " + v.code + " Completed", + receiverId: v.createdByUserId, + })), }); }); // dataRecord.push(record); @@ -984,7 +748,6 @@ export class RequestListController extends Controller { include: { user: true }, }, responsibleInstitution: true, - responsibleGroup: true, }, }, }, @@ -1045,7 +808,6 @@ export class RequestListController extends Controller { include: { user: true }, }, responsibleInstitution: true, - responsibleGroup: true, }, }, }, @@ -1155,7 +917,7 @@ export class RequestListController extends Controller { }); if (record.responsibleUserId === null) { - await tx.requestWorkStepStatus.update({ + await prisma.requestWorkStepStatus.update({ where: { step_requestWorkId: { step: step, @@ -1217,19 +979,13 @@ export class RequestListController extends Controller { data: { quotationStatus: QuotationStatus.Canceled, urgent: false }, }) .then(async (res) => { - await Promise.all( - res.map((v) => - tx.notification.create({ - data: { - title: "สถานะใบเสนอราคาเปลี่ยนแปลง / Quotation Status Updated", - detail: "รหัส / code : " + v.code + " Canceled", - receiverId: v.createdByUserId, - registeredBranchId: v.registeredBranchId, - groupReceiver: { create: { name: "document_checker" } }, - }, - }), - ), - ); + await tx.notification.createMany({ + data: res.map((v) => ({ + title: "สถานะใบเสนอราคาเปลี่ยนแปลง / Quotation Status Updated", + detail: "รหัส / code : " + v.code + " Canceled", + receiverId: v.createdByUserId, + })), + }); }), tx.taskOrder.updateMany({ where: { @@ -1337,19 +1093,13 @@ export class RequestListController extends Controller { }, }) .then(async (res) => { - await Promise.all( - res.map((v) => - tx.notification.create({ - data: { - title: "สถานะใบเสนอราคาเปลี่ยนแปลง / Quotation Status Updated", - detail: "รหัส / code : " + v.code + " Completed", - receiverId: v.createdByUserId, - registeredBranchId: v.registeredBranchId, - groupReceiver: { create: { name: "document_checker" } }, - }, - }), - ), - ); + await tx.notification.createMany({ + data: res.map((v) => ({ + title: "สถานะใบเสนอราคาเปลี่ยนแปลง / Quotation Status Updated", + detail: "รหัส / code : " + v.code + " Completed", + receiverId: v.createdByUserId, + })), + }); const token = await this.#getLineToken(); if (!token) return; diff --git a/src/controllers/07-task-controller.ts b/src/controllers/07-task-controller.ts index 02def1e..03009b3 100644 --- a/src/controllers/07-task-controller.ts +++ b/src/controllers/07-task-controller.ts @@ -42,23 +42,13 @@ import { listFile, setFile, } from "../utils/minio"; -import { queryOrNot, whereDateQuery } from "../utils/relation"; +import { queryOrNot } from "../utils/relation"; -const MANAGE_ROLES = [ - "system", - "head_of_admin", - "admin", - "executive", - "accountant", - "branch_admin", - "branch_manager", - "branch_accountant", - "data_entry", -]; +const MANAGE_ROLES = ["system", "head_of_admin", "admin", "document_checker"]; function globalAllow(user: RequestWithUser["user"]) { - const listAllowed = ["system", "head_of_admin", "admin", "executive", "accountant"]; - return user.roles?.some((v) => listAllowed.includes(v)) || false; + const allowList = ["system", "head_of_admin"]; + return allowList.some((v) => user.roles?.includes(v)); } const permissionCondCompany = createPermCondition((_) => true); @@ -70,14 +60,11 @@ const permissionCheckCompany = createPermCheck((_) => true); @Tags("Task Order") export class TaskController extends Controller { @Get("stats") - @Security("keycloak") - async getTaskOrderStats(@Request() req: RequestWithUser) { + async getTaskOrderStats() { const task = await prisma.taskOrder.groupBy({ - where: { registeredBranch: { OR: permissionCondCompany(req.user) } }, by: ["taskOrderStatus"], _count: true, }); - return task.reduce>( (a, c) => Object.assign(a, { [c.taskOrderStatus]: c._count }), { @@ -99,8 +86,6 @@ export class TaskController extends Controller { @Query() pageSize = 30, @Query() assignedByUserId?: string, @Query() taskOrderStatus?: TaskOrderStatus, - @Query() startDate?: Date, - @Query() endDate?: Date, ) { return this.getTaskOrderListByCriteria( req, @@ -109,8 +94,6 @@ export class TaskController extends Controller { pageSize, assignedByUserId, taskOrderStatus, - startDate, - endDate, ); } @@ -123,8 +106,6 @@ 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 = { @@ -144,7 +125,6 @@ export class TaskController extends Controller { { contactName: { contains: query, mode: "insensitive" } }, { contactTel: { contains: query, mode: "insensitive" } }, ]), - ...whereDateQuery(startDate, endDate), } satisfies Prisma.TaskOrderWhereInput; const [result, total] = await prisma.$transaction([ @@ -213,7 +193,6 @@ export class TaskController extends Controller { step: { include: { value: true, - responsibleGroup: true, responsiblePerson: { include: { user: true }, }, @@ -265,12 +244,6 @@ export class TaskController extends Controller { taskProduct?: { productId: string; discount?: number }[]; }, ) { - if (body.taskList.length < 1 || !body.registeredBranchId) - throw new HttpError( - HttpStatus.BAD_REQUEST, - "Your created invalid task order", - "taskOrderInvalid", - ); return await prisma.$transaction(async (tx) => { const last = await tx.runningNo.upsert({ where: { @@ -320,8 +293,8 @@ export class TaskController extends Controller { if (updated.count !== taskList.length) { throw new HttpError( HttpStatus.PRECONDITION_FAILED, - "all request work to issue task order must be in ready state.", - "requestworkmustready", + "All request work to issue task order must be in ready state.", + "requestWorkMustReady", ); } await tx.institution.updateMany({ @@ -344,51 +317,49 @@ export class TaskController extends Controller { where: { OR: taskList }, }); - return await tx.taskOrder - .create({ - include: { - taskList: { - include: { - requestWorkStep: { - include: { - requestWork: { - include: { - request: { - include: { - employee: true, - quotation: { - include: { - customerBranch: { - include: { - customer: true, - }, + return await tx.taskOrder.create({ + include: { + taskList: { + include: { + requestWorkStep: { + include: { + requestWork: { + include: { + request: { + include: { + employee: true, + quotation: { + include: { + customerBranch: { + include: { + customer: true, }, }, }, }, }, - productService: { - include: { - service: { - include: { - workflow: { - include: { - step: { - include: { - value: true, - responsiblePerson: { - include: { user: true }, - }, - responsibleInstitution: true, + }, + productService: { + include: { + service: { + include: { + workflow: { + include: { + step: { + include: { + value: true, + responsiblePerson: { + include: { user: true }, }, + responsibleInstitution: true, }, }, }, }, }, - work: true, - product: true, }, + work: true, + product: true, }, }, }, @@ -396,30 +367,20 @@ export class TaskController extends Controller { }, }, }, - institution: true, - createdBy: true, }, - data: { - ...rest, - code, - urgent: work.some((v) => v.requestWork.request.quotation.urgent), - registeredBranchId: userAffiliatedBranch.id, - createdByUserId: req.user.sub, - taskList: { create: taskList }, - taskProduct: { create: taskProduct }, - }, - }) - .then(async (v) => { - await prisma.notification.create({ - data: { - title: "ใบสั่งงานใหม่ / New Task Order", - detail: "รหัส / code : " + v.code, - registeredBranchId: v.registeredBranchId, - groupReceiver: { create: { name: "document_checker" } }, - }, - }); - return v; - }); + institution: true, + createdBy: true, + }, + data: { + ...rest, + code, + urgent: work.some((v) => v.requestWork.request.quotation.urgent), + registeredBranchId: userAffiliatedBranch.id, + createdByUserId: req.user.sub, + taskList: { create: taskList }, + taskProduct: { create: taskProduct }, + }, + }); }); } @@ -562,8 +523,6 @@ export class TaskController extends Controller { title: "มีการส่งงาน / Task Submitted", detail: "รหัสใบสั่งงาน / Order : " + record.code, receiverId: record.createdByUserId, - registeredBranchId: record.registeredBranchId, - groupReceiver: { create: { name: "document_checker" } }, }, }); } @@ -639,28 +598,7 @@ export class TaskActionController extends Controller { return await prisma.$transaction(async (tx) => { const promises = body.map(async (v) => { const record = await tx.task.findFirst({ - include: { - requestWorkStep: { - include: { - requestWork: { - include: { - request: { - include: { - quotation: true, - employee: true, - }, - }, - productService: { - include: { - product: true, - }, - }, - }, - }, - }, - }, - taskOrder: true, - }, + include: { requestWorkStep: true }, where: { step: v.step, requestWorkId: v.requestWorkId, @@ -678,25 +616,6 @@ export class TaskActionController extends Controller { data: { userTaskStatus: UserTaskStatus.Restart }, }); } - - if (v.taskStatus === TaskStatus.Failed) { - const taskCode = record.taskOrder.code; - const taskName = record.taskOrder.taskName; - const productCode = record.requestWorkStep.requestWork.productService.product.code; - const productName = record.requestWorkStep.requestWork.productService.product.name; - const employeeName = `${record.requestWorkStep.requestWork.request.employee.namePrefix}.${record.requestWorkStep.requestWork.request.employee.firstNameEN} ${record.requestWorkStep.requestWork.request.employee.lastNameEN}`; - - await tx.notification.create({ - data: { - title: "ใบรายการคำขอที่จัดการเกิดปัญหา / Task Failed", - detail: `ใบรายการคำขอรหัส ${taskCode}: ${taskName} รหัสสินค้า ${productCode}: ${productName} ของลูกจ้าง ${employeeName} เกิดข้อผิดพลาด`, - groupReceiver: { create: { name: "document_checker" } }, - receiverId: record.requestWorkStep.requestWork.request.quotation.createdByUserId, - registeredBranchId: record.taskOrder.registeredBranchId, - }, - }); - } - return await tx.task.update({ where: { id: record.id }, data: { @@ -758,8 +677,6 @@ export class TaskActionController extends Controller { title: "มีการส่งงาน / Task Submitted", detail: "รหัสใบสั่งงาน / Order : " + record.code, receiverId: record.createdByUserId, - registeredBranchId: record.registeredBranchId, - groupReceiver: { create: { name: "document_checker" } }, }, }), ]); @@ -773,53 +690,22 @@ 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 }, - data: { - userTaskStatus: UserTaskStatus.Submit, - }, + tx.taskOrder.update({ + where: { id: taskOrderId }, + data: { + urgent: false, + taskOrderStatus: TaskOrderStatus.Complete, + userTask: { + updateMany: { + where: { taskOrderId }, + data: { + userTaskStatus: UserTaskStatus.Submit, }, }, }, - }) - .then(async (record) => { - await tx.notification.create({ - data: { - title: "ใบงานเสร็จสิ้น / Task Complete", - detail: "รหัสใบสั่งงาน / Order : " + record.code, - receiverId: record.createdByUserId, - registeredBranchId: record.registeredBranchId, - groupReceiver: { create: { name: "document_checker" } }, - }, - }); - }), + }, + }), tx.requestWorkStepStatus.updateMany({ where: { task: { @@ -923,34 +809,10 @@ export class TaskActionController extends Controller { if (completeCheck) completed.push(item.id); }); - await tx.requestData - .updateManyAndReturn({ - where: { id: { in: completed } }, - include: { - quotation: { - select: { - registeredBranchId: true, - createdByUserId: true, - }, - }, - }, - data: { requestDataStatus: RequestDataStatus.Completed }, - }) - .then(async (res) => { - await Promise.all( - res.map((v) => - tx.notification.create({ - data: { - title: "สถานะใบเสนอราคาเปลี่ยนแปลง / Quotation Status Updated", - detail: "รหัส / code : " + v.code + " Completed", - receiverId: v.quotation.createdByUserId, - registeredBranchId: v.quotation.registeredBranchId, - groupReceiver: { create: { name: "document_checker" } }, - }, - }), - ), - ); - }); + await tx.requestData.updateMany({ + where: { id: { in: completed } }, + data: { requestDataStatus: RequestDataStatus.Completed }, + }); await tx.quotation .updateManyAndReturn({ where: { @@ -990,19 +852,13 @@ export class TaskActionController extends Controller { }, }) .then(async (res) => { - await Promise.all( - res.map((v) => - tx.notification.create({ - data: { - title: "สถานะใบเสนอราคาเปลี่ยนแปลง / Quotation Status Updated", - detail: "รหัส / code : " + v.code + " Completed", - receiverId: v.createdByUserId, - registeredBranchId: v.registeredBranchId, - groupReceiver: { create: { name: "document_checker" } }, - }, - }), - ), - ); + await tx.notification.createMany({ + data: res.map((v) => ({ + title: "สถานะใบเสนอราคาเปลี่ยนแปลง / Quotation Status Updated", + detail: "รหัส / code : " + v.code + " Completed", + receiverId: v.createdByUserId, + })), + }); const token = await this.#getLineToken(); @@ -1123,8 +979,6 @@ export class UserTaskController extends Controller { @Query() page = 1, @Query() pageSize = 30, @Query() userTaskStatus?: UserTaskStatus, - @Query() startDate?: Date, - @Query() endDate?: Date, ) { const where = { taskList: { @@ -1171,7 +1025,6 @@ export class UserTaskController extends Controller { { contactName: { contains: query, mode: "insensitive" } }, { contactTel: { contains: query, mode: "insensitive" } }, ]), - ...whereDateQuery(startDate, endDate), } satisfies Prisma.TaskOrderWhereInput; const [result, total] = await prisma.$transaction([ @@ -1241,23 +1094,19 @@ export class UserTaskController extends Controller { }, }) .then(async (v) => { - await tx.notification.create({ - data: { - title: "สถานะใบส่งงานมีการเปลี่ยนแปลง / Order Status Changed", - detail: "รหัสใบสั่งงาน / Order : " + v.code + " InProgress", - receiverId: v.createdByUserId, - registeredBranchId: v.registeredBranchId, - groupReceiver: { create: { name: "document_checker" } }, - }, - }); - await tx.notification.create({ - data: { - title: "มีการรับงาน / Task Accepted", - detail: "รหัสใบสั่งงาน / Order : " + v.code, - receiverId: v.createdByUserId, - registeredBranchId: v.registeredBranchId, - groupReceiver: { create: { name: "document_checker" } }, - }, + await tx.notification.createMany({ + data: [ + { + title: "สถานะใบส่งงานมีการเปลี่ยนแปลง / Order Status Changed", + detail: "รหัสใบสั่งงาน / Order : " + v.code + " InProgress", + receiverId: v.createdByUserId, + }, + { + title: "มีการรับงาน / Task Accepted", + detail: "รหัสใบสั่งงาน / Order : " + v.code, + receiverId: v.createdByUserId, + }, + ], }); }), tx.task.updateMany({ diff --git a/src/controllers/08-credit-note-controller.ts b/src/controllers/08-credit-note-controller.ts index a8e8767..5fda3eb 100644 --- a/src/controllers/08-credit-note-controller.ts +++ b/src/controllers/08-credit-note-controller.ts @@ -13,7 +13,6 @@ import { Security, Tags, } from "tsoa"; -import config from "../config.json"; import prisma from "../db"; @@ -36,28 +35,29 @@ import { } from "../utils/minio"; import { notFoundError } from "../utils/error"; import { CreditNotePaybackType, CreditNoteStatus, Prisma, RequestDataStatus } from "@prisma/client"; -import { queryOrNot, whereDateQuery } from "../utils/relation"; +import { queryOrNot } from "../utils/relation"; import { PaybackStatus, RequestWorkStatus } from "../generated/kysely/types"; const MANAGE_ROLES = [ "system", "head_of_admin", "admin", - "executive", + "head_of_accountant", "accountant", - "branch_admin", - "branch_manager", - "branch_accountant", + "head_of_sale", + "sale", ]; function globalAllow(user: RequestWithUser["user"]) { - const listAllowed = ["system", "head_of_admin", "admin", "executive", "accountant"]; - return user.roles?.some((v) => listAllowed.includes(v)) || false; + const allowList = ["system", "head_of_admin", "head_of_accountant", "head_of_sale"]; + return allowList.some((v) => user.roles?.includes(v)); } -const VAT_DEFAULT = config.vat; +// NOTE: permission condition/check in requestWork -> requestData -> quotation -> registeredBranch const permissionCond = createPermCondition(globalAllow); +const permissionCondCompany = createPermCondition((_) => true); const permissionCheck = createPermCheck(globalAllow); +const permissionCheckCompany = createPermCheck((_) => true); type CreditNoteCreate = { requestWorkId: string[]; @@ -85,14 +85,6 @@ type CreditNoteUpdate = { @Route("api/v1/credit-note") @Tags("Credit Note") export class CreditNoteController extends Controller { - async #getLineToken() { - if (!process.env.LINE_MESSAGING_API_TOKEN) { - console.warn("Line Webhook Activated but LINE_MESSAGING_API_TOKEN not set."); - } - - return process.env.LINE_MESSAGING_API_TOKEN; - } - @Get("stats") @Security("keycloak") async getCreditNoteStats(@Request() req: RequestWithUser, @Query() quotationId?: string) { @@ -102,7 +94,7 @@ export class CreditNoteController extends Controller { request: { quotationId, quotation: { - registeredBranch: { OR: permissionCond(req.user) }, + registeredBranch: { OR: permissionCondCompany(req.user) }, }, }, }, @@ -129,8 +121,6 @@ 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, @@ -139,8 +129,6 @@ export class CreditNoteController extends Controller { query, quotationId, creditNoteStatus, - startDate, - endDate, ); } @@ -154,8 +142,7 @@ export class CreditNoteController extends Controller { @Query() query: string = "", @Query() quotationId?: string, @Query() creditNoteStatus?: CreditNoteStatus, - @Query() startDate?: Date, - @Query() endDate?: Date, + @Body() body?: {}, ) { const where = { OR: queryOrNot(query, [ @@ -172,6 +159,7 @@ export class CreditNoteController extends Controller { customerBranch: { OR: [ { code: { contains: query, mode: "insensitive" } }, + { customerName: { contains: query, mode: "insensitive" } }, { firstName: { contains: query, mode: "insensitive" } }, { firstNameEN: { contains: query, mode: "insensitive" } }, { lastName: { contains: query, mode: "insensitive" } }, @@ -206,19 +194,16 @@ export class CreditNoteController extends Controller { request: { quotationId, quotation: { - registeredBranch: { OR: permissionCond(req.user) }, + registeredBranch: { OR: permissionCondCompany(req.user) }, }, }, }, }, - ...whereDateQuery(startDate, endDate), } satisfies Prisma.CreditNoteWhereInput; const [result, total] = await prisma.$transaction([ prisma.creditNote.findMany({ where, - take: pageSize, - skip: (page - 1) * pageSize, include: { quotation: { include: { @@ -251,7 +236,7 @@ export class CreditNoteController extends Controller { some: { request: { quotation: { - registeredBranch: { OR: permissionCond(req.user) }, + registeredBranch: { OR: permissionCondCompany(req.user) }, }, }, }, @@ -349,8 +334,9 @@ export class CreditNoteController extends Controller { ).length; const price = - c.productService.pricePerUnit * (1 + (c.productService.vat > 0 ? VAT_DEFAULT : 0)) - - c.productService.discount; + c.productService.pricePerUnit - + c.productService.discount / c.productService.amount + + c.productService.vat / c.productService.amount; if (serviceChargeStepCount && successCount) { return a + price - c.productService.product.serviceCharge * successCount; @@ -376,98 +362,40 @@ export class CreditNoteController extends Controller { update: { value: { increment: 1 } }, }); - return await prisma.creditNote - .create({ - include: { - requestWork: { - include: { - request: true, - }, - }, - quotation: { - include: { - customerBranch: { - include: { - customer: { include: { branch: { where: { userId: { not: null } } } } }, - }, - }, - }, + return await prisma.creditNote.create({ + include: { + requestWork: { + include: { + request: true, }, }, - data: { - reason: body.reason, - detail: body.detail, - remark: body.remark, - paybackType: body.paybackType, - paybackBank: body.paybackBank, - paybackAccount: body.paybackAccount, - paybackAccountName: body.paybackAccountName, - code: `CN${currentYear.toString().padStart(2, "0")}${currentMonth.toString().padStart(2, "0")}${last.value.toString().padStart(6, "0")}`, - value, - requestWork: { - connect: body.requestWorkId.map((v) => ({ - id: v, - })), - }, - quotationId: body.quotationId, + quotation: true, + }, + data: { + reason: body.reason, + detail: body.detail, + remark: body.remark, + paybackType: body.paybackType, + paybackBank: body.paybackBank, + paybackAccount: body.paybackAccount, + paybackAccountName: body.paybackAccountName, + code: `CN${currentYear.toString().padStart(2, "0")}${currentMonth.toString().padStart(2, "0")}${last.value.toString().padStart(6, "0")}`, + value, + requestWork: { + connect: body.requestWorkId.map((v) => ({ + id: v, + })), }, - }) - .then(async (res) => { - const token = await this.#getLineToken(); - if (!token) return; - - const textHead = "JWS ALERT:"; - - const textAlert = "ขอแจ้งให้ทราบว่าใบลดหนี้"; - const textAlert2 = "ได้ถูกสร้างขึ้นเรียบร้อยแล้ว"; - const textAlert3 = - "หากท่านต้องการข้อมูลเพิ่มเติมหรือมีข้อสงสัยประการใด โปรดแจ้งให้ฝ่ายที่เกี่ยวข้องทราบ ทางเรายินดีให้ความช่วยเหลืออย่างเต็มที่ 🙏"; - let finalTextWork = ""; - let textData = ""; - - let dataCustomerId: string[] = []; - let dataUserId: string[] = []; - - if (res) { - res.quotation.customerBranch.customer.branch.forEach((item) => { - if (!dataCustomerId?.includes(item.id) && item.userId) { - dataCustomerId.push(item.id); - dataUserId.push(item.userId); - } - }); - finalTextWork = `จำนวนเงิน ${res.value.toFixed(2)} บาท `; - } - - textData = `${textHead}\n\n${textAlert}\n${finalTextWork}${textAlert2}\n\n${textAlert3}`; - - const data = { - to: dataUserId, - messages: [ - { - type: "text", - text: textData, - }, - ], - }; - - await fetch("https://api.line.me/v2/bot/message/multicast", { - method: "POST", - headers: { - Authorization: `Bearer ${token}`, - "Content-Type": "application/json", - }, - body: JSON.stringify(data), - }); - - return res; - }); + quotationId: body.quotationId, + }, + }); }, { isolationLevel: Prisma.TransactionIsolationLevel.Serializable }, ); } @Put("{creditNoteId}") - @Security("keycloak") + @Security("keycloak", MANAGE_ROLES) async updateCreditNote( @Request() req: RequestWithUser, @Path() creditNoteId: string, @@ -542,8 +470,9 @@ export class CreditNoteController extends Controller { ).length; const price = - c.productService.pricePerUnit * (1 + (c.productService.vat > 0 ? VAT_DEFAULT : 0)) - - c.productService.discount; + c.productService.pricePerUnit - + c.productService.discount / c.productService.amount + + c.productService.vat / c.productService.amount; if (serviceChargeStepCount && successCount) { return a + price - c.productService.product.serviceCharge * successCount; @@ -640,14 +569,6 @@ export class CreditNoteActionController extends Controller { return creditNoteData; } - async #getLineToken() { - if (!process.env.LINE_MESSAGING_API_TOKEN) { - console.warn("Line Webhook Activated but LINE_MESSAGING_API_TOKEN not set."); - } - - return process.env.LINE_MESSAGING_API_TOKEN; - } - @Post("accept") @Security("keycloak", MANAGE_ROLES) async acceptCreditNote(@Request() req: RequestWithUser, @Path() creditNoteId: string) { @@ -666,81 +587,23 @@ export class CreditNoteActionController extends Controller { @Body() body: { paybackStatus: PaybackStatus }, ) { await this.#checkPermission(req.user, creditNoteId); - return await prisma.creditNote - .update({ - where: { id: creditNoteId }, - include: { - requestWork: { - include: { - request: true, - }, - }, - quotation: { - include: { - customerBranch: { - include: { - customer: { include: { branch: { where: { userId: { not: null } } } } }, - }, - }, - }, + return await prisma.creditNote.update({ + where: { id: creditNoteId }, + include: { + requestWork: { + include: { + request: true, }, }, - data: { - creditNoteStatus: - body.paybackStatus === PaybackStatus.Done ? CreditNoteStatus.Success : undefined, - paybackStatus: body.paybackStatus, - paybackDate: body.paybackStatus === PaybackStatus.Done ? new Date() : undefined, - }, - }) - .then(async (res) => { - const token = await this.#getLineToken(); - if (!token) return; - - const textHead = "JWS ALERT:"; - - const textAlert = "ทางเราขอแจ้งให้ทราบว่าการดำเนินการคืนเงินสำหรับใบลดหนี้"; - const textAlert2 = "ได้รับการอนุมัติและเสร็จสมบูรณ์เรียบร้อยแล้ว"; - const textAlert3 = - "หากท่านต้องการข้อมูลเพิ่มเติมหรือมีข้อสงสัยประการใด โปรดแจ้งให้ฝ่ายที่เกี่ยวข้องทราบ ทางเรายินดีให้ความช่วยเหลืออย่างเต็มที่ 🙏"; - let finalTextWork = ""; - let textData = ""; - - let dataCustomerId: string[] = []; - let textWorkList: string[] = []; - let dataUserId: string[] = []; - - if (res) { - res.quotation.customerBranch.customer.branch.forEach((item) => { - if (!dataCustomerId?.includes(item.id) && item.userId) { - dataCustomerId.push(item.id); - dataUserId.push(item.userId); - } - }); - finalTextWork = `จำนวนเงิน ${res.value.toFixed(2)} บาท `; - } - - textData = `${textHead}\n\n${textAlert}\n${finalTextWork}${textAlert2}\n\n${textAlert3}`; - - const data = { - to: dataUserId, - messages: [ - { - type: "text", - text: textData, - }, - ], - }; - body.paybackStatus === PaybackStatus.Done - ? await fetch("https://api.line.me/v2/bot/message/multicast", { - method: "POST", - headers: { - Authorization: `Bearer ${token}`, - "Content-Type": "application/json", - }, - body: JSON.stringify(data), - }) - : undefined; - }); + quotation: true, + }, + data: { + creditNoteStatus: + body.paybackStatus === PaybackStatus.Done ? CreditNoteStatus.Success : undefined, + paybackStatus: body.paybackStatus, + paybackDate: body.paybackStatus === PaybackStatus.Done ? new Date() : undefined, + }, + }); } } diff --git a/src/controllers/09-debit-note-controller.ts b/src/controllers/09-debit-note-controller.ts index f87bbe9..a499f88 100644 --- a/src/controllers/09-debit-note-controller.ts +++ b/src/controllers/09-debit-note-controller.ts @@ -36,7 +36,7 @@ import { setFile, } from "../utils/minio"; import { isUsedError, notFoundError, relationError } from "../utils/error"; -import { queryOrNot, whereDateQuery } from "../utils/relation"; +import { queryOrNot } from "../utils/relation"; import { isSystem } from "../utils/keycloak"; import { precisionRound } from "../utils/arithmetic"; @@ -44,20 +44,22 @@ const MANAGE_ROLES = [ "system", "head_of_admin", "admin", - "executive", + "head_of_accountant", "accountant", - "branch_admin", - "branch_manager", - "branch_accountant", + "head_of_sale", + "sale", ]; function globalAllow(user: RequestWithUser["user"]) { - const listAllowed = ["system", "head_of_admin", "admin", "executive", "accountant"]; - return user.roles?.some((v) => listAllowed.includes(v)) || false; + const allowList = ["system", "head_of_admin", "head_of_accountant", "head_of_sale"]; + return allowList.some((v) => user.roles?.includes(v)); } +// NOTE: permission condition/check in registeredBranch const permissionCond = createPermCondition(globalAllow); +const permissionCondCompany = createPermCondition((_) => true); const permissionCheck = createPermCheck(globalAllow); +const permissionCheckCompany = createPermCheck((_) => true); type DebitNoteCreate = { quotationId: string; @@ -74,7 +76,6 @@ type DebitNoteCreate = { dateOfBirth: Date; gender: string; nationality: string; - otherNationality?: string | null; namePrefix?: string; firstName: string; firstNameEN: string; @@ -110,14 +111,13 @@ type DebitNoteUpdate = { dateOfBirth: Date; gender: string; nationality: string; - otherNationality?: string | null; namePrefix?: string; - firstName?: string; + firstName: string; firstNameEN: string; middleName?: string; middleNameEN?: string; - lastName?: string; - lastNameEN?: string; + lastName: string; + lastNameEN: string; } )[]; @@ -168,8 +168,6 @@ 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, @@ -181,8 +179,6 @@ export class DebitNoteController extends Controller { payCondition, includeRegisteredBranch, code, - startDate, - endDate, ); } @@ -199,8 +195,6 @@ export class DebitNoteController extends Controller { @Query() payCondition?: PayCondition, @Query() includeRegisteredBranch?: boolean, @Query() code?: string, - @Query() startDate?: Date, - @Query() endDate?: Date, @Body() body?: {}, ) { const where = { @@ -211,6 +205,7 @@ export class DebitNoteController extends Controller { customerBranch: { OR: [ { code: { contains: query, mode: "insensitive" } }, + { customerName: { contains: query, mode: "insensitive" } }, { firstName: { contains: query, mode: "insensitive" } }, { firstNameEN: { contains: query, mode: "insensitive" } }, { lastName: { contains: query, mode: "insensitive" } }, @@ -225,7 +220,6 @@ 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([ @@ -430,18 +424,12 @@ export class DebitNoteController extends Controller { const list = body.productServiceList.map((v, i) => { const p = product.find((p) => p.id === v.productId)!; - - const vatIncluded = body.agentPrice ? p.agentPriceVatIncluded : p.vatIncluded; - - const originalPrice = body.agentPrice ? p.agentPrice : p.price; - const finalPrice = precisionRound( - originalPrice + (vatIncluded ? 0 : originalPrice * VAT_DEFAULT), - ); - const pricePerUnit = finalPrice / (1 + VAT_DEFAULT); - const vat = (body.agentPrice ? p.agentPriceCalcVat : p.calcVat) - ? ((pricePerUnit * (1 + VAT_DEFAULT) * v.amount - (v.discount || 0)) / - (1 + VAT_DEFAULT)) * - VAT_DEFAULT + const price = body.agentPrice ? p.agentPrice : p.price; + const pricePerUnit = p.vatIncluded ? price / (1 + VAT_DEFAULT) : price; + const vat = p.calcVat + ? (pricePerUnit * (v.discount ? v.amount : 1) - (v.discount || 0)) * + VAT_DEFAULT * + (!v.discount ? v.amount : 1) : 0; return { @@ -464,13 +452,15 @@ export class DebitNoteController extends Controller { const price = list.reduce( (a, c) => { - const vat = c.vat ? VAT_DEFAULT : 0; - const price = c.pricePerUnit * c.amount * (1 + vat) - c.discount; - - a.totalPrice = precisionRound(a.totalPrice + price / (1 + vat) + c.discount); + a.totalPrice = precisionRound(a.totalPrice + c.pricePerUnit * c.amount); a.totalDiscount = precisionRound(a.totalDiscount + c.discount); a.vat = precisionRound(a.vat + c.vat); - a.vatExcluded = c.vat === 0 ? precisionRound(a.vatExcluded + price) : a.vatExcluded; + a.vatExcluded = + c.vat === 0 + ? precisionRound( + a.vatExcluded + (c.pricePerUnit * c.amount - (c.discount || 0)) * VAT_DEFAULT, + ) + : a.vatExcluded; a.finalPrice = precisionRound( Math.max(a.totalPrice - a.totalDiscount + a.vat - (body.discount || 0), 0), ); @@ -582,7 +572,7 @@ export class DebitNoteController extends Controller { } @Put("{debitNoteId}") - @Security("keycloak") + @Security("keycloak", MANAGE_ROLES) async updateDebitNote( @Request() req: RequestWithUser, @Path() debitNoteId: string, @@ -606,7 +596,7 @@ export class DebitNoteController extends Controller { if (!record) throw notFoundError("Debit Note"); - await permissionCheck(req.user, record.registeredBranch); + await permissionCheckCompany(req.user, record.registeredBranch); const { productServiceList: _productServiceList, ...rest } = body; const ids = { @@ -677,18 +667,12 @@ export class DebitNoteController extends Controller { } const list = body.productServiceList.map((v, i) => { const p = product.find((p) => p.id === v.productId)!; - - const vatIncluded = record.agentPrice ? p.agentPriceVatIncluded : p.vatIncluded; - - const originalPrice = record.agentPrice ? p.agentPrice : p.price; - const finalPrice = precisionRound( - originalPrice + (vatIncluded ? 0 : originalPrice * VAT_DEFAULT), - ); - const pricePerUnit = finalPrice / (1 + VAT_DEFAULT); - const vat = (record.agentPrice ? p.agentPriceCalcVat : p.calcVat) - ? ((pricePerUnit * (1 + VAT_DEFAULT) * v.amount - (v.discount || 0)) / - (1 + VAT_DEFAULT)) * - VAT_DEFAULT + const price = body.agentPrice ? p.agentPrice : p.price; + const pricePerUnit = p.vatIncluded ? price / (1 + VAT_DEFAULT) : price; + const vat = p.calcVat + ? (pricePerUnit * (v.discount ? v.amount : 1) - (v.discount || 0)) * + VAT_DEFAULT * + (!v.discount ? v.amount : 1) : 0; return { @@ -711,13 +695,15 @@ export class DebitNoteController extends Controller { const price = list.reduce( (a, c) => { - const vat = c.vat ? VAT_DEFAULT : 0; - const price = c.pricePerUnit * c.amount * (1 + vat) - c.discount; - - a.totalPrice = precisionRound(a.totalPrice + price / (1 + vat) + c.discount); + a.totalPrice = precisionRound(a.totalPrice + c.pricePerUnit * c.amount); a.totalDiscount = precisionRound(a.totalDiscount + c.discount); a.vat = precisionRound(a.vat + c.vat); - a.vatExcluded = c.vat === 0 ? precisionRound(a.vatExcluded + price) : a.vatExcluded; + a.vatExcluded = + c.vat === 0 + ? precisionRound( + a.vatExcluded + (c.pricePerUnit * c.amount - (c.discount || 0)) * VAT_DEFAULT, + ) + : a.vatExcluded; a.finalPrice = precisionRound( Math.max(a.totalPrice - a.totalDiscount + a.vat - (body.discount || 0), 0), ); diff --git a/src/controllers/09-line-controller.ts b/src/controllers/09-line-controller.ts index 87480b7..0a6ea3c 100644 --- a/src/controllers/09-line-controller.ts +++ b/src/controllers/09-line-controller.ts @@ -25,7 +25,7 @@ import { TaskStatus, RequestWorkStatus, } from "@prisma/client"; -import { queryOrNot, whereAddressQuery, whereDateQuery } from "../utils/relation"; +import { queryOrNot, whereAddressQuery } 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,8 +51,6 @@ 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 @@ -89,7 +87,6 @@ export class LineController extends Controller { subDistrict: zipCode ? { zipCode } : undefined, gender, }, - ...whereDateQuery(startDate, endDate), } satisfies Prisma.EmployeeWhereInput; const [result, total] = await prisma.$transaction([ @@ -176,8 +173,6 @@ export class LineController extends Controller { @Query() requestDataStatus?: RequestDataStatus, @Query() quotationId?: string, @Query() code?: string, - @Query() startDate?: Date, - @Query() endDate?: Date, ) { const where = { OR: queryOrNot(query, [ @@ -189,6 +184,7 @@ export class LineController extends Controller { customerBranch: { OR: [ { code: { contains: query, mode: "insensitive" } }, + { customerName: { contains: query, mode: "insensitive" } }, { registerName: { contains: query, mode: "insensitive" } }, { registerNameEN: { contains: query, mode: "insensitive" } }, { firstName: { contains: query, mode: "insensitive" } }, @@ -251,7 +247,6 @@ export class LineController extends Controller { ], }, }, - ...whereDateQuery(startDate, endDate), } satisfies Prisma.RequestDataWhereInput; const [result, total] = await prisma.$transaction([ @@ -609,26 +604,41 @@ export class LineController extends Controller { @Query() includeRegisteredBranch?: boolean, @Query() code?: string, @Query() query = "", - @Query() startDate?: Date, - @Query() endDate?: Date, ) { const where = { - OR: queryOrNot(query, [ - { code: { contains: query, mode: "insensitive" } }, - { workName: { contains: query, mode: "insensitive" } }, - { - customerBranch: { - OR: [ - { code: { contains: query, mode: "insensitive" } }, - { registerName: { contains: query, mode: "insensitive" } }, - { firstName: { contains: query, mode: "insensitive" } }, - { firstNameEN: { contains: query, mode: "insensitive" } }, - { lastName: { contains: query, mode: "insensitive" } }, - { lastNameEN: { contains: query, mode: "insensitive" } }, - ], - }, - }, - ]), + OR: + query || pendingOnly + ? [ + ...(queryOrNot(query, [ + { code: { contains: query, mode: "insensitive" } }, + { workName: { contains: query, mode: "insensitive" } }, + { + customerBranch: { + OR: [ + { code: { contains: query, mode: "insensitive" } }, + { 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" } }, + ], + }, + }, + ]) || []), + ...(queryOrNot(!!pendingOnly, [ + { + requestData: { + some: { + requestDataStatus: "Pending", + }, + }, + }, + { + requestData: { none: {} }, + }, + ]) || []), + ] + : undefined, isDebitNote: false, code, payCondition, @@ -650,23 +660,6 @@ export class LineController extends Controller { }, } : undefined, - AND: pendingOnly - ? { - OR: [ - { - requestData: { - some: { - requestDataStatus: "Pending", - }, - }, - }, - { - requestData: { none: {} }, - }, - ], - } - : undefined, - ...whereDateQuery(startDate, endDate), } satisfies Prisma.QuotationWhereInput; const [result, total] = await prisma.$transaction([ diff --git a/src/controllers/09-web-hook-controller.ts b/src/controllers/09-web-hook-controller.ts index 028bf75..2914e20 100644 --- a/src/controllers/09-web-hook-controller.ts +++ b/src/controllers/09-web-hook-controller.ts @@ -90,7 +90,7 @@ export class WebHookController extends Controller { firstNameEN: true, lastName: true, lastNameEN: true, - registerName: true, + customerName: true, customer: { select: { customerType: true, @@ -133,13 +133,13 @@ export class WebHookController extends Controller { let textData = ""; if (dataEmployee.length > 0) { - const registerName = - dataEmployee[0]?.employee?.customerBranch?.registerName ?? "ไม่ระบุ"; + const customerName = + dataEmployee[0]?.employee?.customerBranch?.customerName ?? "ไม่ระบุ"; const telephoneNo = dataEmployee[0]?.employee?.customerBranch?.customer.registeredBranch.telephoneNo ?? "ไม่ระบุ"; - const textEmployer = `เรียน คุณ${registerName}`; + const textEmployer = `เรียน คุณ${customerName}`; const textAlert = "ขอแจ้งให้ทราบว่าหนังสือเดินทางของลูกจ้าง"; const textAlert2 = "และจำเป็นต้องดำเนินการต่ออายุในเร็ว ๆ นี้"; const textExpDate = diff --git a/src/controllers/10-business-type-controller.ts b/src/controllers/10-business-type-controller.ts deleted file mode 100644 index 6d7373c..0000000 --- a/src/controllers/10-business-type-controller.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { - Body, - Controller, - Delete, - Get, - Path, - Post, - Put, - Query, - Request, - Route, - Security, - Tags, -} from "tsoa"; -import { RequestWithUser } from "../interfaces/user"; -import prisma from "../db"; -import { Prisma } from "@prisma/client"; -import { queryOrNot } from "../utils/relation"; -import { notFoundError } from "../utils/error"; - -type BusinessTypePayload = { - name: string; - nameEN: string; -}; - -@Route("api/v1/business-type") -@Tags("Business Type") -export class businessTypeController extends Controller { - @Get() - @Security("keycloak") - async getList( - @Request() req: RequestWithUser, - @Query() query: string = "", - @Query() page: number = 1, - @Query() pageSize: number = 30, - ) { - const where = { - OR: queryOrNot(query, [ - { name: { contains: query, mode: "insensitive" } }, - { nameEN: { contains: query, mode: "insensitive" } }, - ]), - } satisfies Prisma.BusinessTypeWhereInput; - - const [result, total] = await prisma.$transaction([ - prisma.businessType.findMany({ - where, - take: pageSize, - skip: (page - 1) * pageSize, - }), - prisma.businessType.count({ where }), - ]); - - return { result, page, pageSize, total }; - } - - @Post() - @Security("keycloak") - async createBusinessType(@Request() req: RequestWithUser, @Body() body: BusinessTypePayload) { - return await prisma.businessType.create({ - data: { - ...body, - createdByUserId: req.user.sub, - updatedByUserId: req.user.sub, - }, - }); - } - - @Get(":businessTypeId") - @Security("keycloak") - async getBusinessTypeById(@Path() businessTypeId: string) { - return await prisma.businessType.findUnique({ - where: { id: businessTypeId }, - }); - } - - @Put(":businessTypeId") - @Security("keycloak") - async updateBusinessType( - @Request() req: RequestWithUser, - @Path() businessTypeId: string, - @Body() body: BusinessTypePayload, - ) { - return await prisma.$transaction(async (tx) => { - const record = await tx.businessType.findUnique({ - where: { id: businessTypeId }, - }); - - if (!record) throw notFoundError("BusinessType"); - return await tx.businessType.update({ - where: { id: businessTypeId }, - data: { - ...body, - updatedByUserId: req.user.sub, - }, - }); - }); - } - - @Delete(":businessTypeId") - @Security("keycloak") - async deleteBusinessType(@Path() businessTypeId: string) { - return await prisma.$transaction(async (tx) => { - const record = await tx.businessType.findUnique({ - where: { id: businessTypeId }, - }); - - if (!record) throw notFoundError("BusinessType"); - return await tx.businessType.delete({ - where: { id: businessTypeId }, - }); - }); - } -} diff --git a/src/controllers/10-troubleshooting-controller.ts b/src/controllers/10-troubleshooting-controller.ts deleted file mode 100644 index 2c5418a..0000000 --- a/src/controllers/10-troubleshooting-controller.ts +++ /dev/null @@ -1,25 +0,0 @@ -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`)); - } -} diff --git a/src/services/flowaccount.ts b/src/services/flowaccount.ts index 7faf492..730482d 100644 --- a/src/services/flowaccount.ts +++ b/src/services/flowaccount.ts @@ -1,10 +1,6 @@ import prisma from "../db"; import config from "../config.json"; import { CustomerType, PayCondition } from "@prisma/client"; -import { convertTemplate } from "../utils/string-template"; -import { htmlToText } from "html-to-text"; -import { JsonObject } from "@prisma/client/runtime/library"; -import { precisionRound } from "../utils/arithmetic"; if (!process.env.FLOW_ACCOUNT_URL) throw new Error("Require FLOW_ACCOUNT_URL"); if (!process.env.FLOW_ACCOUNT_CLIENT_ID) throw new Error("Require FLOW_ACCOUNT_CLIENT_ID"); @@ -236,29 +232,6 @@ const flowAccount = { installments: true, quotation: { include: { - paySplit: true, - worker: { - select: { - employee: { - select: { - employeePassport: { - select: { - number: true, - }, - orderBy: { - expireDate: "desc", - }, - take: 1, - }, - namePrefix: true, - firstName: true, - lastName: true, - firstNameEN: true, - lastNameEN: true, - }, - }, - }, - }, registeredBranch: { include: { province: true, @@ -289,58 +262,19 @@ const flowAccount = { const quotation = data.quotation; const customer = quotation.customerBranch; - - const summary = { - subTotal: 0, - discountAmount: 0, - vatableAmount: 0, - exemptAmount: 0, - vatAmount: 0, - grandTotal: 0, - }; - - const products = ( + const product = quotation.payCondition === PayCondition.BillFull || quotation.payCondition === PayCondition.Full ? quotation.productServiceList : quotation.productServiceList.filter((lhs) => data.installments.some((rhs) => rhs.no === lhs.installmentNo), - ) - ).map((v) => { - // TODO: Use product's VAT field (not implemented) instead. - const VAT_RATE = VAT_DEFAULT; - - summary.subTotal += - precisionRound(v.pricePerUnit * (1 + (v.vat > 0 ? VAT_RATE : 0))) * v.amount; - summary.discountAmount += v.discount; - - const total = - precisionRound(v.pricePerUnit * (1 + (v.vat > 0 ? VAT_RATE : 0))) * v.amount - - (v.discount ?? 0); - - if (v.vat > 0) { - summary.vatableAmount += precisionRound(total / (1 + VAT_RATE)); - summary.vatAmount += v.vat; - } else { - summary.exemptAmount += total; - } - - summary.grandTotal += total; - - return { - type: ProductAndServiceType.ProductNonInv, - name: v.product.name, - pricePerUnit: precisionRound(v.pricePerUnit), - quantity: v.amount, - discountAmount: v.discount, - vatRate: v.vat === 0 ? 0 : Math.round(VAT_RATE * 100), - total, - }; - }); - + ); const payload = { contactCode: customer.code, - contactName: customer.contactName || "-", + contactName: + (customer.customer.customerType === CustomerType.PERS + ? [customer.firstName, customer.lastName].join(" ").trim() + : customer.registerName) || "-", contactAddress: [ customer.address, !!customer.moo ? "หมู่ " + customer.moo : null, @@ -349,10 +283,11 @@ const flowAccount = { (customer.province?.id === "10" ? "แขวง" : "อำเภอ") + customer.subDistrict?.name, (customer.province?.id === "10" ? "เขต" : "ตำบล") + customer.district?.name, "จังหวัด" + customer.province?.name, + customer.subDistrict?.zipCode, ] .filter(Boolean) .join(" "), - contactTaxId: customer.citizenId || customer.legalPersonNo || "-", + contactTaxId: customer.citizenId || customer.code, contactBranch: (customer.customer.customerType === CustomerType.PERS ? [customer.firstName, customer.lastName].join(" ").trim() @@ -370,35 +305,36 @@ const flowAccount = { isVat: true, useReceiptDeduction: false, - useInlineVat: true, discounPercentage: 0, discountAmount: quotation.totalDiscount, - subTotal: summary.subTotal, - totalAfterDiscount: summary.subTotal - summary.discountAmount, - vatableAmount: summary.vatableAmount, - exemptAmount: summary.exemptAmount, - vatAmount: summary.vatAmount, - grandTotal: summary.grandTotal, + subTotal: + quotation.payCondition === "BillSplitCustom" || quotation.payCondition === "SplitCustom" + ? 0 + : quotation.totalPrice, + totalAfterDiscount: + quotation.payCondition === "BillSplitCustom" || quotation.payCondition === "SplitCustom" + ? 0 + : quotation.finalPrice, + vatAmount: + quotation.payCondition === "BillSplitCustom" || quotation.payCondition === "SplitCustom" + ? 0 + : quotation.vat, + grandTotal: + quotation.payCondition === "BillSplitCustom" || quotation.payCondition === "SplitCustom" + ? data.installments.reduce((a, c) => a + c.amount, 0) + : quotation.finalPrice, - remarks: htmlToText( - convertTemplate(quotation.remark ?? "", { - "quotation-payment": { - paymentType: quotation?.payCondition || "Full", - amount: quotation.finalPrice, - installments: quotation?.paySplit, - }, - "quotation-labor": { - name: quotation.worker.map( - (v, i) => - `${i + 1}. ` + - `${v.employee.employeePassport.length !== 0 ? v.employee.employeePassport[0].number + "_" : ""}${v.employee.namePrefix}. ${v.employee.firstNameEN ? `${v.employee.firstNameEN} ${v.employee.lastNameEN}` : `${v.employee.firstName} ${v.employee.lastName}`} `.toUpperCase(), - ), - }, - }), - ), - items: products, + items: product.map((v) => ({ + type: ProductAndServiceType.ProductNonInv, + name: v.product.name, + pricePerUnit: v.pricePerUnit, + quantity: v.amount, + discountAmount: v.discount, + total: (v.pricePerUnit - (v.discount || 0)) * v.amount + v.vat, + vatRate: v.vat === 0 ? 0 : Math.round(VAT_DEFAULT * 100), + })), }; return await flowAccountAPI.createReceipt(payload, false); @@ -411,219 +347,6 @@ const flowAccount = { } return null; }, - - // flowAccount GET Product list - async getProducts() { - const { token } = await flowAccountAPI.auth(); - - const res = await fetch(api + "/products", { - method: "GET", - headers: { - ["Content-Type"]: `application/json`, - ["Authorization"]: `Bearer ${token}`, - }, - }); - - return { - ok: res.ok, - status: res.status, - body: await res.json(), - }; - }, - - // flowAccount GET Product by id - async getProductsById(recordId: string) { - const { token } = await flowAccountAPI.auth(); - - const res = await fetch(api + `/products/${recordId}`, { - method: "GET", - headers: { - ["Content-Type"]: `application/json`, - ["Authorization"]: `Bearer ${token}`, - }, - }); - - const data = await res.json(); - - return { - ok: res.ok, - status: res.status, - list: data.data.list, - total: data.data.total, - }; - }, - - // flowAccount POST create Product - async createProducts(code: string, body: JsonObject) { - const { token } = await flowAccountAPI.auth(); - - const commonBody = { - productStructureType: null, - type: 3, - name: body.name, - sellDescription: body.detail, - sellVatType: 3, - buyPrice: body.serviceCharge, - buyVatType: body.serviceChargeVatIncluded ? 1 : 3, - buyDescription: body.detail, - }; - - const createProduct = async (name: string, price: any, vatIncluded: boolean) => { - try { - const res = await fetch(`${api}/products`, { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - }, - body: JSON.stringify({ - ...commonBody, - name, - sellPrice: price, - sellVatType: vatIncluded ? 1 : 3, - }), - }); - - if (!res.ok) throw new Error(`HTTP ${res.status}: Failed to create product`); - - const json = await res.json().catch(() => { - throw new Error("Invalid JSON response from FlowAccount API"); - }); - - return json?.data?.list?.[0]?.id ?? null; - } catch (err) { - console.error("createProduct error:", err); - return null; - } - }; - - const deleteProduct = async (id: string) => { - try { - await fetch(`${api}/products/${id}`, { - method: "DELETE", - headers: { Authorization: `Bearer ${token}` }, - }); - } catch (err) { - console.error("Rollback delete failed:", err); - } - }; - - const [sellResult, agentResult] = await Promise.allSettled([ - createProduct(`${code} ${body.name}`, body.price, /true/.test(`${body.vatIncluded}`)), - createProduct( - `${code} ${body.name} (ราคาตัวแทน)`, - body.agentPrice, - /true/.test(`${body.agentPriceVatIncluded}`), - ), - ]); - - const sellId = sellResult.status === "fulfilled" ? sellResult.value : null; - const agentId = agentResult.status === "fulfilled" ? agentResult.value : null; - - // --- validation --- - if (!sellId && !agentId) { - throw new Error("FlowAccountProductError.BOTH_CREATION_FAILED"); - } - if (!sellId && agentId) { - await deleteProduct(agentId); - throw new Error("FlowAccountProductError.SELL_PRICE_CREATION_FAILED"); - } - if (sellId && !agentId) { - await deleteProduct(sellId); - throw new Error("FlowAccountProductError.AGENT_PRICE_CREATION_FAILED"); - } - - return { - ok: true, - status: 200, - data: { - productIdSellPrice: sellId, - productIdAgentPrice: agentId, - }, - }; - }, - - // flowAccount PUT edit Product - async editProducts(sellPriceId: String, agentPriceId: String, body: JsonObject) { - const { token } = await flowAccountAPI.auth(); - - const commonBody = { - productStructureType: null, - type: 3, - name: body.name, - sellDescription: body.detail, - sellVatType: 3, - buyPrice: body.serviceCharge, - buyVatType: body.serviceChargeVatIncluded ? 1 : 3, - buyDescription: body.detail, - }; - - const editProduct = async (id: String, name: String, price: any, vatIncluded: boolean) => { - try { - const res = await fetch(api + `/products/${id}`, { - method: "PUT", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - }, - body: JSON.stringify({ - ...commonBody, - name: name, - sellPrice: price, - sellVatType: vatIncluded ? 1 : 3, - }), - }); - - if (!res.ok) { - throw new Error(`Request failed with status ${res.status} ${res}`); - } - - let json: any = null; - try { - json = await res.json(); - } catch { - throw new Error("Response is not valid JSON"); - } - - return json?.data?.list?.[0]?.id ?? null; - } catch (err) { - console.error("createProduct error:", err); - return null; - } - }; - - await Promise.all([ - editProduct( - sellPriceId, - `${body.code} ${body.name}`, - body.price, - /true/.test(`${body.vatIncluded}`), - ), - editProduct( - agentPriceId, - `${body.code} ${body.name} (ราคาตัวแทน)`, - body.agentPrice, - /true/.test(`${body.agentPriceVatIncluded}`), - ), - ]); - }, - - // flowAccount DELETE Product - async deleteProduct(recordId: string) { - const { token } = await flowAccountAPI.auth(); - - const res = await fetch(api + `/products/${recordId}`, { - method: "DELETE", - headers: { - ["Authorization"]: `Bearer ${token}`, - }, - }); - - return { - ok: res.ok, - status: res.status, - }; - }, }; export default flowAccount; diff --git a/src/services/keycloak.ts b/src/services/keycloak.ts index 494e19e..db2d15d 100644 --- a/src/services/keycloak.ts +++ b/src/services/keycloak.ts @@ -346,64 +346,6 @@ 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, diff --git a/src/services/schedule.ts b/src/services/schedule.ts index dd0591e..bd12bf8 100644 --- a/src/services/schedule.ts +++ b/src/services/schedule.ts @@ -2,7 +2,6 @@ import dayjs from "dayjs"; import { CronJob } from "cron"; import prisma from "../db"; -import { Prisma } from "@prisma/client"; const jobs = [ CronJob.from({ @@ -39,162 +38,6 @@ const jobs = [ .catch((e) => console.error("[ERR]: Update expired quotation status, FAILED.", e)); }, }), - CronJob.from({ - cronTime: "0 0 0 * * *", - runOnInit: true, - onTick: async () => { - const employeeExpireData = await prisma.employee.findMany({ - include: { - employeePassport: { - orderBy: { - expireDate: "desc", - }, - take: 1, - }, - customerBranch: { - include: { - customer: true, - }, - }, - quotationWorker: { - include: { - quotation: true, - }, - orderBy: { - createdAt: "desc", - }, - take: 1, - }, - }, - where: { - employeePassport: { - some: { - expireDate: dayjs().add(90, "day").toDate(), - }, - }, - }, - }); - - await Promise.all( - employeeExpireData.map(async (record) => { - const fullName = `${record.namePrefix}.${record.firstNameEN} ${record.lastNameEN}`; - const expireDate = `${dayjs(record.employeePassport[0].expireDate).format("DD/MM")}/${dayjs(record.employeePassport[0].expireDate).year() + 543}`; - const textDetail = `ลูกจ้างรหัส / code : ${record.code} ชื่อ : ${fullName} หนังสือเดินทางจะหมดอายุในวันที่ ${expireDate}`; - const duplicateText = await prisma.notification.findFirst({ - where: { - detail: textDetail, - }, - }); - - const dataNotification: Prisma.NotificationCreateArgs["data"] = { - title: "หนังสือเดินทางลูกจ้างหมดอายุ / Employee Passport Expire", - detail: textDetail, - }; - - if (record.quotationWorker && record.quotationWorker.length > 0) { - dataNotification.receiverId = record.quotationWorker[0].quotation.updatedByUserId; - dataNotification.registeredBranchId = - record.quotationWorker[0].quotation.registeredBranchId; - } else { - (dataNotification.groupReceiver = { - create: [{ name: "sale" }, { name: "head_of_sale" }], - }), - (dataNotification.registeredBranchId = - record.customerBranch.customer.registeredBranchId); - } - - if (!duplicateText) { - await prisma.notification - .create({ - data: dataNotification, - }) - .then(() => console.log("[INFO]: Create notification employee passport expired, OK.")) - .catch((e) => - console.error("[ERR]: Create notification employee passport expired, FAILED.", e), - ); - } - }), - ); - }, - }), - CronJob.from({ - cronTime: "0 0 0 * * *", - runOnInit: true, - onTick: async () => { - const employeeVisaData = await prisma.employee.findMany({ - include: { - employeeVisa: { - orderBy: { - expireDate: "desc", - }, - take: 1, - }, - customerBranch: { - include: { - customer: true, - }, - }, - quotationWorker: { - include: { - quotation: true, - }, - orderBy: { - createdAt: "desc", - }, - take: 1, - }, - }, - where: { - employeeVisa: { - some: { - expireDate: dayjs().add(90, "day").toDate(), - }, - }, - }, - }); - - await Promise.all( - employeeVisaData.map(async (record) => { - const fullName = `${record.namePrefix}.${record.firstNameEN} ${record.lastNameEN}`; - const expireDate = `${dayjs(record.employeeVisa[0].expireDate).format("DD/MM")}/${dayjs(record.employeeVisa[0].expireDate).year() + 543}`; - const textDetail = `ลูกจ้างรหัส / code : ${record.code} ชื่อ : ${fullName} ข้อมูลการตรวจลงตราจะหมดอายุในวันที่ ${expireDate}`; - const duplicateText = await prisma.notification.findFirst({ - where: { - detail: textDetail, - }, - }); - - const dataNotification: Prisma.NotificationCreateArgs["data"] = { - title: "ข้อมูลการตรวจลงตราลูกจ้างหมดอายุ / Employee Visa Expire", - detail: textDetail, - }; - - if (record.quotationWorker && record.quotationWorker.length > 0) { - dataNotification.receiverId = record.quotationWorker[0].quotation.updatedByUserId; - dataNotification.registeredBranchId = - record.quotationWorker[0].quotation.registeredBranchId; - } else { - (dataNotification.groupReceiver = { - create: [{ name: "sale" }, { name: "head_of_sale" }], - }), - (dataNotification.registeredBranchId = - record.customerBranch.customer.registeredBranchId); - } - - if (!duplicateText) { - await prisma.notification - .create({ - data: dataNotification, - }) - .then(() => console.log("[INFO]: Create notification employee visa expired, OK.")) - .catch((e) => - console.error("[ERR]: Create notification employee visa expired, FAILED.", e), - ); - } - }), - ); - }, - }), ]; export function initSchedule() { diff --git a/src/utils/relation.ts b/src/utils/relation.ts index aebb744..3e96f11 100644 --- a/src/utils/relation.ts +++ b/src/utils/relation.ts @@ -10,35 +10,26 @@ export function connectOrDisconnect(id?: string | null) { export function whereAddressQuery(query: string) { return [ - { 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; + { 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 } } }, + ]; } -export function queryOrNot(query: any, where: T): T | undefined; -export function queryOrNot(query: any, where: T, fallback: U): T | U; -export function queryOrNot(query: any, where: T, fallback?: U) { +export function queryOrNot(query: string | boolean, where: T): T | undefined; +export function queryOrNot(query: string | boolean, where: T, fallback: U): T | U; +export function queryOrNot(query: string | boolean, where: T, fallback?: U) { return !!query ? where : fallback; } - -export function whereDateQuery(startDate: Date | undefined, endDate: Date | undefined) { - return { - createdAt: { - gte: startDate, - lte: endDate, - }, - }; -} diff --git a/src/utils/spreadsheet.ts b/src/utils/spreadsheet.ts deleted file mode 100644 index b04a4f2..0000000 --- a/src/utils/spreadsheet.ts +++ /dev/null @@ -1,105 +0,0 @@ -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( - buffer: Excel.Buffer, - opts?: { header?: boolean; worksheet?: number | string }, - ): Promise { - const workbook = new Excel.Workbook(); - await workbook.xlsx.load(buffer); - const worksheet = workbook.getWorksheet(opts?.worksheet ?? 1); - - if (!worksheet) return []; - - const header: Record = {}; - 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 = {}; - 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; -} diff --git a/src/utils/string-template.ts b/src/utils/string-template.ts deleted file mode 100644 index aaa477e..0000000 --- a/src/utils/string-template.ts +++ /dev/null @@ -1,67 +0,0 @@ -export function formatNumberDecimal(num: number, point: number = 2): string { - return (num || 0).toLocaleString("eng", { - minimumFractionDigits: point, - maximumFractionDigits: point, - }); -} - -const templates = { - "quotation-labor": { - converter: (context?: { name: string[] }) => { - return context?.name.join("
") || ""; - }, - }, - "quotation-payment": { - converter: (context?: { - paymentType: "Full" | "Split" | "SplitCustom" | "BillFull" | "BillSplit" | "BillSplitCustom"; - - amount?: number; - installments?: { - no: number; - amount: number; - }[]; - }) => { - if (context?.paymentType === "Full") { - return [ - "**** เงื่อนไขเพิ่มเติม", - "- เงื่อนไขการชำระเงิน แบบเต็มจำนวน", - `  จำนวน ${formatNumberDecimal(context?.amount || 0, 2)}`, - ].join("
"); - } else { - return [ - "**** เงื่อนไขเพิ่มเติม", - `- เงื่อนไขการชำระเงิน แบบแบ่งจ่าย${context?.paymentType === "SplitCustom" ? " กำหนดเอง " : " "}${context?.installments?.length} งวด`, - ...(context?.installments?.map( - (v) => `  งวดที่ ${v.no} จำนวน ${formatNumberDecimal(v.amount, 2)}`, - ) || []), - ].join("
"); - } - }, - }, -} as const; - -type Template = typeof templates; -type TemplateName = keyof Template; -type TemplateContext = { - [key in TemplateName]?: Parameters[0]; -}; - -export function convertTemplate( - text: string, - context?: TemplateContext, - templateUse?: TemplateName[], -) { - let ret = text; - - for (const [name, template] of Object.entries(templates)) { - if (templateUse && !templateUse.includes(name as TemplateName)) continue; - ret = ret.replace( - new RegExp("\\#\\[" + name.replaceAll("-", "\\-") + "\\]", "g"), - typeof template.converter === "function" - ? template.converter(context?.[name as TemplateName] as any) - : template.converter, - ); - } - - return ret; -} diff --git a/src/utils/thailand-area.ts b/src/utils/thailand-area.ts index 7bcf360..1319e0b 100644 --- a/src/utils/thailand-area.ts +++ b/src/utils/thailand-area.ts @@ -62,90 +62,85 @@ export async function initThailandAreaDatabase() { return result; } - await prisma.$transaction( - async (tx) => { - const meta = { - createdBy: null, - createdAt: new Date(), - updatedBy: null, - updatedAt: new Date(), - }; + await prisma.$transaction(async (tx) => { + const meta = { + createdBy: null, + createdAt: new Date(), + updatedBy: null, + updatedAt: new Date(), + }; - await Promise.all( - splitChunk(province, 1000, async (r) => { - return await tx.$kysely - .insertInto("Province") - .columns(["id", "name", "nameEN", "createdBy", "createdAt", "updatedBy", "updatedAt"]) - .values(r.map((v) => ({ ...v, ...meta }))) - .onConflict((oc) => - oc.column("id").doUpdateSet({ - name: (eb) => eb.ref("excluded.name"), - nameEN: (eb) => eb.ref("excluded.nameEN"), - updatedAt: (eb) => eb.ref("excluded.updatedAt"), - }), - ) - .execute(); - }), - ); + await Promise.all( + splitChunk(province, 1000, async (r) => { + return await tx.$kysely + .insertInto("Province") + .columns(["id", "name", "nameEN", "createdBy", "createdAt", "updatedBy", "updatedAt"]) + .values(r.map((v) => ({ ...v, ...meta }))) + .onConflict((oc) => + oc.column("id").doUpdateSet({ + name: (eb) => eb.ref("excluded.name"), + nameEN: (eb) => eb.ref("excluded.nameEN"), + updatedAt: (eb) => eb.ref("excluded.updatedAt"), + }), + ) + .execute(); + }), + ); - await Promise.all( - splitChunk(district, 2000, async (r) => { - return await tx.$kysely - .insertInto("District") - .columns([ - "id", - "name", - "nameEN", - "provinceId", - "createdBy", - "createdAt", - "updatedBy", - "updatedAt", - ]) - .values(r.map((v) => ({ ...v, ...meta }))) - .onConflict((oc) => - oc.column("id").doUpdateSet({ - name: (eb) => eb.ref("excluded.name"), - nameEN: (eb) => eb.ref("excluded.nameEN"), - provinceId: (eb) => eb.ref("excluded.provinceId"), - updatedAt: (eb) => eb.ref("excluded.updatedAt"), - }), - ) - .execute(); - }), - ); + await Promise.all( + splitChunk(district, 2000, async (r) => { + return await tx.$kysely + .insertInto("District") + .columns([ + "id", + "name", + "nameEN", + "provinceId", + "createdBy", + "createdAt", + "updatedBy", + "updatedAt", + ]) + .values(r.map((v) => ({ ...v, ...meta }))) + .onConflict((oc) => + oc.column("id").doUpdateSet({ + name: (eb) => eb.ref("excluded.name"), + nameEN: (eb) => eb.ref("excluded.nameEN"), + provinceId: (eb) => eb.ref("excluded.provinceId"), + updatedAt: (eb) => eb.ref("excluded.updatedAt"), + }), + ) + .execute(); + }), + ); - await Promise.all( - splitChunk(subDistrict, 1000, async (r) => { - return await tx.$kysely - .insertInto("SubDistrict") - .columns([ - "id", - "name", - "nameEN", - "districtId", - "createdBy", - "createdAt", - "updatedBy", - "updatedAt", - ]) - .values(r.map((v) => ({ ...v, ...meta }))) - .onConflict((oc) => - oc.column("id").doUpdateSet({ - name: (eb) => eb.ref("excluded.name"), - nameEN: (eb) => eb.ref("excluded.nameEN"), - districtId: (eb) => eb.ref("excluded.districtId"), - updatedAt: (eb) => eb.ref("excluded.updatedAt"), - }), - ) - .execute(); - }), - ); - }, - { - timeout: 15_000, - }, - ); + await Promise.all( + splitChunk(subDistrict, 1000, async (r) => { + return await tx.$kysely + .insertInto("SubDistrict") + .columns([ + "id", + "name", + "nameEN", + "districtId", + "createdBy", + "createdAt", + "updatedBy", + "updatedAt", + ]) + .values(r.map((v) => ({ ...v, ...meta }))) + .onConflict((oc) => + oc.column("id").doUpdateSet({ + name: (eb) => eb.ref("excluded.name"), + nameEN: (eb) => eb.ref("excluded.nameEN"), + districtId: (eb) => eb.ref("excluded.districtId"), + updatedAt: (eb) => eb.ref("excluded.updatedAt"), + }), + ) + .execute(); + }), + ); + }); console.log("[INFO]: Sync thailand province, district and subdistrict, OK."); } @@ -175,72 +170,67 @@ export async function initEmploymentOffice() { const list = await prisma.province.findMany(); - await prisma.$transaction( - async (tx) => { - await Promise.all( - list - .map(async (province) => { - if (special[province.id]) { - await tx.employmentOffice.deleteMany({ - where: { provinceId: province.id, district: { none: {} } }, - }); - return await Promise.all( - Object.entries(special[province.id]).map(async ([key, val]) => { - const id = province.id + "-" + key.padStart(2, "0"); - return tx.employmentOffice.upsert({ - where: { id }, - create: { - id, - name: nameSpecial(province.name, +key), - nameEN: nameSpecialEN(province.nameEN, +key), - provinceId: province.id, - district: { - createMany: { - data: val.map((districtId) => ({ districtId })), - skipDuplicates: true, - }, - }, - }, - update: { - id, - name: nameSpecial(province.name, +key), - nameEN: nameSpecialEN(province.nameEN, +key), - provinceId: province.id, - district: { - deleteMany: { districtId: { notIn: val } }, - createMany: { - data: val.map((districtId) => ({ districtId })), - skipDuplicates: true, - }, - }, - }, - }); - }), - ); - } - - return tx.employmentOffice.upsert({ - where: { id: province.id }, - create: { - id: province.id, - name: name(province.name), - nameEN: nameEN(province.nameEN), - provinceId: province.id, - }, - update: { - name: name(province.name), - nameEN: nameEN(province.nameEN), - provinceId: province.id, - }, + await prisma.$transaction(async (tx) => { + await Promise.all( + list + .map(async (province) => { + if (special[province.id]) { + await tx.employmentOffice.deleteMany({ + where: { provinceId: province.id, district: { none: {} } }, }); - }) - .flat(), - ); - }, - { - timeout: 15_000, - }, - ); + return await Promise.all( + Object.entries(special[province.id]).map(async ([key, val]) => { + const id = province.id + "-" + key.padStart(2, "0"); + return tx.employmentOffice.upsert({ + where: { id }, + create: { + id, + name: nameSpecial(province.name, +key), + nameEN: nameSpecialEN(province.nameEN, +key), + provinceId: province.id, + district: { + createMany: { + data: val.map((districtId) => ({ districtId })), + skipDuplicates: true, + }, + }, + }, + update: { + id, + name: nameSpecial(province.name, +key), + nameEN: nameSpecialEN(province.nameEN, +key), + provinceId: province.id, + district: { + deleteMany: { districtId: { notIn: val } }, + createMany: { + data: val.map((districtId) => ({ districtId })), + skipDuplicates: true, + }, + }, + }, + }); + }), + ); + } + + return tx.employmentOffice.upsert({ + where: { id: province.id }, + create: { + id: province.id, + name: name(province.name), + nameEN: nameEN(province.nameEN), + provinceId: province.id, + }, + update: { + name: name(province.name), + nameEN: nameEN(province.nameEN), + provinceId: province.id, + }, + }); + }) + .flat(), + ); + }); console.log("[INFO]: Sync employment office, OK."); } diff --git a/test/branch.test.ts b/test/branch.test.ts deleted file mode 100644 index 25226d5..0000000 --- a/test/branch.test.ts +++ /dev/null @@ -1,323 +0,0 @@ -import { afterAll, beforeAll, describe, expect, it, onTestFailed } from "vitest"; -import { PrismaClient } from "@prisma/client"; - -import { isDateString } from "./lib"; - -const prisma = new PrismaClient({ - datasourceUrl: process.env.TEST_DATABASE_URL || process.env.DATABASE_URL, -}); -const baseUrl = process.env.TEST_BASE_URL || "http://localhost"; -const record: Record = { - code: "CMT", - taxNo: "1052299402851", - name: "Chamomind", - nameEN: "Chamomind", - email: "contact@chamomind.com", - lineId: "@chamomind", - telephoneNo: "0988929248", - contactName: "John", - webUrl: "https://chamomind.com", - latitude: "", - longitude: "", - virtual: false, - permitNo: "1135182804792", - permitIssueDate: "2025-01-01T00:00:00.000Z", - permitExpireDate: "2030-01-01T00:00:00.000Z", - address: "11/3", - addressEN: "11/3", - soi: "1", - soiEN: "1", - moo: "2", - mooEN: "2", - street: "Straight", - streetEN: "Straight", - provinceId: "50", - districtId: "5001", - subDistrictId: "500107", -}; -const recordList: Record[] = []; - -let token: string; - -beforeAll(async () => { - const body = new URLSearchParams(); - - body.append("grant_type", "password"); - body.append("client_id", "app"); - body.append("username", process.env.TEST_USERNAME || ""); - body.append("password", process.env.TEST_PASSWORD || ""); - body.append("scope", "openid"); - - const res = await fetch( - process.env.KC_URL + "/realms/" + process.env.KC_REALM + "/protocol/openid-connect/token", - { - method: "POST", - body: body, - }, - ); - - expect(res.ok).toBe(true); - - await res.json().then((data) => { - token = data["access_token"]; - }); -}); - -afterAll(async () => { - if (!record["id"]) return; - - await prisma.branch.deleteMany({ - where: { id: { in: [record, ...recordList].map((v) => v["id"]) } }, - }); - await prisma.runningNo.deleteMany({ - where: { - key: { in: [record, ...recordList].map((v) => `MAIN_BRANCH_${v["code"].slice(0, -5)}`) }, - }, - }); -}); - -describe("branch management", () => { - it("create branch without required fields", async () => { - const requiredFields = [ - "taxNo", - "name", - "nameEN", - "permitNo", - "telephoneNo", - "address", - "addressEN", - "email", - ]; - onTestFailed(() => console.log("Field:", requiredFields, "is required.")); - - for await (const field of requiredFields) { - const res = await fetch(baseUrl + "/api/v1/branch", { - method: "POST", - headers: { - ["Content-Type"]: "application/json", - ["Authorization"]: "Bearer " + token, - }, - body: JSON.stringify({ ...record, [field]: undefined }), - }); - - if (res.ok) recordList.push(await res.json()); - - expect(res.ok).toBe(false); - expect(res.status).toBe(400); - } - }); - - it("create branch", async () => { - const res = await fetch(baseUrl + "/api/v1/branch", { - method: "POST", - headers: { - ["Content-Type"]: "application/json", - ["Authorization"]: "Bearer " + token, - }, - body: JSON.stringify(record), - }); - if (!res.ok) { - const text = await res.text(); - try { - console.log(JSON.parse(text)); - } catch (e) { - console.log(text); - } - } - - expect(res.ok).toBe(true); - - const data = await res.json(); - - record["id"] = data["id"]; // This field is auto generated - record["code"] = data["code"]; // This field is auto generated - - recordList.push(data); - - expect(data).toMatchObject(record); - }); - - it("get branch list", async () => { - const res = await fetch(baseUrl + "/api/v1/branch", { - method: "GET", - headers: { - ["Authorization"]: "Bearer " + token, - }, - }); - if (!res.ok) { - const text = await res.text(); - try { - console.log(JSON.parse(text)); - } catch (e) { - console.log(text); - } - } - - expect(res.ok).toBe(true); - - const data = await res.json(); - - expect(data).toHaveProperty("result"); - expect(data).toHaveProperty("total"); - expect(data).toHaveProperty("page"); - expect(data).toHaveProperty("pageSize"); - expect(data.result).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(String), - code: expect.any(String), - virtual: expect.any(Boolean), - name: expect.any(String), - nameEN: expect.any(String), - email: expect.any(String), - taxNo: expect.any(String), - telephoneNo: expect.any(String), - latitude: expect.any(String), - longitude: expect.any(String), - contactName: expect.toBeOneOf([expect.any(String), null]), - lineId: expect.toBeOneOf([expect.any(String), null]), - webUrl: expect.toBeOneOf([expect.any(String), null]), - remark: expect.toBeOneOf([expect.any(String), null]), - selectedImage: expect.toBeOneOf([expect.any(String), null]), - - isHeadOffice: expect.any(Boolean), - - permitNo: expect.any(String), - permitIssueDate: expect.toSatisfy(isDateString(true)), - permitExpireDate: expect.toSatisfy(isDateString(true)), - - address: expect.any(String), - addressEN: expect.any(String), - moo: expect.toBeOneOf([expect.any(String), null]), - mooEN: expect.toBeOneOf([expect.any(String), null]), - street: expect.toBeOneOf([expect.any(String), null]), - streetEN: expect.toBeOneOf([expect.any(String), null]), - provinceId: expect.any(String), - province: expect.objectContaining({ - id: expect.any(String), - name: expect.any(String), - nameEN: expect.any(String), - }), - districtId: expect.any(String), - district: expect.objectContaining({ - id: expect.any(String), - name: expect.any(String), - nameEN: expect.any(String), - }), - subDistrictId: expect.any(String), - subDistrict: expect.objectContaining({ - id: expect.any(String), - name: expect.any(String), - nameEN: expect.any(String), - zipCode: expect.any(String), - }), - - status: expect.toBeOneOf(["CREATED", "ACTIVE", "INACTIVE"]), - statusOrder: expect.toBeOneOf([1, 0]), - - createdAt: expect.toSatisfy(isDateString()), - createdByUserId: expect.toBeOneOf([expect.any(String), null]), - createdBy: expect.objectContaining({ - id: expect.any(String), - username: expect.any(String), - firstName: expect.any(String), - lastName: expect.any(String), - firstNameEN: expect.any(String), - lastNameEN: expect.any(String), - }), - updatedAt: expect.toSatisfy(isDateString()), - updatedByUserId: expect.toBeOneOf([expect.any(String), null]), - updatedBy: expect.objectContaining({ - id: expect.any(String), - username: expect.any(String), - firstName: expect.any(String), - lastName: expect.any(String), - firstNameEN: expect.any(String), - lastNameEN: expect.any(String), - }), - - _count: expect.objectContaining({ - branch: expect.any(Number), - }), - }), - ]), - ); - }); - - it("get branch by id", async () => { - const res = await fetch(baseUrl + "/api/v1/branch/" + record["id"], { - method: "GET", - headers: { - ["Authorization"]: "Bearer " + token, - }, - }); - if (!res.ok) { - const text = await res.text(); - try { - console.log(JSON.parse(text)); - } catch (e) { - console.log(text); - } - } - - expect(res.ok).toBe(true); - - const data = await res.json(); - - expect(data).toMatchObject(record); - }); - - it("update branch by id", async () => { - const res = await fetch(baseUrl + "/api/v1/branch/" + record["id"], { - method: "PUT", - headers: { - ["Content-Type"]: "application/json", - ["Authorization"]: "Bearer " + token, - }, - body: JSON.stringify({ name: "Chamomind Intl.", nameEN: "Chamomind Intl." }), - }); - - record["name"] = "Chamomind Intl."; - record["nameEN"] = "Chamomind Intl."; - - expect(res.ok).toBe(true); - - const data = await res.json(); - - expect(data).toMatchObject(record); - }); - - it("delete branch by id", async () => { - const res = await fetch(baseUrl + "/api/v1/branch/" + record["id"], { - method: "DELETE", - headers: { - ["Content-Type"]: "application/json", - ["Authorization"]: "Bearer " + token, - }, - }); - if (!res.ok) { - const text = await res.text(); - try { - console.log(JSON.parse(text)); - } catch (e) { - console.log(text); - } - } - expect(res.ok).toBe(true); - - const data = await res.json(); - - expect(data).toMatchObject(record); - }); - - it("get deleted branch by id", async () => { - const res = await fetch(baseUrl + "/api/v1/branch/" + record["id"], { - method: "GET", - headers: { - ["Authorization"]: "Bearer " + token, - }, - }); - - expect(res.ok).toBe(false); - }); -}); diff --git a/test/lib/index.ts b/test/lib/index.ts deleted file mode 100644 index ed9d771..0000000 --- a/test/lib/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -export function isDateString(nullable: boolean = false): (val: any) => boolean { - return (value: any) => { - try { - if (value) return !!new Date(value); - return nullable; - } catch (_) { - return false; - } - }; -} diff --git a/vite.config.ts b/vite.config.ts deleted file mode 100644 index 77a73cf..0000000 --- a/vite.config.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { defineConfig } from "vitest/config"; - -export default defineConfig({ - test: {}, -});