Compare commits

...

52 Commits

Author SHA1 Message Date
Allan Carr
b0dcd3618e IO-3190 Quick Intake Schedule Event
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2025-04-16 13:00:01 -07:00
Dave Richer
e015d3574a Merged in release/2025-04-11 (pull request #2267)
Release/2025-04-11 into master-AIO - IO-2769, IO-2885, IO-3045, IO-3066, IO-3193, IO-3198, IO-3202
2025-04-12 01:27:08 +00:00
Dave Richer
60140902d4 Merged in feature/IO-3045-Product-Fruits-Tours-Modifications (pull request #2265)
feature/IO-3045-Product-Fruits-Tours-Modifications - Add in roles prop on Product fruits, tie the usage of it to a new db bodyshop var tours_enabled.
2025-04-10 16:28:21 +00:00
Dave Richer
84f41b2c11 feature/IO-3045-Product-Fruits-Tours-Modifications - Add in roles prop on Product fruits, tie the usage of it to a new db bodyshop var tours_enabled. 2025-04-10 12:27:54 -04:00
Dave Richer
282fa787a9 Merged in feature/IO-2769-Job-Totals-Testing (pull request #2263)
feature/IO-2769-Job-Totals-Testing - packages, final update
2025-04-09 16:53:04 +00:00
Dave Richer
037efff81c feature/IO-2769-Job-Totals-Testing - packages, final update 2025-04-09 12:52:23 -04:00
Patrick Fic
e26eb17d09 Merged in feature/IO-3066-ems-parts-order-data (pull request #2262)
IO-3066 Add additional CIECA fields for new partner

Approved-by: Patrick Fic
2025-04-09 16:34:42 +00:00
Patrick Fic
fbea9fde27 IO-3066 Add additional CIECA fields for new partner 2025-04-09 09:33:37 -07:00
Dave Richer
ce7cf6bdbe Merged in feature/IO-2769-Job-Totals-Testing (pull request #2260)
feature/IO-2769-Job-Totals-Testing - updated tests
2025-04-09 15:19:09 +00:00
Dave Richer
2c47e5d852 feature/IO-2769-Job-Totals-Testing - updated tests 2025-04-09 11:18:09 -04:00
Dave Richer
a6f809b20a Merged in feature/IO-2769-Job-Totals-Testing (pull request #2258)
feature/IO-2769-Job-Totals-Testing - non-related
2025-04-08 22:14:52 +00:00
Dave Richer
2bcad68351 feature/IO-2769-Job-Totals-Testing - non-related 2025-04-08 18:14:20 -04:00
Dave Richer
6b1b393804 Merged in feature/IO-2769-Job-Totals-Testing (pull request #2256)
Feature/IO-2769 Job Totals Testing
2025-04-08 22:11:26 +00:00
Dave Richer
c5181d1c5d feature/IO-2769-Job-Totals-Testing - non-related 2025-04-08 18:10:28 -04:00
Dave Richer
e33ff2a45d feature/IO-2769-Job-Totals-Testing - cleanup 2025-04-08 17:04:50 -04:00
Allan Carr
9eb77964db Merged in feature/IO-3202-HasFeatureAccess-Boolean (pull request #2250)
IO-3202 HasFeatureAccess Boolean

Approved-by: Dave Richer
2025-04-08 17:17:50 +00:00
Allan Carr
0a68d2791d IO-3202 HasFeatureAccess Boolean
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2025-04-08 09:51:52 -07:00
Dave Richer
11928d9a7e Merged in feature/IO-2769-Job-Totals-Testing (pull request #2253)
Feature/IO-2769 Job Totals Testing
2025-04-08 16:23:34 +00:00
Dave Richer
c169bb5d5d feature/IO-2769-Job-Totals-Testing - update end point 2025-04-08 12:19:33 -04:00
Dave Richer
3cc4f1c63e feature/IO-2769-Job-Totals-Testing - fix typo 2025-04-08 12:00:43 -04:00
Dave Richer
5237b1d535 Merged in feature/IO-2769-Job-Totals-Testing (pull request #2251)
feature/IO-2769-Job-Totals-Testing
2025-04-08 15:47:09 +00:00
Dave Richer
cd56c50cf9 feature/IO-2769-Job-Totals-Testing 2025-04-08 11:46:16 -04:00
Dave Richer
a18ce18d72 feature/IO-2769-Job-Totals-Testing 2025-04-08 11:42:27 -04:00
Allan Carr
3691d32aaa IO-3202 HasFeatureAccess Boolean
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2025-04-07 17:36:39 -07:00
Dave Richer
5f66488410 release/2025-04-11 - Remove unused constant from server.js 2025-04-07 13:06:47 -04:00
Dave Richer
d1be7f6e09 Merged in test-AIO (pull request #2249)
Test AIO
2025-04-07 17:04:04 +00:00
Dave Richer
44f02f28a6 Merged in release/2025-04-11 (pull request #2248)
release/2025-04-11 - Add Ivana to Usage Report
2025-04-07 17:03:00 +00:00
Dave Richer
6d33622b4e release/2025-04-11 - Add Ivana to Usage Report 2025-04-07 13:01:23 -04:00
Dave Richer
f8b8e23ef4 Merged in release/2025-04-11 (pull request #2247)
release/2025-04-11 - Fix Packages
2025-04-07 16:12:42 +00:00
Dave Richer
db09d09428 release/2025-04-11 - Fix Packages 2025-04-07 12:11:53 -04:00
Dave Richer
451820a67c Merged in release/2025-04-11 (pull request #2246)
Release/2025 04 11
2025-04-04 18:19:46 +00:00
Dave Richer
ba0ce5027e Merged in feature/IO-2769-Job-Totals-Testing (pull request #2245)
feature/IO-2769-Job-Totals-testing: Setup testing method for job totals

Approved-by: Patrick Fic
2025-04-04 18:18:51 +00:00
Dave Richer
f777d26cc1 feature/IO-2769-Job-Totals-testing: Allow for both american and canadian capture + tests 2025-04-04 14:15:30 -04:00
Dave Richer
1463037878 feature/IO-2769-Job-Totals-testing: Allow for both american and canadian capture + tests 2025-04-04 13:54:53 -04:00
Dave Richer
7ddec0bb0f feature/IO-2769-Job-Totals-testing: Allow for both american and canadian capture + tests 2025-04-04 13:49:21 -04:00
Dave Richer
51c2d3351a feature/IO-2769-Job-Totals-testing: Allow for both american and canadian capture + tests 2025-04-04 13:47:38 -04:00
Dave Richer
8323fa6696 feature/IO-2769-Job-Totals-testing: Allow for both american and canadian capture + tests 2025-04-04 13:45:45 -04:00
Dave Richer
27a3932c08 feature/IO-2769-Job-Totals-testing: Allow for both american and canadian capture + tests 2025-04-04 13:43:19 -04:00
Dave Richer
add88659a4 feature/IO-2769-Job-Totals-testing: Setup testing method for job totals 2025-04-04 13:23:33 -04:00
Dave Richer
320ad065d0 feature/IO-2769-Job-Totals-testing: Setup testing method for job totals 2025-04-04 13:19:44 -04:00
Dave Richer
a9bc51949a Merged in release/2025-04-11 (pull request #2244)
feature/IO-3198-Seperate-Socket-Provider-useSocket
2025-04-03 17:12:19 +00:00
Dave Richer
39d1397221 Merged in feature/IO-3198-Seperate-Socket-Provider-useSocket (pull request #2243)
feature/IO-3198-Seperate-Socket-Provider-useSocket
2025-04-03 17:11:55 +00:00
Dave Richer
f3e2a83bab Merged in release/2025-04-11 (pull request #2242)
IO-3193 Reconciliation Zero Part Price or Qty
2025-04-03 16:37:40 +00:00
Dave Richer
c03d45b3fc Merged in release/2025-04-11 (pull request #2240)
Release/2025 04 11
2025-04-02 18:15:36 +00:00
Dave Richer
24d47ae1c5 Merged in release/2025-03-28 (pull request #2237)
Release/2025 03 28
2025-04-02 15:39:16 +00:00
Dave Richer
1b8be56c15 Merged in release/2025-03-28 (pull request #2234)
Release/2025-03-28 into test-AIO - IO-3181
2025-03-28 16:18:08 +00:00
Dave Richer
2b26db78eb Merged in release/2025-03-28 (pull request #2232)
IO-3187 Admin Enhancements
2025-03-27 14:04:43 +00:00
Dave Richer
c2d96922c8 Merged in release/2025-03-28 (pull request #2230)
IO-3176 IntelliPay Payment Mapping
2025-03-26 18:24:26 +00:00
Dave Richer
70b4ec7948 Merged in release/2025-03-28 (pull request #2228)
release/2025-03-28 - Modify vite config
2025-03-25 20:53:36 +00:00
Dave Richer
a3ec364034 Merged in release/2025-03-28 (pull request #2227)
release/2025-03-28 - Modify vite config
2025-03-25 20:48:25 +00:00
Dave Richer
e1728b275b Merged in release/2025-03-28 (pull request #2226)
release/2025-03-28 - Package locks
2025-03-25 20:38:36 +00:00
Dave Richer
10d55df461 Merged in release/2025-03-28 (pull request #2224)
Release/2025 03 28
2025-03-25 19:07:28 +00:00
34 changed files with 933 additions and 348 deletions

2
.gitignore vendored
View File

@@ -127,4 +127,6 @@ vitest-report*/
vitest-coverage/
*.vitest.log
test-output.txt
server/job/test/fixtures
.github

View File

@@ -56,4 +56,5 @@ COPY . .
EXPOSE 4000 9229
# Start the application
CMD ["nodemon", "--legacy-watch", "--inspect=0.0.0.0:9229", "server.js"]
RUN echo "Starting the application..."
CMD ["nodemon", "--ignore", "./server/job/test/fixtures", "--legacy-watch", "--inspect=0.0.0.0:9229", "server.js"]

235
client/package-lock.json generated
View File

@@ -10,7 +10,7 @@
"hasInstallScript": true,
"dependencies": {
"@ant-design/pro-layout": "^7.22.4",
"@apollo/client": "^3.13.5",
"@apollo/client": "^3.13.6",
"@emotion/is-prop-valid": "^1.3.1",
"@fingerprintjs/fingerprintjs": "^4.6.1",
"@firebase/analytics": "^0.10.12",
@@ -21,9 +21,9 @@
"@jsreport/browser-client": "^3.1.0",
"@reduxjs/toolkit": "^2.6.1",
"@sentry/cli": "^2.43.0",
"@sentry/react": "^9.10.1",
"@sentry/vite-plugin": "^3.2.4",
"@splitsoftware/splitio-react": "^2.1.0",
"@sentry/react": "^9.11.0",
"@sentry/vite-plugin": "^3.3.1",
"@splitsoftware/splitio-react": "^2.1.1",
"@tanem/react-nprogress": "^5.0.53",
"antd": "^5.24.6",
"apollo-link-logger": "^2.0.1",
@@ -58,7 +58,7 @@
"react-dom": "^18.3.1",
"react-drag-listview": "^2.0.0",
"react-grid-gallery": "^1.0.1",
"react-grid-layout": "1.3.4",
"react-grid-layout": "^1.3.4",
"react-i18next": "^15.4.1",
"react-icons": "^5.5.0",
"react-image-lightbox": "^5.1.4",
@@ -70,17 +70,17 @@
"react-resizable": "^3.0.5",
"react-router-dom": "^6.30.0",
"react-sticky": "^6.0.3",
"react-virtuoso": "^4.12.6",
"recharts": "^2.15.0",
"react-virtuoso": "^4.12.5",
"recharts": "^2.15.2",
"redux": "^5.0.1",
"redux-actions": "^3.0.3",
"redux-persist": "^6.0.0",
"redux-saga": "^1.3.0",
"redux-state-sync": "^3.1.4",
"reselect": "^5.1.1",
"sass": "^1.86.1",
"sass": "^1.86.3",
"socket.io-client": "^4.8.1",
"styled-components": "^6.1.16",
"styled-components": "^6.1.17",
"subscriptions-transport-ws": "^0.11.0",
"use-memo-one": "^1.1.3",
"vite-plugin-ejs": "^1.7.0",
@@ -90,22 +90,22 @@
"@ant-design/icons": "^6.0.0",
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@babel/preset-react": "^7.26.3",
"@dotenvx/dotenvx": "^1.39.0",
"@dotenvx/dotenvx": "^1.39.1",
"@emotion/babel-plugin": "^11.13.5",
"@emotion/react": "^11.14.0",
"@eslint/js": "^9.23.0",
"@eslint/js": "^9.24.0",
"@playwright/test": "^1.51.1",
"@sentry/webpack-plugin": "^3.2.4",
"@sentry/webpack-plugin": "^3.3.1",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.2.0",
"@testing-library/react": "^16.3.0",
"@vitejs/plugin-react": "^4.3.4",
"browserslist": "^4.24.4",
"browserslist-to-esbuild": "^2.1.1",
"chalk": "^5.4.1",
"eslint": "^8.57.1",
"eslint-config-react-app": "^7.0.1",
"eslint-plugin-react": "^7.37.4",
"eslint-plugin-react": "^7.37.5",
"globals": "^15.15.0",
"jsdom": "^26.0.0",
"memfs": "^4.17.0",
@@ -114,7 +114,7 @@
"react-error-overlay": "^6.1.0",
"redux-logger": "^3.0.6",
"source-map-explorer": "^2.5.3",
"vite": "^6.2.4",
"vite": "^6.2.5",
"vite-plugin-babel": "^1.3.0",
"vite-plugin-eslint": "^1.8.1",
"vite-plugin-node-polyfills": "^0.23.0",
@@ -396,9 +396,9 @@
}
},
"node_modules/@apollo/client": {
"version": "3.13.5",
"resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.13.5.tgz",
"integrity": "sha512-ceHa1lApLAiGmUur4V+G/CrjwVwHYujfB7U5HM++poCgHpfGn6eet8YGM93fgeWjYX85SaqwdZbQk18IVwhRHg==",
"version": "3.13.6",
"resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.13.6.tgz",
"integrity": "sha512-G6A8uNb13V/Tv4TJQOs5PnxuE5Rf5D2dMnBQcg9mng1Eo4YBecwFEJ0L022mraq/dLB0jD5tiAESOD2bTyJ6gg==",
"license": "MIT",
"dependencies": {
"@graphql-typed-document-node/core": "^3.1.1",
@@ -2566,9 +2566,9 @@
}
},
"node_modules/@dotenvx/dotenvx": {
"version": "1.39.0",
"resolved": "https://registry.npmjs.org/@dotenvx/dotenvx/-/dotenvx-1.39.0.tgz",
"integrity": "sha512-qGfDpL/3S17MQYXpR3HkBS5xNQ7wiFlqLdpr+iIQzv17aMRcSlgL4EjMIsYFZ540Dq17J+y5FVElA1AkVoXiUA==",
"version": "1.39.1",
"resolved": "https://registry.npmjs.org/@dotenvx/dotenvx/-/dotenvx-1.39.1.tgz",
"integrity": "sha512-FIjEB/s3TSQBYnYA64GPkXJrOR6w5J52SSnl6gSoq1tp+4r9zLjaAsf65AgDv5emA4ypm90gVWv1XX0/bfHA/A==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
@@ -2891,9 +2891,9 @@
}
},
"node_modules/@eslint/js": {
"version": "9.23.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.23.0.tgz",
"integrity": "sha512-35MJ8vCPU0ZMxo7zfev2pypqTwWTofFZO6m4KAtdoFhRpLJUpHTZZ+KB3C7Hb1d7bULYwO4lJXGCi5Se+8OMbw==",
"version": "9.24.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.24.0.tgz",
"integrity": "sha512-uIY/y3z0uvOGX8cp1C2fiC4+ZmBhp6yZWkojtHL1YEMnRt1Y63HB9TM17proGEmeG7HeUY+UP36F0aknKYTpYA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -4178,88 +4178,88 @@
"license": "MIT"
},
"node_modules/@sentry-internal/browser-utils": {
"version": "9.10.1",
"resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-9.10.1.tgz",
"integrity": "sha512-O/ibpHbKfpG+xtZuEzbLNtLcbanRcDYGxT+QbslVItmcS9GjMSwvMpp1jnD9Y7/LIFtv7O1gJZ9Hrz///lLprw==",
"version": "9.11.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-9.11.0.tgz",
"integrity": "sha512-XS71kRf7lw5St/Jc9G2Viy1cKgqGoPHqUAykXEtFt38JVXdf1TY/dSbKv/PAgNqMvC1xvdTsN0HF/81o7DNUEA==",
"license": "MIT",
"dependencies": {
"@sentry/core": "9.10.1"
"@sentry/core": "9.11.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry-internal/feedback": {
"version": "9.10.1",
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-9.10.1.tgz",
"integrity": "sha512-DM32eAzRvXk36iGBWtlLZA88QzOFBODd+kbz55X4Py+1bDNdRc3Vl6214uuAr7iweHcOQy1rIvmAeO8Xusp7tQ==",
"version": "9.11.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-9.11.0.tgz",
"integrity": "sha512-50KiRmrF1Ldr+KoRawqcCYVk7TAVP8K/I81Jk9YWwlp1+Pu1ArpYDmTNCLXTgoyiyO38aHefKGZJX6AKFuSsUQ==",
"license": "MIT",
"dependencies": {
"@sentry/core": "9.10.1"
"@sentry/core": "9.11.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry-internal/replay": {
"version": "9.10.1",
"resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-9.10.1.tgz",
"integrity": "sha512-nqG33NwojtteL8e3Qg/SOu0BsTJ9R7AjpmQIlOpFGL007nzKgcJHOngewd7FEHyB+F3iOI0MoI9iEWhRFEGRLw==",
"version": "9.11.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-9.11.0.tgz",
"integrity": "sha512-0k24h58O/2VQw1dwT/zQiWvUzLNQxpxbrVN/MYPT7czSEhI+1bX8fxMHXZORl2JqhetImMXzxH3XkuHQPEqQMg==",
"license": "MIT",
"dependencies": {
"@sentry-internal/browser-utils": "9.10.1",
"@sentry/core": "9.10.1"
"@sentry-internal/browser-utils": "9.11.0",
"@sentry/core": "9.11.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry-internal/replay-canvas": {
"version": "9.10.1",
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-9.10.1.tgz",
"integrity": "sha512-fxrpqElqdsAQrzVly0V/XaljhAlwwMk+iGyf+wZeK6RwEPVxtoxXVfx7fEEtPn+gortqQR09N/zH179hefjuaw==",
"version": "9.11.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-9.11.0.tgz",
"integrity": "sha512-ZcRg8TWfF0ucjK2i+4TY/blRNJ7YKrgMpx19pFj6eCOJ1K8geSkAFPIfDHcQEwIU1ZTN+HiCwx0JvTI9YZxjfg==",
"license": "MIT",
"dependencies": {
"@sentry-internal/replay": "9.10.1",
"@sentry/core": "9.10.1"
"@sentry-internal/replay": "9.11.0",
"@sentry/core": "9.11.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry/babel-plugin-component-annotate": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/@sentry/babel-plugin-component-annotate/-/babel-plugin-component-annotate-3.2.4.tgz",
"integrity": "sha512-yBzRn3GEUSv1RPtE4xB4LnuH74ZxtdoRJ5cmQ9i6mzlmGDxlrnKuvem5++AolZTE9oJqAD3Tx2rd1PqmpWnLoA==",
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/@sentry/babel-plugin-component-annotate/-/babel-plugin-component-annotate-3.3.1.tgz",
"integrity": "sha512-5GOxGT7lZN+I8A7Vp0rWY+726FDKEw8HnFiebe51rQrMbfGfCu2Aw9uSM0nT9OG6xhV6WvGccIcCszTPs4fUZQ==",
"license": "MIT",
"engines": {
"node": ">= 14"
}
},
"node_modules/@sentry/browser": {
"version": "9.10.1",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-9.10.1.tgz",
"integrity": "sha512-9RWjcyskhnDK2Q6LntFR90EqZD5+DXcXNqeTlE+mpVf65y7wz+9SIuVjAMP7qiDBwfxNbmTxiVCXeCuQnnATsQ==",
"version": "9.11.0",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-9.11.0.tgz",
"integrity": "sha512-DSDj8wQJoiLqqOcntl+7phjd8l8KN9A0vaV7mZNHWbrHU3MVwXqTyLyERRLC6wi0t7F5kqczqa3xLmKjK/fMZg==",
"license": "MIT",
"dependencies": {
"@sentry-internal/browser-utils": "9.10.1",
"@sentry-internal/feedback": "9.10.1",
"@sentry-internal/replay": "9.10.1",
"@sentry-internal/replay-canvas": "9.10.1",
"@sentry/core": "9.10.1"
"@sentry-internal/browser-utils": "9.11.0",
"@sentry-internal/feedback": "9.11.0",
"@sentry-internal/replay": "9.11.0",
"@sentry-internal/replay-canvas": "9.11.0",
"@sentry/core": "9.11.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry/bundler-plugin-core": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/@sentry/bundler-plugin-core/-/bundler-plugin-core-3.2.4.tgz",
"integrity": "sha512-YMj9XW5W2JA89EeweE7CPKLDz245LBsI1JhCmqpt/bjSvmsSIAAPsLYnvIJBS3LQFm0OhtG8NB54PTi96dAcMA==",
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/@sentry/bundler-plugin-core/-/bundler-plugin-core-3.3.1.tgz",
"integrity": "sha512-Dd6xaWb293j9otEJ1yJqG2Ra6zB49OPzMNdIkdP8wdY+S9UFQE5PyKTyredmPY7hqCc005OrUQZolIIo9Zl13A==",
"license": "MIT",
"dependencies": {
"@babel/core": "^7.18.5",
"@sentry/babel-plugin-component-annotate": "3.2.4",
"@sentry/babel-plugin-component-annotate": "3.3.1",
"@sentry/cli": "2.42.2",
"dotenv": "^16.3.1",
"find-up": "^5.0.0",
@@ -4619,22 +4619,22 @@
}
},
"node_modules/@sentry/core": {
"version": "9.10.1",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-9.10.1.tgz",
"integrity": "sha512-TE2zZV3Od4131mZNgFo2Mv4aKU8FXxL0s96yqRvmV+8AU57mJoycMXBnmNSYfWuDICbPJTVAp+3bYMXwX7N5YA==",
"version": "9.11.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-9.11.0.tgz",
"integrity": "sha512-qfb4ahGZubbrNh1MnbEqyHFp87rIwQIZapyQLCaYpudXrP1biEpLOV3mMDvDJWCdX460hoOwQ3SkwipV3We/7w==",
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry/react": {
"version": "9.10.1",
"resolved": "https://registry.npmjs.org/@sentry/react/-/react-9.10.1.tgz",
"integrity": "sha512-DYBs3F+F2elWEhWvp3HmBmORhAlTBbY0KsRj+Lt2mOSEfiz8WWrS3Ibe+9QmErVdjQZy68ic9Yt84MHL/rlmkQ==",
"version": "9.11.0",
"resolved": "https://registry.npmjs.org/@sentry/react/-/react-9.11.0.tgz",
"integrity": "sha512-sH/3KnDsLxBFRoxPyIpab7OewkfStdZQQwgpfv8R0yDKpGg4lU7KdTccryFvWL123UpHC7ydPWjdcfC8YV/EPQ==",
"license": "MIT",
"dependencies": {
"@sentry/browser": "9.10.1",
"@sentry/core": "9.10.1",
"@sentry/browser": "9.11.0",
"@sentry/core": "9.11.0",
"hoist-non-react-statics": "^3.3.2"
},
"engines": {
@@ -4645,12 +4645,12 @@
}
},
"node_modules/@sentry/vite-plugin": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/@sentry/vite-plugin/-/vite-plugin-3.2.4.tgz",
"integrity": "sha512-ZRn5TLlq5xtwKOqaWP+XqS1PYVfbBCgsbMk7wW2Ly6EgF9wYePvtLqKgYnE3hwPg2LpBnRPR2ti1ohlUkR+wXA==",
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/@sentry/vite-plugin/-/vite-plugin-3.3.1.tgz",
"integrity": "sha512-eIIIHqVOTO0m7+3aTg//gVi11XNpKi4G0xA45hjz46UmRiToVfqgBH7Dsn1qRrDxa7YPYCdREQkyGEINlElT2A==",
"license": "MIT",
"dependencies": {
"@sentry/bundler-plugin-core": "3.2.4",
"@sentry/bundler-plugin-core": "3.3.1",
"unplugin": "1.0.1"
},
"engines": {
@@ -4658,13 +4658,13 @@
}
},
"node_modules/@sentry/webpack-plugin": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/@sentry/webpack-plugin/-/webpack-plugin-3.2.4.tgz",
"integrity": "sha512-LCuNu5LXPSCq2BNke1zvEW8CXL4SPBsCjYexAx51PZ6Lp87VxWcCxGqXhr37MGpYwY10A1r31/XOe69iXHJjGA==",
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/@sentry/webpack-plugin/-/webpack-plugin-3.3.1.tgz",
"integrity": "sha512-AFRnGNUnlIvq3M+ADdfWb+DIXWKK6yYEkVPAyOppkjO+cL/19gjXMdvAwv+CMFts28YCFKF8Kr3pamUiCmwodA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@sentry/bundler-plugin-core": "3.2.4",
"@sentry/bundler-plugin-core": "3.3.1",
"unplugin": "1.0.1",
"uuid": "^9.0.0"
},
@@ -4718,9 +4718,9 @@
}
},
"node_modules/@splitsoftware/splitio-react": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@splitsoftware/splitio-react/-/splitio-react-2.1.0.tgz",
"integrity": "sha512-iAGXl/qadHVFUQA/+asX8UGwDPpNi6WCKhNIzLZ6NSvt38+M8Bpc3CMnkYNEXsNsz1J+C26ICsMZ067YQ96k6g==",
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@splitsoftware/splitio-react/-/splitio-react-2.1.1.tgz",
"integrity": "sha512-cUMyIdsgzDEFgUZxoV/PyjQR0OXt+Ffqqjh2LVcADsVDpTGUf95ydEVYaszZRVoYYj+hMw9xMw6Yfr0b+uejIQ==",
"license": "Apache-2.0",
"dependencies": {
"@splitsoftware/splitio": "11.2.0",
@@ -4865,9 +4865,9 @@
}
},
"node_modules/@testing-library/react": {
"version": "16.2.0",
"resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.2.0.tgz",
"integrity": "sha512-2cSskAvA1QNtKc8Y9VJQRv0tm3hLVgxRGDB+KYhIaPQJ1I+RHbhIXcM+zClKXzMes/wshsMVzf4B9vS4IZpqDQ==",
"version": "16.3.0",
"resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.0.tgz",
"integrity": "sha512-kFSyxiEDwv1WLl2fgsq6pPBbw5aWKrsY2/noi1Id0TK0UParSF62oFQFGHXIyaG4pp2tEub/Zlel+fjjZILDsw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -6770,9 +6770,9 @@
}
},
"node_modules/call-bind-apply-helpers": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz",
"integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -6784,14 +6784,14 @@
}
},
"node_modules/call-bound": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz",
"integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==",
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
"get-intrinsic": "^1.2.6"
"call-bind-apply-helpers": "^1.0.2",
"get-intrinsic": "^1.3.0"
},
"engines": {
"node": ">= 0.4"
@@ -8671,9 +8671,9 @@
}
},
"node_modules/eslint-plugin-react": {
"version": "7.37.4",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.4.tgz",
"integrity": "sha512-BGP0jRmfYyvOyvMoRX/uoUeW+GqNj9y16bPQzqAHf3AYII/tDs+jMN0dBVkl88/OZwNGwrVFxE7riHsXVfy/LQ==",
"version": "7.37.5",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz",
"integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -8687,7 +8687,7 @@
"hasown": "^2.0.2",
"jsx-ast-utils": "^2.4.1 || ^3.0.0",
"minimatch": "^3.1.2",
"object.entries": "^1.1.8",
"object.entries": "^1.1.9",
"object.fromentries": "^2.0.8",
"object.values": "^1.2.1",
"prop-types": "^15.8.1",
@@ -9403,18 +9403,18 @@
}
},
"node_modules/get-intrinsic": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz",
"integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==",
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
"call-bind-apply-helpers": "^1.0.2",
"es-define-property": "^1.0.1",
"es-errors": "^1.3.0",
"es-object-atoms": "^1.0.0",
"es-object-atoms": "^1.1.1",
"function-bind": "^1.1.2",
"get-proto": "^1.0.0",
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"has-symbols": "^1.1.0",
"hasown": "^2.0.2",
@@ -12486,15 +12486,16 @@
}
},
"node_modules/object.entries": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz",
"integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==",
"version": "1.1.9",
"resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz",
"integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.7",
"call-bind": "^1.0.8",
"call-bound": "^1.0.4",
"define-properties": "^1.2.1",
"es-object-atoms": "^1.0.0"
"es-object-atoms": "^1.1.1"
},
"engines": {
"node": ">= 0.4"
@@ -14374,9 +14375,9 @@
}
},
"node_modules/react-virtuoso": {
"version": "4.12.6",
"resolved": "https://registry.npmjs.org/react-virtuoso/-/react-virtuoso-4.12.6.tgz",
"integrity": "sha512-bfvS6aCL1ehXmq39KRiz/vxznGUbtA27I5I24TYCe1DhMf84O3aVNCIwrSjYQjkJGJGzY46ihdN8WkYlemuhMQ==",
"version": "4.12.5",
"resolved": "https://registry.npmjs.org/react-virtuoso/-/react-virtuoso-4.12.5.tgz",
"integrity": "sha512-YeCbRRsC9CLf0buD0Rct7WsDbzf+yBU1wGbo05/XjbcN2nJuhgh040m3y3+6HVogTZxEqVm45ac9Fpae4/MxRQ==",
"license": "MIT",
"peerDependencies": {
"react": ">=16 || >=17 || >= 18 || >= 19",
@@ -14421,9 +14422,9 @@
}
},
"node_modules/recharts": {
"version": "2.15.1",
"resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.1.tgz",
"integrity": "sha512-v8PUTUlyiDe56qUj82w/EDVuzEFXwEHp9/xOowGAZwfLjB9uAy3GllQVIYMWF6nU+qibx85WF75zD7AjqoT54Q==",
"version": "2.15.2",
"resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.2.tgz",
"integrity": "sha512-xv9lVztv3ingk7V3Jf05wfAZbM9Q2umJzu5t/cfnAK7LUslNrGT7LPBr74G+ok8kSCeFMaePmWMg0rcYOnczTw==",
"license": "MIT",
"dependencies": {
"clsx": "^2.0.0",
@@ -15070,9 +15071,9 @@
"license": "MIT"
},
"node_modules/sass": {
"version": "1.86.1",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.86.1.tgz",
"integrity": "sha512-Yaok4XELL1L9Im/ZUClKu//D2OP1rOljKj0Gf34a+GzLbMveOzL7CfqYo+JUa5Xt1nhTCW+OcKp/FtR7/iqj1w==",
"version": "1.86.3",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.86.3.tgz",
"integrity": "sha512-iGtg8kus4GrsGLRDLRBRHY9dNVA78ZaS7xr01cWnS7PEMQyFtTqBiyCrfpTYTZXRWM94akzckYjh8oADfFNTzw==",
"license": "MIT",
"dependencies": {
"chokidar": "^4.0.0",
@@ -15945,9 +15946,9 @@
}
},
"node_modules/styled-components": {
"version": "6.1.16",
"resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.16.tgz",
"integrity": "sha512-KpWB6ORAWGmbWM10cDJfEV6sXc/uVkkkQV3SLwTNQ/E/PqWgNHIoMSLh1Lnk2FkB9+JHK7uuMq1i+9ArxDD7iQ==",
"version": "6.1.17",
"resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.17.tgz",
"integrity": "sha512-97D7DwWanI7nN24v0D4SvbfjLE9656umNSJZkBkDIWL37aZqG/wRQ+Y9pWtXyBIM/NSfcBzHLErEsqHmJNSVUg==",
"license": "MIT",
"dependencies": {
"@emotion/is-prop-valid": "1.2.2",
@@ -17118,9 +17119,9 @@
}
},
"node_modules/vite": {
"version": "6.2.4",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.2.4.tgz",
"integrity": "sha512-veHMSew8CcRzhL5o8ONjy8gkfmFJAd5Ac16oxBUjlwgX3Gq2Wqr+qNC3TjPIpy7TPV/KporLga5GT9HqdrCizw==",
"version": "6.2.5",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.2.5.tgz",
"integrity": "sha512-j023J/hCAa4pRIUH6J9HemwYfjB5llR2Ps0CWeikOtdR8+pAURAk0DoJC5/mm9kd+UgdnIy7d6HE4EAvlYhPhA==",
"dev": true,
"license": "MIT",
"dependencies": {

View File

@@ -9,7 +9,7 @@
"proxy": "http://localhost:4000",
"dependencies": {
"@ant-design/pro-layout": "^7.22.4",
"@apollo/client": "^3.13.5",
"@apollo/client": "^3.13.6",
"@emotion/is-prop-valid": "^1.3.1",
"@fingerprintjs/fingerprintjs": "^4.6.1",
"@firebase/analytics": "^0.10.12",
@@ -20,9 +20,9 @@
"@jsreport/browser-client": "^3.1.0",
"@reduxjs/toolkit": "^2.6.1",
"@sentry/cli": "^2.43.0",
"@sentry/react": "^9.10.1",
"@sentry/vite-plugin": "^3.2.4",
"@splitsoftware/splitio-react": "^2.1.0",
"@sentry/react": "^9.11.0",
"@sentry/vite-plugin": "^3.3.1",
"@splitsoftware/splitio-react": "^2.1.1",
"@tanem/react-nprogress": "^5.0.53",
"antd": "^5.24.6",
"apollo-link-logger": "^2.0.1",
@@ -57,7 +57,7 @@
"react-dom": "^18.3.1",
"react-drag-listview": "^2.0.0",
"react-grid-gallery": "^1.0.1",
"react-grid-layout": "1.3.4",
"react-grid-layout": "^1.3.4",
"react-i18next": "^15.4.1",
"react-icons": "^5.5.0",
"react-image-lightbox": "^5.1.4",
@@ -69,17 +69,17 @@
"react-resizable": "^3.0.5",
"react-router-dom": "^6.30.0",
"react-sticky": "^6.0.3",
"react-virtuoso": "^4.12.6",
"recharts": "^2.15.0",
"react-virtuoso": "^4.12.5",
"recharts": "^2.15.2",
"redux": "^5.0.1",
"redux-actions": "^3.0.3",
"redux-persist": "^6.0.0",
"redux-saga": "^1.3.0",
"redux-state-sync": "^3.1.4",
"reselect": "^5.1.1",
"sass": "^1.86.1",
"sass": "^1.86.3",
"socket.io-client": "^4.8.1",
"styled-components": "^6.1.16",
"styled-components": "^6.1.17",
"subscriptions-transport-ws": "^0.11.0",
"use-memo-one": "^1.1.3",
"vite-plugin-ejs": "^1.7.0",
@@ -130,22 +130,22 @@
"@ant-design/icons": "^6.0.0",
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@babel/preset-react": "^7.26.3",
"@dotenvx/dotenvx": "^1.39.0",
"@dotenvx/dotenvx": "^1.39.1",
"@emotion/babel-plugin": "^11.13.5",
"@emotion/react": "^11.14.0",
"@eslint/js": "^9.23.0",
"@eslint/js": "^9.24.0",
"@playwright/test": "^1.51.1",
"@sentry/webpack-plugin": "^3.2.4",
"@sentry/webpack-plugin": "^3.3.1",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.2.0",
"@testing-library/react": "^16.3.0",
"@vitejs/plugin-react": "^4.3.4",
"browserslist": "^4.24.4",
"browserslist-to-esbuild": "^2.1.1",
"chalk": "^5.4.1",
"eslint": "^8.57.1",
"eslint-config-react-app": "^7.0.1",
"eslint-plugin-react": "^7.37.4",
"eslint-plugin-react": "^7.37.5",
"globals": "^15.15.0",
"jsdom": "^26.0.0",
"memfs": "^4.17.0",
@@ -154,7 +154,7 @@
"react-error-overlay": "^6.1.0",
"redux-logger": "^3.0.6",
"source-map-explorer": "^2.5.3",
"vite": "^6.2.4",
"vite": "^6.2.5",
"vite-plugin-babel": "^1.3.0",
"vite-plugin-eslint": "^1.8.1",
"vite-plugin-node-polyfills": "^0.23.0",

View File

@@ -142,11 +142,10 @@ export function App({ bodyshop, checkUserSession, currentUser, online, setOnline
>
<ProductFruitsWrapper
currentUser={currentUser}
workspaceCode={InstanceRenderMgr({
imex: null,
rome: "9BkbEseqNqxw8jUH"
})}
bodyshop={bodyshop}
workspaceCode={bodyshop?.tours_enabled ? "9BkbEseqNqxw8jUH" : ""}
/>
<NotificationProvider>
<Routes>
<Route

View File

@@ -1,8 +1,16 @@
import React from "react";
import { ProductFruits } from "react-product-fruits";
import PropTypes from "prop-types";
import { ProductFruits } from "react-product-fruits";
import dayjs from "dayjs";
const ProductFruitsWrapper = React.memo(({ currentUser, bodyshop, workspaceCode }) => {
const featureProps = bodyshop?.features
? Object.entries(bodyshop.features).reduce((acc, [key, value]) => {
acc[key] = value === true || (typeof value === "string" && dayjs(value).isAfter(dayjs()));
return acc;
}, {})
: {};
const ProductFruitsWrapper = React.memo(({ currentUser, workspaceCode }) => {
return (
workspaceCode &&
currentUser?.authorized === true &&
@@ -14,7 +22,8 @@ const ProductFruitsWrapper = React.memo(({ currentUser, workspaceCode }) => {
language="en"
user={{
email: currentUser.email,
username: currentUser.email
username: currentUser.email,
props: featureProps
}}
/>
)
@@ -28,5 +37,6 @@ ProductFruitsWrapper.propTypes = {
authorized: PropTypes.bool,
email: PropTypes.string
}),
workspaceCode: PropTypes.string
workspaceCode: PropTypes.string,
bodyshop: PropTypes.object
};

View File

@@ -20,6 +20,7 @@ function FeatureWrapper({
children,
upsellComponent,
bypass,
// eslint-disable-next-line no-unused-vars
...restProps
}) {
const { t } = useTranslation();
@@ -78,7 +79,11 @@ export function HasFeatureAccess({ featureName, bodyshop, bypass, debug = false
}
return true;
}
return bodyshop?.features?.allAccess || dayjs(bodyshop?.features[featureName]).isAfter(dayjs());
return (
bodyshop?.features?.allAccess ||
bodyshop?.features?.[featureName] ||
dayjs(bodyshop?.features[featureName]).isAfter(dayjs())
);
}
export default connect(mapStateToProps, null)(FeatureWrapper);

View File

@@ -1,5 +1,5 @@
import { AlertFilled } from "@ant-design/icons";
import { useMutation } from "@apollo/client";
import { useLazyQuery, useMutation } from "@apollo/client";
import { Button, Divider, Dropdown, Form, Input, Popover, Select, Space } from "antd";
import parsePhoneNumber from "libphonenumber-js";
import queryString from "query-string";
@@ -8,24 +8,30 @@ import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { Link, useLocation, useNavigate } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
import { useSocket } from "../../contexts/SocketIO/useSocket.js";
import { UPDATE_APPOINTMENT } from "../../graphql/appointments.queries";
import { GET_JOB_BY_PK_QUICK_INTAKE, JOB_PRODUCTION_TOGGLE } from "../../graphql/jobs.queries";
import { insertAuditTrail } from "../../redux/application/application.actions";
import { openChatByPhone, setMessage } from "../../redux/messaging/messaging.actions";
import { setModalContext } from "../../redux/modals/modals.actions";
import { selectBodyshop } from "../../redux/user/user.selectors";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { DateTimeFormatterFunction } from "../../utils/DateFormatter";
import dayjs from "../../utils/day";
import { GenerateDocument } from "../../utils/RenderTemplate";
import { TemplateList } from "../../utils/TemplateConstants";
import ChatOpenButton from "../chat-open-button/chat-open-button.component";
import DataLabel from "../data-label/data-label.component";
import FormDateTimePickerComponent from "../form-date-time-picker/form-date-time-picker.component";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
import ProductionListColumnComment from "../production-list-columns/production-list-columns.comment.component";
import ScheduleManualEvent from "../schedule-manual-event/schedule-manual-event.component";
import { HasFeatureAccess } from "./../feature-wrapper/feature-wrapper.component";
import ScheduleAtChange from "./job-at-change.component";
import ScheduleEventColor from "./schedule-event.color.component";
import ScheduleEventNote from "./schedule-event.note.component";
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop
@@ -33,7 +39,8 @@ const mapStateToProps = createStructuredSelector({
const mapDispatchToProps = (dispatch) => ({
setScheduleContext: (context) => dispatch(setModalContext({ context: context, modal: "schedule" })),
openChatByPhone: (phone) => dispatch(openChatByPhone(phone)),
setMessage: (text) => dispatch(setMessage(text))
setMessage: (text) => dispatch(setMessage(text)),
insertAuditTrail: ({ jobid, operation }) => dispatch(insertAuditTrail({ jobid, operation }))
});
export function ScheduleEventComponent({
@@ -43,16 +50,36 @@ export function ScheduleEventComponent({
event,
refetch,
handleCancel,
setScheduleContext
setScheduleContext,
insertAuditTrail
}) {
const { t } = useTranslation();
const [open, setOpen] = useState(false);
const history = useNavigate();
const searchParams = queryString.parse(useLocation().search);
const [updateAppointment] = useMutation(UPDATE_APPOINTMENT);
const [mutationUpdateJob] = useMutation(JOB_PRODUCTION_TOGGLE);
const [title, setTitle] = useState(event.title);
const { socket } = useSocket();
const notification = useNotification();
const [form] = Form.useForm();
const [popOverVisible, setPopOverVisible] = useState(false);
const [getJobDetails] = useLazyQuery(GET_JOB_BY_PK_QUICK_INTAKE, {
variables: { id: event.job.id },
onCompleted: (data) => {
if (data?.jobs_by_pk) {
form.setFieldsValue({
actual_in: data.jobs_by_pk.actual_in ? data.jobs_by_pk.actual_in : dayjs(),
scheduled_completion: data.jobs_by_pk.scheduled_completion,
actual_completion: data.jobs_by_pk.actual_completion,
scheduled_delivery: data.jobs_by_pk.scheduled_delivery,
actual_delivery: data.jobs_by_pk.actual_delivery
});
}
},
fetchPolicy: "network-only"
});
const blockContent = (
<Space direction="vertical" wrap>
@@ -89,6 +116,74 @@ export function ScheduleEventComponent({
</Space>
);
const handleConvert = async (values) => {
const res = await mutationUpdateJob({
variables: {
jobId: event.job.id,
job: {
...values,
status: bodyshop.md_ro_statuses.default_arrived,
inproduction: true
}
}
});
if (!res.errors) {
notification["success"]({
message: t("jobs.successes.converted")
});
insertAuditTrail({
jobid: event.job.id,
operation: AuditTrailMapping.jobintake(
res.data.update_jobs.returning[0].status,
DateTimeFormatterFunction(values.scheduled_completion)
)
});
setPopOverVisible(false);
refetch();
}
};
const popMenu = (
<div onClick={(e) => e.stopPropagation()}>
<Form layout="vertical" form={form} onFinish={handleConvert}>
<Form.Item
name={["actual_in"]}
label={t("jobs.fields.actual_in")}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
>
<FormDateTimePickerComponent disabled={event.ro_number} />
</Form.Item>
<Form.Item
name={["scheduled_completion"]}
label={t("jobs.fields.scheduled_completion")}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
>
<FormDateTimePickerComponent disabled={event.ro_number} />
</Form.Item>
<Form.Item name={["scheduled_delivery"]} label={t("jobs.fields.scheduled_delivery")}>
<FormDateTimePickerComponent disabled={event.ro_number} />
</Form.Item>
<Space wrap>
<Button type="primary" onClick={() => form.submit()}>
{t("general.actions.save")}
</Button>
</Space>
</Form>
</div>
);
const popoverContent = (
<div style={{ maxWidth: "40vw" }}>
{!event.isintake ? (
@@ -294,7 +389,7 @@ export function ScheduleEventComponent({
) : (
<ScheduleManualEvent event={event} />
)}
{event.isintake ? (
{event.isintake && HasFeatureAccess({ featureName: "checklist", bodyshop }) ? (
<Link
to={{
pathname: `/manage/jobs/${event.job && event.job.id}/intake`,
@@ -303,7 +398,21 @@ export function ScheduleEventComponent({
>
<Button disabled={event.arrived}>{t("appointments.actions.intake")}</Button>
</Link>
) : null}
) : (
<Popover //open={open}
content={popMenu}
open={popOverVisible}
onOpenChange={setPopOverVisible}
onClick={(e) => {
getJobDetails();
e.stopPropagation();
}}
getPopupContainer={(trigger) => trigger.parentNode}
trigger="click"
>
<Button disabled={event.arrived}>{t("jobs.actions.intake_quick")}</Button>
</Popover>
)}
</Space>
</div>
);

View File

@@ -133,6 +133,16 @@ export function JobsDetailHeaderActions({
const { socket } = useSocket();
const notification = useNotification();
const isDevEnv = import.meta.env.DEV;
const isProdEnv = import.meta.env.PROD;
const userEmail = currentUser?.email || "";
const devEmails = ["imex.dev", "rome.dev"];
const prodEmails = ["imex.prod", "rome.prod", "imex.test", "rome.test"];
const hasValidEmail = (emails) => emails.some((email) => userEmail.endsWith(email));
const canSubmitForTesting = (isDevEnv && hasValidEmail(devEmails)) || (isProdEnv && hasValidEmail(prodEmails));
const {
treatments: { ImEXPay }
} = useSplitTreatments({
@@ -171,7 +181,7 @@ export function JobsDetailHeaderActions({
{ defaultOpenStatus: bodyshop.md_ro_statuses.default_imported },
(newJobId) => {
history(`/manage/jobs/${newJobId}`);
notification["success"]({
notification.success({
message: t("jobs.successes.duplicated")
});
},
@@ -181,7 +191,7 @@ export function JobsDetailHeaderActions({
const handleDuplicateConfirm = () =>
DuplicateJob(client, job.id, { defaultOpenStatus: bodyshop.md_ro_statuses.default_imported }, (newJobId) => {
history(`/manage/jobs/${newJobId}`);
notification["success"]({
notification.success({
message: t("jobs.successes.duplicated")
});
});
@@ -217,13 +227,13 @@ export function JobsDetailHeaderActions({
const result = await deleteJob({ variables: { id: job.id } });
if (!result.errors) {
notification["success"]({
notification.success({
message: t("jobs.successes.delete")
});
//go back to jobs list.
history(`/manage/`);
} else {
notification["error"]({
notification.error({
message: t("jobs.errors.deleted", {
error: JSON.stringify(result.errors)
})
@@ -275,9 +285,9 @@ export function JobsDetailHeaderActions({
});
if (!result.errors) {
notification["success"]({ message: t("csi.successes.created") });
notification.success({ message: t("csi.successes.created") });
} else {
notification["error"]({
notification.error({
message: t("csi.errors.creating", {
message: JSON.stringify(result.errors)
})
@@ -316,7 +326,7 @@ export function JobsDetailHeaderActions({
`${window.location.protocol}//${window.location.host}/csi/${result.data.insert_csi.returning[0].id}`
);
} else {
notification["error"]({
notification.error({
message: t("messaging.error.invalidphone")
});
}
@@ -328,7 +338,7 @@ export function JobsDetailHeaderActions({
);
}
} else {
notification["error"]({
notification.error({
message: t("csi.errors.notconfigured")
});
}
@@ -358,7 +368,7 @@ export function JobsDetailHeaderActions({
});
setMessage(`${window.location.protocol}//${window.location.host}/csi/${job.csiinvites[0].id}`);
} else {
notification["error"]({
notification.error({
message: t("messaging.error.invalidphone")
});
}
@@ -398,7 +408,7 @@ export function JobsDetailHeaderActions({
});
if (!result.errors) {
notification["success"]({
notification.success({
message: t("jobs.successes.voided")
});
insertAuditTrail({
@@ -409,7 +419,7 @@ export function JobsDetailHeaderActions({
//go back to jobs list.
history(`/manage/`);
} else {
notification["error"]({
notification.error({
message: t("jobs.errors.voiding", {
error: JSON.stringify(result.errors)
})
@@ -442,7 +452,7 @@ export function JobsDetailHeaderActions({
console.log("handle -> XML", QbXmlResponse);
} catch (error) {
console.log("Error getting QBXML from Server.", error);
notification["error"]({
notification.error({
message: t("jobs.errors.exporting", {
error: "Unable to retrieve QBXML. " + JSON.stringify(error.message)
})
@@ -460,7 +470,7 @@ export function JobsDetailHeaderActions({
});
} catch (error) {
console.log("Error connecting to quickbooks or partner.", error);
notification["error"]({
notification.error({
message: t("jobs.errors.exporting-partner")
});
@@ -556,7 +566,7 @@ export function JobsDetailHeaderActions({
}
});
if (!jobUpdate.errors) {
notification["success"]({
notification.success({
message: t("appointments.successes.canceled")
});
insertAuditTrail({
@@ -931,11 +941,11 @@ export function JobsDetailHeaderActions({
});
if (!result.errors) {
notification["success"]({
notification.success({
message: t("jobs.successes.partsqueue")
});
} else {
notification["error"]({
notification.error({
message: t("jobs.errors.saving", {
error: JSON.stringify(result.errors)
})
@@ -1111,6 +1121,27 @@ export function JobsDetailHeaderActions({
});
}
if (canSubmitForTesting) {
menuItems.push({
key: "submitfortesting",
id: "job-actions-submitfortesting",
label: t("menus.jobsactions.submit-for-testing"),
onClick: async () => {
try {
await axios.post("/job/totals-recorder", { id: job.id });
notification.success({
message: t("general.messages.submit-for-testing")
});
} catch (err) {
console.error(`Error submitting job for testing: ${err?.message}`);
notification.error({
message: t("general.errors.submit-for-testing-error")
});
}
}
});
}
const menu = {
items: menuItems,
key: "popovermenu"

View File

@@ -57,6 +57,7 @@ export const QUERY_BODYSHOP = gql`
logo_img_path
md_ro_statuses
md_order_statuses
tours_enabled
md_functionality_toggles
shopname
state
@@ -186,6 +187,7 @@ export const UPDATE_SHOP = gql`
phone
federal_tax_id
id
tours_enabled
insurance_vendor_id
logo_img_path
md_ro_statuses

View File

@@ -78,6 +78,9 @@ export const QUERY_PARTS_ORDER_OEC = gql`
}
ro_number
clm_no
cieca_stl
cieca_ttl
cieca_pfl
asgn_no
asgn_date
state_tax_rate
@@ -164,6 +167,7 @@ export const QUERY_PARTS_ORDER_OEC = gql`
loss_desc
loss_of_use
loss_type
materials
ownr_addr1
ownr_addr2
ownr_city

View File

@@ -1220,7 +1220,8 @@
"errors": {
"fcm": "You must allow notification permissions to have real time messaging. Click to try again.",
"notfound": "No record was found.",
"sizelimit": "The selected items exceed the size limit."
"sizelimit": "The selected items exceed the size limit.",
"submit-for-testing": "Error submitting Job for testing."
},
"itemtypes": {
"contract": "CC Contract",
@@ -1322,7 +1323,8 @@
"partnernotrunning": "{{app}} has detected that the partner is not running. Please ensure it is running to enable full functionality.",
"rbacunauth": "You are not authorized to view this content. Please reach out to your shop manager to change your access level.",
"unsavedchanges": "You have unsaved changes.",
"unsavedchangespopup": "You have unsaved changes. Are you sure you want to leave?"
"unsavedchangespopup": "You have unsaved changes. Are you sure you want to leave?",
"submit-for-testing": "Submitted Job for testing successfully."
},
"validation": {
"dateRangeExceeded": "The date range has been exceeded.",
@@ -2314,7 +2316,8 @@
"duplicate": "Duplicate this Job",
"duplicatenolines": "Duplicate this Job without Repair Data",
"newcccontract": "Create Courtesy Car Contract",
"void": "Void Job"
"void": "Void Job",
"submit-for-testing": "Submit for Testing"
},
"jobsdetail": {
"claimdetail": "Claim Details",

View File

@@ -1220,7 +1220,8 @@
"errors": {
"fcm": "",
"notfound": "",
"sizelimit": ""
"sizelimit": "",
"submit-for-testing": ""
},
"itemtypes": {
"contract": "",
@@ -1322,7 +1323,8 @@
"partnernotrunning": "",
"rbacunauth": "",
"unsavedchanges": "Usted tiene cambios no guardados.",
"unsavedchangespopup": ""
"unsavedchangespopup": "",
"submit-for-testing": ""
},
"validation": {
"dateRangeExceeded": "",
@@ -2314,7 +2316,8 @@
"duplicate": "",
"duplicatenolines": "",
"newcccontract": "",
"void": ""
"void": "",
"submit-for-testing": ""
},
"jobsdetail": {
"claimdetail": "Detalles de la reclamación",

View File

@@ -1220,7 +1220,8 @@
"errors": {
"fcm": "",
"notfound": "",
"sizelimit": ""
"sizelimit": "",
"submit-for-testing": ""
},
"itemtypes": {
"contract": "",
@@ -1322,7 +1323,9 @@
"partnernotrunning": "",
"rbacunauth": "",
"unsavedchanges": "Vous avez des changements non enregistrés.",
"unsavedchangespopup": ""
"unsavedchangespopup": "",
"submit-for-testing": ""
},
"validation": {
"dateRangeExceeded": "",
@@ -2314,7 +2317,8 @@
"duplicate": "",
"duplicatenolines": "",
"newcccontract": "",
"void": ""
"void": "",
"submit-for-testing": ""
},
"jobsdetail": {
"claimdetail": "Détails de la réclamation",

View File

@@ -15,8 +15,8 @@ const AuditTrailMapping = {
jobchecklist: (type, inproduction, status) =>
i18n.t("audit_trail.messages.jobchecklist", { type, inproduction, status }),
jobconverted: (ro_number) => i18n.t("audit_trail.messages.jobconverted", { ro_number }),
jobintake: (status, email, scheduled_completion) =>
i18n.t("audit_trail.messages.jobintake", { status, email, scheduled_completion }),
jobintake: (status, scheduled_completion) =>
i18n.t("audit_trail.messages.jobintake", { status, scheduled_completion }),
jobdelivery: (status, email, actual_completion) =>
i18n.t("audit_trail.messages.jobdelivery", { status, email, actual_completion }),
jobexported: () => i18n.t("audit_trail.messages.jobexported"),

View File

@@ -117,6 +117,7 @@ services:
aws --endpoint-url=http://localstack:4566 secretsmanager create-secret --name CHATTER_PRIVATE_KEY --secret-string file:///tmp/certs/io-ftp-test.key
aws --endpoint-url=http://localstack:4566 logs create-log-group --log-group-name development --region ca-central-1
aws --endpoint-url=http://localstack:4566 s3api create-bucket --bucket imex-large-log --create-bucket-configuration LocationConstraint=ca-central-1
aws --endpoint-url=http://localstack:4566 s3api create-bucket --bucket imex-job-totals --create-bucket-configuration LocationConstraint=ca-central-1
"
# Node App: The Main IMEX API
node-app:

View File

@@ -0,0 +1,77 @@
const fs = require("fs");
const path = require("path");
const logger = require("./server/utils/logger"); // Assuming same logger utility
const s3Client = require("./server/utils/s3"); // Using the S3 client utilities with LocalStack support
// Set bucket name for development with LocalStack
const S3_BUCKET_NAME = "imex-job-totals";
// Set fixtures directory path
const FIXTURES_DIR = path.join(__dirname, "server", "job", "test", "fixtures", "job-totals");
const ensureFixturesDirectory = () => {
if (!fs.existsSync(FIXTURES_DIR)) {
fs.mkdirSync(FIXTURES_DIR, { recursive: true });
logger.log(`Created fixtures directory: ${FIXTURES_DIR}`, "info");
}
};
const downloadJsonFiles = async (userInfo = { email: "system" }) => {
logger.log(`Starting download of JSON files from bucket: ${S3_BUCKET_NAME}`, "debug", userInfo.email);
try {
ensureFixturesDirectory();
const contents = await s3Client.listFilesInS3Bucket(S3_BUCKET_NAME);
if (!contents.length) {
logger.log("No files found in bucket", "info", userInfo.email);
return;
}
logger.log(`Found ${contents.length} files in bucket`, "info", userInfo.email);
for (const item of contents) {
if (!item.Key.endsWith(".json")) {
logger.log(`Skipping non-JSON file: ${item.Key}`, "debug", userInfo.email);
continue;
}
logger.log(`Downloading: ${item.Key}`, "debug", userInfo.email);
const fileData = await s3Client.downloadFileFromS3({
bucketName: S3_BUCKET_NAME,
key: item.Key
});
const fileContent = await fileData.transformToString();
const fileName = path.basename(item.Key);
const filePath = path.join(FIXTURES_DIR, fileName);
fs.writeFileSync(filePath, fileContent);
logger.log(`Saved: ${filePath}`, "info", userInfo.email);
}
logger.log("Download completed successfully", "info", userInfo.email);
} catch (error) {
logger.log("Failed to download JSON files", "error", userInfo.email, null, {
error: error?.message,
stack: error?.stack
});
throw error; // Re-throw to trigger process exit with error code
}
};
// Run the download if script is executed directly
if (require.main === module) {
(async () => {
try {
await downloadJsonFiles();
console.log("Script completed successfully");
process.exit(0); // Explicitly exit with success code
} catch (error) {
console.error("Fatal error downloading files:", error);
process.exit(1); // Explicitly exit with error code
}
})();
}
module.exports = downloadJsonFiles;

View File

@@ -965,6 +965,7 @@
- insurance_vendor_id
- intakechecklist
- intellipay_config
- intellipay_merchant_id
- jc_hourly_rates
- jobsizelimit
- last_name_first
@@ -1023,6 +1024,7 @@
- template_header
- textid
- timezone
- tours_enabled
- tt_allow_post_to_invoiced
- tt_enforce_hours_for_tech_console
- updated_at

View File

@@ -0,0 +1,4 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- alter table "public"."bodyshops" add column "tours_enabled" boolean
-- not null default 'true';

View File

@@ -0,0 +1,2 @@
alter table "public"."bodyshops" add column "tours_enabled" boolean
not null default 'true';

293
package-lock.json generated
View File

@@ -9,14 +9,14 @@
"version": "0.2.0",
"license": "UNLICENSED",
"dependencies": {
"@aws-sdk/client-cloudwatch-logs": "^3.777.0",
"@aws-sdk/client-elasticache": "^3.777.0",
"@aws-sdk/client-s3": "^3.779.0",
"@aws-sdk/client-secrets-manager": "^3.777.0",
"@aws-sdk/client-ses": "^3.777.0",
"@aws-sdk/credential-provider-node": "^3.777.0",
"@aws-sdk/lib-storage": "^3.779.0",
"@aws-sdk/s3-request-presigner": "^3.779.0",
"@aws-sdk/client-cloudwatch-logs": "^3.782.0",
"@aws-sdk/client-elasticache": "^3.782.0",
"@aws-sdk/client-s3": "^3.782.0",
"@aws-sdk/client-secrets-manager": "^3.782.0",
"@aws-sdk/client-ses": "^3.782.0",
"@aws-sdk/credential-provider-node": "^3.782.0",
"@aws-sdk/lib-storage": "^3.782.0",
"@aws-sdk/s3-request-presigner": "^3.782.0",
"@opensearch-project/opensearch": "^2.13.0",
"@socket.io/admin-ui": "^0.5.1",
"@socket.io/redis-adapter": "^8.3.0",
@@ -26,7 +26,7 @@
"bee-queue": "^1.7.1",
"better-queue": "^3.8.12",
"bluebird": "^3.7.2",
"bullmq": "^5.45.2",
"bullmq": "^5.48.0",
"chart.js": "^4.4.8",
"cloudinary": "^2.6.0",
"compression": "^1.8.0",
@@ -62,7 +62,7 @@
"socket.io": "^4.8.1",
"socket.io-adapter": "^2.5.5",
"ssh2-sftp-client": "^11.0.0",
"twilio": "^5.5.1",
"twilio": "^5.5.2",
"uuid": "^11.1.0",
"winston": "^3.17.0",
"winston-cloudwatch": "^6.3.0",
@@ -70,10 +70,10 @@
"xmlbuilder2": "^3.1.1"
},
"devDependencies": {
"@eslint/js": "^9.23.0",
"@eslint/js": "^9.24.0",
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
"eslint": "^9.23.0",
"eslint-plugin-react": "^7.37.4",
"eslint": "^9.24.0",
"eslint-plugin-react": "^7.37.5",
"globals": "^15.15.0",
"mock-require": "^3.0.3",
"p-limit": "^3.1.0",
@@ -290,24 +290,24 @@
}
},
"node_modules/@aws-sdk/client-cloudwatch-logs": {
"version": "3.777.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudwatch-logs/-/client-cloudwatch-logs-3.777.0.tgz",
"integrity": "sha512-ebrO1ZlgSKEYERegcKnyjC0VkvLnxDm2HES78N54MiMQCfFCUJ3W6xx2aoKVSVWaUrGUaY13Cd67h/X0RhuU6g==",
"version": "3.782.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudwatch-logs/-/client-cloudwatch-logs-3.782.0.tgz",
"integrity": "sha512-hUyMYWebb1HRCSK9jynWRQfNJoRhPaScvbePTPkNJybrVAo+7q2D5/nFP6burroRSWfYEaJXRNgr1besLjZZBA==",
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/sha256-browser": "5.2.0",
"@aws-crypto/sha256-js": "5.2.0",
"@aws-sdk/core": "3.775.0",
"@aws-sdk/credential-provider-node": "3.777.0",
"@aws-sdk/credential-provider-node": "3.782.0",
"@aws-sdk/middleware-host-header": "3.775.0",
"@aws-sdk/middleware-logger": "3.775.0",
"@aws-sdk/middleware-recursion-detection": "3.775.0",
"@aws-sdk/middleware-user-agent": "3.775.0",
"@aws-sdk/middleware-user-agent": "3.782.0",
"@aws-sdk/region-config-resolver": "3.775.0",
"@aws-sdk/types": "3.775.0",
"@aws-sdk/util-endpoints": "3.775.0",
"@aws-sdk/util-endpoints": "3.782.0",
"@aws-sdk/util-user-agent-browser": "3.775.0",
"@aws-sdk/util-user-agent-node": "3.775.0",
"@aws-sdk/util-user-agent-node": "3.782.0",
"@smithy/config-resolver": "^4.1.0",
"@smithy/core": "^3.2.0",
"@smithy/eventstream-serde-browser": "^4.0.2",
@@ -358,24 +358,24 @@
}
},
"node_modules/@aws-sdk/client-elasticache": {
"version": "3.777.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/client-elasticache/-/client-elasticache-3.777.0.tgz",
"integrity": "sha512-6MzXEyUwVIxJqNQh4rvSE32OweJtG9PYdp3UxXfoiuslJnuHgPxWMRpvJIkF/hLeAjfQf4cPii5pBYrfHDbz+g==",
"version": "3.782.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/client-elasticache/-/client-elasticache-3.782.0.tgz",
"integrity": "sha512-brN4paoCUMtGrt4rm23B0/9V6jdKzlc/630u8AJtTeeKCHLMQhzl4O1TJKh0jPvEs2xXt4uNLquKpIxKPQcMVQ==",
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/sha256-browser": "5.2.0",
"@aws-crypto/sha256-js": "5.2.0",
"@aws-sdk/core": "3.775.0",
"@aws-sdk/credential-provider-node": "3.777.0",
"@aws-sdk/credential-provider-node": "3.782.0",
"@aws-sdk/middleware-host-header": "3.775.0",
"@aws-sdk/middleware-logger": "3.775.0",
"@aws-sdk/middleware-recursion-detection": "3.775.0",
"@aws-sdk/middleware-user-agent": "3.775.0",
"@aws-sdk/middleware-user-agent": "3.782.0",
"@aws-sdk/region-config-resolver": "3.775.0",
"@aws-sdk/types": "3.775.0",
"@aws-sdk/util-endpoints": "3.775.0",
"@aws-sdk/util-endpoints": "3.782.0",
"@aws-sdk/util-user-agent-browser": "3.775.0",
"@aws-sdk/util-user-agent-node": "3.775.0",
"@aws-sdk/util-user-agent-node": "3.782.0",
"@smithy/config-resolver": "^4.1.0",
"@smithy/core": "^3.2.0",
"@smithy/fetch-http-handler": "^5.0.2",
@@ -409,16 +409,16 @@
}
},
"node_modules/@aws-sdk/client-s3": {
"version": "3.779.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.779.0.tgz",
"integrity": "sha512-Lagz+ersQaLNYkpOU9V12PYspT//lGvhPXlKU3OXDj3whDchdqUdtRKY8rmV+jli4KXe+udx/hj2yqrFRfKGvQ==",
"version": "3.782.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.782.0.tgz",
"integrity": "sha512-V6JR2JAGYQY7J8wk5un5n/ja2nfCUyyoRCF8Du8JL91NGI8i41Mdr/TzuOGwTgFl6RSXb/ge1K1jk30OH4MugQ==",
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/sha1-browser": "5.2.0",
"@aws-crypto/sha256-browser": "5.2.0",
"@aws-crypto/sha256-js": "5.2.0",
"@aws-sdk/core": "3.775.0",
"@aws-sdk/credential-provider-node": "3.777.0",
"@aws-sdk/credential-provider-node": "3.782.0",
"@aws-sdk/middleware-bucket-endpoint": "3.775.0",
"@aws-sdk/middleware-expect-continue": "3.775.0",
"@aws-sdk/middleware-flexible-checksums": "3.775.0",
@@ -428,13 +428,13 @@
"@aws-sdk/middleware-recursion-detection": "3.775.0",
"@aws-sdk/middleware-sdk-s3": "3.775.0",
"@aws-sdk/middleware-ssec": "3.775.0",
"@aws-sdk/middleware-user-agent": "3.775.0",
"@aws-sdk/middleware-user-agent": "3.782.0",
"@aws-sdk/region-config-resolver": "3.775.0",
"@aws-sdk/signature-v4-multi-region": "3.775.0",
"@aws-sdk/types": "3.775.0",
"@aws-sdk/util-endpoints": "3.775.0",
"@aws-sdk/util-endpoints": "3.782.0",
"@aws-sdk/util-user-agent-browser": "3.775.0",
"@aws-sdk/util-user-agent-node": "3.775.0",
"@aws-sdk/util-user-agent-node": "3.782.0",
"@aws-sdk/xml-builder": "3.775.0",
"@smithy/config-resolver": "^4.1.0",
"@smithy/core": "^3.2.0",
@@ -476,24 +476,24 @@
}
},
"node_modules/@aws-sdk/client-secrets-manager": {
"version": "3.777.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/client-secrets-manager/-/client-secrets-manager-3.777.0.tgz",
"integrity": "sha512-HqBGQPFUZMTOkQJB6JLv7Jopfz+cBP4spzjpBlZ/JeJShMAXw9To2mxi22jU5qGGWPGH5y4tVXnw4aVf2TOPhQ==",
"version": "3.782.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/client-secrets-manager/-/client-secrets-manager-3.782.0.tgz",
"integrity": "sha512-j2n8717Q7HeQgyXjdiUwuE0Pk80nOaDacWvEmmMr2w+DYXLvdXrOThbyy3jItt5XQw8mhaC8KZ4RfK6dqUlwGA==",
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/sha256-browser": "5.2.0",
"@aws-crypto/sha256-js": "5.2.0",
"@aws-sdk/core": "3.775.0",
"@aws-sdk/credential-provider-node": "3.777.0",
"@aws-sdk/credential-provider-node": "3.782.0",
"@aws-sdk/middleware-host-header": "3.775.0",
"@aws-sdk/middleware-logger": "3.775.0",
"@aws-sdk/middleware-recursion-detection": "3.775.0",
"@aws-sdk/middleware-user-agent": "3.775.0",
"@aws-sdk/middleware-user-agent": "3.782.0",
"@aws-sdk/region-config-resolver": "3.775.0",
"@aws-sdk/types": "3.775.0",
"@aws-sdk/util-endpoints": "3.775.0",
"@aws-sdk/util-endpoints": "3.782.0",
"@aws-sdk/util-user-agent-browser": "3.775.0",
"@aws-sdk/util-user-agent-node": "3.775.0",
"@aws-sdk/util-user-agent-node": "3.782.0",
"@smithy/config-resolver": "^4.1.0",
"@smithy/core": "^3.2.0",
"@smithy/fetch-http-handler": "^5.0.2",
@@ -541,24 +541,24 @@
}
},
"node_modules/@aws-sdk/client-ses": {
"version": "3.777.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/client-ses/-/client-ses-3.777.0.tgz",
"integrity": "sha512-COZ6Yb5qt/JLmWtJG1rGXhvTFnaWHt0X8r9j0uGFuSRhLcguItxYlOnIskYePz/NJ0u/OXYbad0uG1M4V5IJ/w==",
"version": "3.782.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/client-ses/-/client-ses-3.782.0.tgz",
"integrity": "sha512-ZfnbiRwW9CnmwIgKChPVT06PB0GOjVoUXu2SZHW/PZbgFuLokkqAbRScEVnwtBLF6NR1k5Msg74HH4HRimRDtA==",
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/sha256-browser": "5.2.0",
"@aws-crypto/sha256-js": "5.2.0",
"@aws-sdk/core": "3.775.0",
"@aws-sdk/credential-provider-node": "3.777.0",
"@aws-sdk/credential-provider-node": "3.782.0",
"@aws-sdk/middleware-host-header": "3.775.0",
"@aws-sdk/middleware-logger": "3.775.0",
"@aws-sdk/middleware-recursion-detection": "3.775.0",
"@aws-sdk/middleware-user-agent": "3.775.0",
"@aws-sdk/middleware-user-agent": "3.782.0",
"@aws-sdk/region-config-resolver": "3.775.0",
"@aws-sdk/types": "3.775.0",
"@aws-sdk/util-endpoints": "3.775.0",
"@aws-sdk/util-endpoints": "3.782.0",
"@aws-sdk/util-user-agent-browser": "3.775.0",
"@aws-sdk/util-user-agent-node": "3.775.0",
"@aws-sdk/util-user-agent-node": "3.782.0",
"@smithy/config-resolver": "^4.1.0",
"@smithy/core": "^3.2.0",
"@smithy/fetch-http-handler": "^5.0.2",
@@ -592,9 +592,9 @@
}
},
"node_modules/@aws-sdk/client-sso": {
"version": "3.777.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.777.0.tgz",
"integrity": "sha512-0+z6CiAYIQa7s6FJ+dpBYPi9zr9yY5jBg/4/FGcwYbmqWPXwL9Thdtr0FearYRZgKl7bhL3m3dILCCfWqr3teQ==",
"version": "3.782.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.782.0.tgz",
"integrity": "sha512-5GlJBejo8wqMpSSEKb45WE82YxI2k73YuebjLH/eWDNQeE6VI5Bh9lA1YQ7xNkLLH8hIsb0pSfKVuwh0VEzVrg==",
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/sha256-browser": "5.2.0",
@@ -603,12 +603,12 @@
"@aws-sdk/middleware-host-header": "3.775.0",
"@aws-sdk/middleware-logger": "3.775.0",
"@aws-sdk/middleware-recursion-detection": "3.775.0",
"@aws-sdk/middleware-user-agent": "3.775.0",
"@aws-sdk/middleware-user-agent": "3.782.0",
"@aws-sdk/region-config-resolver": "3.775.0",
"@aws-sdk/types": "3.775.0",
"@aws-sdk/util-endpoints": "3.775.0",
"@aws-sdk/util-endpoints": "3.782.0",
"@aws-sdk/util-user-agent-browser": "3.775.0",
"@aws-sdk/util-user-agent-node": "3.775.0",
"@aws-sdk/util-user-agent-node": "3.782.0",
"@smithy/config-resolver": "^4.1.0",
"@smithy/core": "^3.2.0",
"@smithy/fetch-http-handler": "^5.0.2",
@@ -700,18 +700,18 @@
}
},
"node_modules/@aws-sdk/credential-provider-ini": {
"version": "3.777.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.777.0.tgz",
"integrity": "sha512-1X9mCuM9JSQPmQ+D2TODt4THy6aJWCNiURkmKmTIPRdno7EIKgAqrr/LLN++K5mBf54DZVKpqcJutXU2jwo01A==",
"version": "3.782.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.782.0.tgz",
"integrity": "sha512-wd4KdRy2YjLsE4Y7pz00470Iip06GlRHkG4dyLW7/hFMzEO2o7ixswCWp6J2VGZVAX64acknlv2Q0z02ebjmhw==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/core": "3.775.0",
"@aws-sdk/credential-provider-env": "3.775.0",
"@aws-sdk/credential-provider-http": "3.775.0",
"@aws-sdk/credential-provider-process": "3.775.0",
"@aws-sdk/credential-provider-sso": "3.777.0",
"@aws-sdk/credential-provider-web-identity": "3.777.0",
"@aws-sdk/nested-clients": "3.777.0",
"@aws-sdk/credential-provider-sso": "3.782.0",
"@aws-sdk/credential-provider-web-identity": "3.782.0",
"@aws-sdk/nested-clients": "3.782.0",
"@aws-sdk/types": "3.775.0",
"@smithy/credential-provider-imds": "^4.0.2",
"@smithy/property-provider": "^4.0.2",
@@ -724,17 +724,17 @@
}
},
"node_modules/@aws-sdk/credential-provider-node": {
"version": "3.777.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.777.0.tgz",
"integrity": "sha512-ZD66ywx1Q0KyUSuBXZIQzBe3Q7MzX8lNwsrCU43H3Fww+Y+HB3Ncws9grhSdNhKQNeGmZ+MgKybuZYaaeLwJEQ==",
"version": "3.782.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.782.0.tgz",
"integrity": "sha512-HZiAF+TCEyKjju9dgysjiPIWgt/+VerGaeEp18mvKLNfgKz1d+/82A2USEpNKTze7v3cMFASx3CvL8yYyF7mJw==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/credential-provider-env": "3.775.0",
"@aws-sdk/credential-provider-http": "3.775.0",
"@aws-sdk/credential-provider-ini": "3.777.0",
"@aws-sdk/credential-provider-ini": "3.782.0",
"@aws-sdk/credential-provider-process": "3.775.0",
"@aws-sdk/credential-provider-sso": "3.777.0",
"@aws-sdk/credential-provider-web-identity": "3.777.0",
"@aws-sdk/credential-provider-sso": "3.782.0",
"@aws-sdk/credential-provider-web-identity": "3.782.0",
"@aws-sdk/types": "3.775.0",
"@smithy/credential-provider-imds": "^4.0.2",
"@smithy/property-provider": "^4.0.2",
@@ -764,14 +764,14 @@
}
},
"node_modules/@aws-sdk/credential-provider-sso": {
"version": "3.777.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.777.0.tgz",
"integrity": "sha512-9mPz7vk9uE4PBVprfINv4tlTkyq1OonNevx2DiXC1LY4mCUCNN3RdBwAY0BTLzj0uyc3k5KxFFNbn3/8ZDQP7w==",
"version": "3.782.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.782.0.tgz",
"integrity": "sha512-1y1ucxTtTIGDSNSNxriQY8msinilhe9gGvQpUDYW9gboyC7WQJPDw66imy258V6osdtdi+xoHzVCbCz3WhosMQ==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/client-sso": "3.777.0",
"@aws-sdk/client-sso": "3.782.0",
"@aws-sdk/core": "3.775.0",
"@aws-sdk/token-providers": "3.777.0",
"@aws-sdk/token-providers": "3.782.0",
"@aws-sdk/types": "3.775.0",
"@smithy/property-provider": "^4.0.2",
"@smithy/shared-ini-file-loader": "^4.0.2",
@@ -783,13 +783,13 @@
}
},
"node_modules/@aws-sdk/credential-provider-web-identity": {
"version": "3.777.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.777.0.tgz",
"integrity": "sha512-uGCqr47fnthkqwq5luNl2dksgcpHHjSXz2jUra7TXtFOpqvnhOW8qXjoa1ivlkq8qhqlaZwCzPdbcN0lXpmLzQ==",
"version": "3.782.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.782.0.tgz",
"integrity": "sha512-xCna0opVPaueEbJoclj5C6OpDNi0Gynj+4d7tnuXGgQhTHPyAz8ZyClkVqpi5qvHTgxROdUEDxWqEO5jqRHZHQ==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/core": "3.775.0",
"@aws-sdk/nested-clients": "3.777.0",
"@aws-sdk/nested-clients": "3.782.0",
"@aws-sdk/types": "3.775.0",
"@smithy/property-provider": "^4.0.2",
"@smithy/types": "^4.2.0",
@@ -800,9 +800,9 @@
}
},
"node_modules/@aws-sdk/lib-storage": {
"version": "3.779.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.779.0.tgz",
"integrity": "sha512-AZfykrCgfnhlb5d5uyThHsqIwt41PYgnUTMyDuk4hbuKbiY8pfOiPdg8BYsC59iD2T4Iw9NujYhWUD+l8zNKcw==",
"version": "3.782.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.782.0.tgz",
"integrity": "sha512-UQYnIzpBReLko2XhDgG/rWpoHTWv4/zqUNl4XJXZRo9akLzrxGKtPrp5nJ4OLUkH3tIm1cvmI3XlSjHUW/OxWw==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/abort-controller": "^4.0.2",
@@ -817,7 +817,7 @@
"node": ">=18.0.0"
},
"peerDependencies": {
"@aws-sdk/client-s3": "^3.779.0"
"@aws-sdk/client-s3": "^3.782.0"
}
},
"node_modules/@aws-sdk/lib-storage/node_modules/buffer": {
@@ -985,14 +985,14 @@
}
},
"node_modules/@aws-sdk/middleware-user-agent": {
"version": "3.775.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.775.0.tgz",
"integrity": "sha512-7Lffpr1ptOEDE1ZYH1T78pheEY1YmeXWBfFt/amZ6AGsKSLG+JPXvof3ltporTGR2bhH/eJPo7UHCglIuXfzYg==",
"version": "3.782.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.782.0.tgz",
"integrity": "sha512-i32H2R6IItX+bQ2p4+v2gGO2jA80jQoJO2m1xjU9rYWQW3+ErWy4I5YIuQHTBfb6hSdAHbaRfqPDgbv9J2rjEg==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/core": "3.775.0",
"@aws-sdk/types": "3.775.0",
"@aws-sdk/util-endpoints": "3.775.0",
"@aws-sdk/util-endpoints": "3.782.0",
"@smithy/core": "^3.2.0",
"@smithy/protocol-http": "^5.1.0",
"@smithy/types": "^4.2.0",
@@ -1003,9 +1003,9 @@
}
},
"node_modules/@aws-sdk/nested-clients": {
"version": "3.777.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.777.0.tgz",
"integrity": "sha512-bmmVRsCjuYlStYPt06hr+f8iEyWg7+AklKCA8ZLDEJujXhXIowgUIqXmqpTkXwkVvDQ9tzU7hxaONjyaQCGybA==",
"version": "3.782.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.782.0.tgz",
"integrity": "sha512-QOYC8q7luzHFXrP0xYAqBctoPkynjfV0r9dqntFu4/IWMTyC1vlo1UTxFAjIPyclYw92XJyEkVCVg9v/nQnsUA==",
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/sha256-browser": "5.2.0",
@@ -1014,12 +1014,12 @@
"@aws-sdk/middleware-host-header": "3.775.0",
"@aws-sdk/middleware-logger": "3.775.0",
"@aws-sdk/middleware-recursion-detection": "3.775.0",
"@aws-sdk/middleware-user-agent": "3.775.0",
"@aws-sdk/middleware-user-agent": "3.782.0",
"@aws-sdk/region-config-resolver": "3.775.0",
"@aws-sdk/types": "3.775.0",
"@aws-sdk/util-endpoints": "3.775.0",
"@aws-sdk/util-endpoints": "3.782.0",
"@aws-sdk/util-user-agent-browser": "3.775.0",
"@aws-sdk/util-user-agent-node": "3.775.0",
"@aws-sdk/util-user-agent-node": "3.782.0",
"@smithy/config-resolver": "^4.1.0",
"@smithy/core": "^3.2.0",
"@smithy/fetch-http-handler": "^5.0.2",
@@ -1069,9 +1069,9 @@
}
},
"node_modules/@aws-sdk/s3-request-presigner": {
"version": "3.779.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.779.0.tgz",
"integrity": "sha512-L3mGSh6/9gf3FBVrQziCkuLbaRJMeNbLr6tg9ZSymJcDRzRqAiCWnHrenAavTnAAnm+Lu62Fg/A4g3T+YT+gEg==",
"version": "3.782.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.782.0.tgz",
"integrity": "sha512-Er8hdjc9zkxTh15MjdnMYggtUrGknDiuD1FwdW035kn/kwWop587G9rnRa1crhmyKRjLMn0Ki3fsyFUm/943XA==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/signature-v4-multi-region": "3.775.0",
@@ -1105,12 +1105,12 @@
}
},
"node_modules/@aws-sdk/token-providers": {
"version": "3.777.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.777.0.tgz",
"integrity": "sha512-Yc2cDONsHOa4dTSGOev6Ng2QgTKQUEjaUnsyKd13pc/nLLz/WLqHiQ/o7PcnKERJxXGs1g1C6l3sNXiX+kbnFQ==",
"version": "3.782.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.782.0.tgz",
"integrity": "sha512-4tPuk/3+THPrzKaXW4jE2R67UyGwHLFizZ47pcjJWbhb78IIJAy94vbeqEQ+veS84KF5TXcU7g5jGTXC0D70Wg==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/nested-clients": "3.777.0",
"@aws-sdk/nested-clients": "3.782.0",
"@aws-sdk/types": "3.775.0",
"@smithy/property-provider": "^4.0.2",
"@smithy/shared-ini-file-loader": "^4.0.2",
@@ -1147,9 +1147,9 @@
}
},
"node_modules/@aws-sdk/util-endpoints": {
"version": "3.775.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.775.0.tgz",
"integrity": "sha512-yjWmUgZC9tUxAo8Uaplqmq0eUh0zrbZJdwxGRKdYxfm4RG6fMw1tj52+KkatH7o+mNZvg1GDcVp/INktxonJLw==",
"version": "3.782.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.782.0.tgz",
"integrity": "sha512-/RJOAO7o7HI6lEa4ASbFFLHGU9iPK876BhsVfnl54MvApPVYWQ9sHO0anOUim2S5lQTwd/6ghuH3rFYSq/+rdw==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/types": "3.775.0",
@@ -1201,12 +1201,12 @@
}
},
"node_modules/@aws-sdk/util-user-agent-node": {
"version": "3.775.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.775.0.tgz",
"integrity": "sha512-N9yhTevbizTOMo3drH7Eoy6OkJ3iVPxhV7dwb6CMAObbLneS36CSfA6xQXupmHWcRvZPTz8rd1JGG3HzFOau+g==",
"version": "3.782.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.782.0.tgz",
"integrity": "sha512-dMFkUBgh2Bxuw8fYZQoH/u3H4afQ12VSkzEi//qFiDTwbKYq+u+RYjc8GLDM6JSK1BShMu5AVR7HD4ap1TYUnA==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/middleware-user-agent": "3.775.0",
"@aws-sdk/middleware-user-agent": "3.782.0",
"@aws-sdk/types": "3.775.0",
"@smithy/node-config-provider": "^4.0.2",
"@smithy/types": "^4.2.0",
@@ -1953,9 +1953,9 @@
}
},
"node_modules/@eslint/config-array": {
"version": "0.19.2",
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz",
"integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==",
"version": "0.20.0",
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz",
"integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -2028,9 +2028,9 @@
}
},
"node_modules/@eslint/js": {
"version": "9.23.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.23.0.tgz",
"integrity": "sha512-35MJ8vCPU0ZMxo7zfev2pypqTwWTofFZO6m4KAtdoFhRpLJUpHTZZ+KB3C7Hb1d7bULYwO4lJXGCi5Se+8OMbw==",
"version": "9.24.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.24.0.tgz",
"integrity": "sha512-uIY/y3z0uvOGX8cp1C2fiC4+ZmBhp6yZWkojtHL1YEMnRt1Y63HB9TM17proGEmeG7HeUY+UP36F0aknKYTpYA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -5139,9 +5139,9 @@
}
},
"node_modules/bullmq": {
"version": "5.45.2",
"resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.45.2.tgz",
"integrity": "sha512-wHZfcD4z4aLolxREmwNNDSbfh7USeq2e3yu5W2VGkzHMUcrH0fzZuRuCMsjD0XKS9ViK1U854oM9yWR6ftPeDA==",
"version": "5.48.0",
"resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.48.0.tgz",
"integrity": "sha512-fUtQrkefr6VAYYPjLXKHR6scWhwGI/0ok1wfAEPyhq8aRnJK8PJGEXUSssTEzDShadgLLXCmIOsVyhbs5/XWWg==",
"license": "MIT",
"dependencies": {
"cron-parser": "^4.9.0",
@@ -5215,9 +5215,9 @@
}
},
"node_modules/call-bind-apply-helpers": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz",
"integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
@@ -5228,13 +5228,13 @@
}
},
"node_modules/call-bound": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz",
"integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==",
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
"get-intrinsic": "^1.2.6"
"call-bind-apply-helpers": "^1.0.2",
"get-intrinsic": "^1.3.0"
},
"engines": {
"node": ">= 0.4"
@@ -6626,9 +6626,9 @@
"license": "MIT"
},
"node_modules/es-object-atoms": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz",
"integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
@@ -6762,19 +6762,19 @@
}
},
"node_modules/eslint": {
"version": "9.23.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.23.0.tgz",
"integrity": "sha512-jV7AbNoFPAY1EkFYpLq5bslU9NLNO8xnEeQXwErNibVryjk67wHVmddTBilc5srIttJDBrB0eMHKZBFbSIABCw==",
"version": "9.24.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.24.0.tgz",
"integrity": "sha512-eh/jxIEJyZrvbWRe4XuVclLPDYSYYYgLy5zXGGxD6j8zjSAxFEzI2fL/8xNq6O2yKqVt+eF2YhV+hxjV6UKXwQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.12.1",
"@eslint/config-array": "^0.19.2",
"@eslint/config-array": "^0.20.0",
"@eslint/config-helpers": "^0.2.0",
"@eslint/core": "^0.12.0",
"@eslint/eslintrc": "^3.3.1",
"@eslint/js": "9.23.0",
"@eslint/js": "9.24.0",
"@eslint/plugin-kit": "^0.2.7",
"@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
@@ -6823,9 +6823,9 @@
}
},
"node_modules/eslint-plugin-react": {
"version": "7.37.4",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.4.tgz",
"integrity": "sha512-BGP0jRmfYyvOyvMoRX/uoUeW+GqNj9y16bPQzqAHf3AYII/tDs+jMN0dBVkl88/OZwNGwrVFxE7riHsXVfy/LQ==",
"version": "7.37.5",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz",
"integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -6839,7 +6839,7 @@
"hasown": "^2.0.2",
"jsx-ast-utils": "^2.4.1 || ^3.0.0",
"minimatch": "^3.1.2",
"object.entries": "^1.1.8",
"object.entries": "^1.1.9",
"object.fromentries": "^2.0.8",
"object.values": "^1.2.1",
"prop-types": "^15.8.1",
@@ -7653,17 +7653,17 @@
}
},
"node_modules/get-intrinsic": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz",
"integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==",
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
"call-bind-apply-helpers": "^1.0.2",
"es-define-property": "^1.0.1",
"es-errors": "^1.3.0",
"es-object-atoms": "^1.0.0",
"es-object-atoms": "^1.1.1",
"function-bind": "^1.1.2",
"get-proto": "^1.0.0",
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"has-symbols": "^1.1.0",
"hasown": "^2.0.2",
@@ -9919,15 +9919,16 @@
}
},
"node_modules/object.entries": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz",
"integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==",
"version": "1.1.9",
"resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz",
"integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.7",
"call-bind": "^1.0.8",
"call-bound": "^1.0.4",
"define-properties": "^1.2.1",
"es-object-atoms": "^1.0.0"
"es-object-atoms": "^1.1.1"
},
"engines": {
"node": ">= 0.4"
@@ -12315,9 +12316,9 @@
"license": "Unlicense"
},
"node_modules/twilio": {
"version": "5.5.1",
"resolved": "https://registry.npmjs.org/twilio/-/twilio-5.5.1.tgz",
"integrity": "sha512-b1gLd2eMsCSCHRerp3GQUedVlz0nCTt5FbyPxDPmMvk5cm6eIPk4ZTp5JNpgucARZgpCB2uUACJbdcidEHAUBA==",
"version": "5.5.2",
"resolved": "https://registry.npmjs.org/twilio/-/twilio-5.5.2.tgz",
"integrity": "sha512-yrRh6immcL5xEVX7VmHsl3vU01x/fmqxf38kvxMrrtvEtAkYARYOPor9lt5T7964zC7l31k5sTrnLJmd2jjeOA==",
"license": "MIT",
"dependencies": {
"axios": "^1.7.8",

View File

@@ -12,17 +12,18 @@
"start": "node server.js",
"makeitpretty": "prettier --write \"**/*.{css,js,json,jsx,scss}\"",
"test:unit": "vitest run",
"test:watch": "vitest"
"test:watch": "vitest",
"job-totals-fixtures:local": "docker exec node-app /usr/bin/node /app/download-job-totals-fixtures.js"
},
"dependencies": {
"@aws-sdk/client-cloudwatch-logs": "^3.777.0",
"@aws-sdk/client-elasticache": "^3.777.0",
"@aws-sdk/client-s3": "^3.779.0",
"@aws-sdk/client-secrets-manager": "^3.777.0",
"@aws-sdk/client-ses": "^3.777.0",
"@aws-sdk/credential-provider-node": "^3.777.0",
"@aws-sdk/lib-storage": "^3.779.0",
"@aws-sdk/s3-request-presigner": "^3.779.0",
"@aws-sdk/client-cloudwatch-logs": "^3.782.0",
"@aws-sdk/client-elasticache": "^3.782.0",
"@aws-sdk/client-s3": "^3.782.0",
"@aws-sdk/client-secrets-manager": "^3.782.0",
"@aws-sdk/client-ses": "^3.782.0",
"@aws-sdk/credential-provider-node": "^3.782.0",
"@aws-sdk/lib-storage": "^3.782.0",
"@aws-sdk/s3-request-presigner": "^3.782.0",
"@opensearch-project/opensearch": "^2.13.0",
"@socket.io/admin-ui": "^0.5.1",
"@socket.io/redis-adapter": "^8.3.0",
@@ -32,7 +33,7 @@
"bee-queue": "^1.7.1",
"better-queue": "^3.8.12",
"bluebird": "^3.7.2",
"bullmq": "^5.45.2",
"bullmq": "^5.48.0",
"chart.js": "^4.4.8",
"cloudinary": "^2.6.0",
"compression": "^1.8.0",
@@ -68,7 +69,7 @@
"socket.io": "^4.8.1",
"socket.io-adapter": "^2.5.5",
"ssh2-sftp-client": "^11.0.0",
"twilio": "^5.5.1",
"twilio": "^5.5.2",
"uuid": "^11.1.0",
"winston": "^3.17.0",
"winston-cloudwatch": "^6.3.0",
@@ -76,10 +77,10 @@
"xmlbuilder2": "^3.1.1"
},
"devDependencies": {
"@eslint/js": "^9.23.0",
"@eslint/js": "^9.24.0",
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
"eslint": "^9.23.0",
"eslint-plugin-react": "^7.37.4",
"eslint": "^9.24.0",
"eslint-plugin-react": "^7.37.5",
"globals": "^15.15.0",
"mock-require": "^3.0.3",
"p-limit": "^3.1.0",

View File

@@ -16,7 +16,6 @@ const cors = require("cors");
const http = require("http");
const Redis = require("ioredis");
const express = require("express");
const bodyParser = require("body-parser");
const compression = require("compression");
const cookieParser = require("cookie-parser");
const { Server } = require("socket.io");

View File

@@ -55,7 +55,12 @@ exports.default = async (req, res) => {
const csv = converter.json2csv(shopList, { emptyFieldValue: "" });
emailer
.sendTaskEmail({
to: ["patrick.fic@convenient-brands.com", "bradley.rhoades@convenient-brands.com", "jrome@rometech.com"],
to: [
"patrick.fic@convenient-brands.com",
"bradley.rhoades@convenient-brands.com",
"jrome@rometech.com",
"ivana@imexsystems.ca"
],
subject: `RO Usage Report - ${moment().format("MM/DD/YYYY")}`,
text: `
Usage Report for ${moment().format("MM/DD/YYYY")} for Rome Online Customers.

View File

@@ -2841,6 +2841,15 @@ query GET_JOBID_BY_MERCHANTID_RONUMBER($merchantID: String!, $roNumber: String!)
bodyshop {
id
intellipay_config
email
}
}
}`;
exports.GET_BODYSHOP_BY_MERCHANT_ID = `
query GET_BODYSHOP_BY_MERCHANTID($merchantID: String!) {
bodyshops(where: {intellipay_merchant_id: {_eq: $merchantID}}) {
id
email
}
}`;

View File

@@ -2,8 +2,11 @@ const handlePaymentValidationError = require("./handlePaymentValidationError");
const {
GET_JOBID_BY_MERCHANTID_RONUMBER,
INSERT_PAYMENT_RESPONSE,
INSERT_NEW_PAYMENT
INSERT_NEW_PAYMENT,
GET_BODYSHOP_BY_MERCHANT_ID
} = require("../../graphql-client/queries");
const { sendTaskEmail } = require("../../email/sendemail");
const getPaymentType = require("./getPaymentType");
const moment = require("moment");
@@ -36,7 +39,34 @@ const handleInvoiceBasedPayment = async (values, logger, logMeta, res) => {
});
if (!result?.jobs?.length) {
return handlePaymentValidationError(res, logger, "intellipay-postback-job-not-found", "Job not found", logMeta);
// Fetch bodyshop data
const bodyshop = await gqlClient.request(GET_BODYSHOP_BY_MERCHANT_ID, {
merchantID: values.merchantid
});
if (bodyshop?.bodyshops?.[0]) {
// Note: changed bodyshops to bodyshop to match query name
const email = bodyshop.bodyshops[0].email;
await sendTaskEmail({
to: email,
subject: `Failed to Insert Payment`,
text: `The system has attempted to insert a payment that was generated by your merchant terminal but could not find an associated invoice. Transaction details are below. Please input this payment to your system manually.\n\n${Object.keys(
values
)
.map((key) => `${key}: ${values[key]}`)
.join("\n")}`
});
}
return handlePaymentValidationError(
res,
logger,
"intellipay-postback-job-not-found",
"Job not found",
logMeta,
200
);
}
const job = result.jobs[0];

View File

@@ -5,14 +5,15 @@
* @param logCode
* @param message
* @param logMeta
* @param returnCode
* @returns {*}
*/
const handlePaymentValidationError = (res, logger, logCode, message, logMeta) => {
const handlePaymentValidationError = (res, logger, logCode, message, logMeta, returnCode) => {
logger.log(logCode, "ERROR", "api", null, {
message,
...logMeta
});
return res.status(400).send(`Bad Request: ${message}`);
return res.status(returnCode || 400).send(`Bad Request: ${message}`);
};
module.exports = handlePaymentValidationError;

View File

@@ -96,7 +96,8 @@ describe("handleInvoiceBasedPayment", () => {
mockLogger,
"intellipay-postback-job-not-found",
"Job not found",
logMeta
logMeta,
200
);
});

View File

@@ -1,7 +1,5 @@
const Dinero = require("dinero.js");
const queries = require("../graphql-client/queries");
// const adminClient = require("../graphql-client/graphql-client").client;
// const _ = require("lodash");
const logger = require("../utils/logger");
const InstanceMgr = require("../utils/instanceMgr").default;
@@ -45,9 +43,11 @@ exports.totalsSsu = async function (req, res) {
}
});
if (result) {
res.status(200).send();
if (!result) {
throw new Error("Failed to update job totals");
}
res.status(200).send();
} catch (error) {
logger.log("job-totals-ssu-USA-error", "ERROR", req?.user?.email, id, {
jobid: id,
@@ -58,7 +58,7 @@ exports.totalsSsu = async function (req, res) {
}
};
//IMPORTANT*** These two functions MUST be mirrrored.
//IMPORTANT*** These two functions MUST be mirrored.
async function TotalsServerSide(req, res) {
const { job, client } = req.body;
await AtsAdjustmentsIfRequired({ job: job, client: client, user: req?.user });
@@ -133,6 +133,9 @@ async function TotalsServerSide(req, res) {
}
}
// Exported for testing purposes.
exports.TotalsServerSide = TotalsServerSide;
async function Totals(req, res) {
const { job, id } = req.body;

View File

@@ -0,0 +1,139 @@
const logger = require("../utils/logger");
const queries = require("../graphql-client/queries");
const moment = require("moment");
const { captureFixture } = require("./utils/seralizeHelper");
const { TotalsServerSide: totalsServerSideCA } = require("./job-totals"); // Canadian version (imex)
const { TotalsServerSide: totalsServerSideUS } = require("./job-totals-USA");
const InstanceMgr = require("../utils/instanceMgr").default;
const { uploadFileToS3 } = require("../utils/s3");
// requires two buckets be made per env, job-totals-test, job-totals-production, locally it will
// use `job-totals` in the owncloud stack
/**
* Returns the environment prefix based on NODE_ENV
* @returns {string}
*/
const getEnvPrefix = () => {
switch (process.env?.NODE_ENV) {
case "test":
return "test";
case "production":
return "production";
default:
return "test";
}
};
const envPrefix = getEnvPrefix();
const S3_BUCKET_NAME =
process.env?.NODE_ENV === "development"
? "imex-job-totals"
: InstanceMgr({
imex: `job-totals-${envPrefix}`,
rome: `job-totals-${envPrefix}-rome`
});
/**
* Generates a unique S3 key for the job totals file
* @param {string} jobId - The job ID
* @returns {string} - S3 key with timestamp
*/
const generateS3Key = (jobId) => `${jobId}-${moment().toISOString()}.json`;
/**
* Uploads job totals data to S3
* @param {object} data - The data to upload
* @param {string} jobId - The job ID
* @param {object} userInfo - User information for logging
* @returns {Promise<string>} - The S3 key
*/
const uploadJobTotalsToS3 = async (data, jobId, userInfo) => {
const key = generateS3Key(jobId);
try {
await uploadFileToS3({
bucketName: S3_BUCKET_NAME,
key: key,
content: JSON.stringify(data, null, 2),
contentType: "application/json"
});
logger.log(`Job totals uploaded successfully to ${key}`, "info", userInfo.email, jobId);
return key;
} catch (error) {
logger.log("Failed to upload job totals to S3", "error", userInfo.email, jobId, {
error: error?.message,
stack: error?.stack
});
throw error; // Re-throw for the main handler to catch
}
};
/**
* Fetches job data using GraphQL
* @param {object} client - GraphQL client
* @param {string} token - Bearer token
* @param {string} jobId - Job ID to fetch
* @returns {Promise<object>} - Job data
*/
const fetchJobData = async (client, token, jobId) => {
return client
.setHeaders({ Authorization: token })
.request(queries.GET_JOB_BY_PK, { id: jobId })
.then((response) => response.jobs_by_pk);
};
/**
* This function is used to capture job totals json files.
* @param {object} req - Express request
* @param {object} res - Express response
* @returns {Promise<void>}
*/
const jobTotalsRecorder = async (req, res) => {
const { id: jobId } = req.body;
const bearerToken = req.BearerToken;
const client = req.userGraphQLClient;
const userEmail = req?.user?.email;
logger.log("Starting job totals recording", "debug", userEmail, jobId);
try {
// Fetch job data
const jobData = await fetchJobData(client, bearerToken, jobId);
// Get the appropriate totals function based on instance
const totalsFunction = InstanceMgr({
imex: totalsServerSideCA,
rome: totalsServerSideUS
});
// Calculate the totals
const calculatedTotals = await totalsFunction({ body: { job: jobData, client }, req }, res, true);
// Prepare data for storage
const dataToSave = captureFixture(jobData, calculatedTotals);
// Upload to S3
await uploadJobTotalsToS3(dataToSave, jobId, { email: userEmail });
res.status(200).json({ success: true, message: "Job totals recorded successfully" });
} catch (error) {
logger.log("Failed to record job totals", "error", userEmail, jobId, {
error: error?.message,
stack: error?.stack
});
// Avoid sending response if it's already been sent
if (!res.headersSent) {
res.status(503).json({
success: false,
message: "Error processing job totals",
error: error.message
});
}
}
};
module.exports = jobTotalsRecorder;

View File

@@ -30,6 +30,7 @@ exports.totalsSsu = async function (req, res) {
id: id
});
// Capture the output of TotalsServerSide
const newTotals = await TotalsServerSide({ body: { job: job.jobs_by_pk, client: client } }, res, true);
const result = await client.setHeaders({ Authorization: BearerToken }).request(queries.UPDATE_JOB, {
@@ -57,7 +58,7 @@ exports.totalsSsu = async function (req, res) {
}
};
//IMPORTANT*** These two functions MUST be mirrrored.
//IMPORTANT*** These two functions MUST be mirrored.
async function TotalsServerSide(req, res) {
const { job, client } = req.body;
await AtsAdjustmentsIfRequired({ job: job, client: client, user: req?.user });
@@ -81,6 +82,9 @@ async function TotalsServerSide(req, res) {
}
}
// Exported for testing purposes
exports.TotalsServerSide = TotalsServerSide;
async function Totals(req, res) {
const { job, id } = req.body;

View File

@@ -0,0 +1,72 @@
import fs from "fs";
import path from "path";
import { describe, it, expect } from "vitest";
import { TotalsServerSide as TotalsServerSideCA } from "../job-totals"; // Canadian version (imex)
import { TotalsServerSide as TotalsServerSideUS } from "../job-totals-USA";
import { isFunction } from "lodash"; // US version (rome)
/**
* This function is used to replace the values in the object with their toObject() representation.
* @param key
* @param value
* @returns {*}
*/
const dineroReplacer = (key, value) => {
if (isFunction(value)) {
return value.toObject();
}
return value;
};
/**
* Normalizes the output of the TotalsServerSide function by converting
* @param obj
* @returns {any}
*/
const normalizeOutput = (obj) => {
return JSON.parse(JSON.stringify(obj, dineroReplacer));
};
/**
* This test suite is designed to validate the functionality of the TotalsServerSide function
*/
describe("TotalsServerSide fixture tests", () => {
const fixturesDir = path.join(__dirname, "fixtures", "job-totals");
const fixtureFiles = fs.readdirSync(fixturesDir).filter((f) => f.endsWith(".json"));
const dummyClient = {
request: async () => {
return {};
}
};
const dummyRes = {
status: () => ({ send: () => {} })
};
fixtureFiles.forEach((file) => {
it(`should produce matching output for fixture file ${file}`, async () => {
const fixturePath = path.join(fixturesDir, file);
const fixtureData = JSON.parse(fs.readFileSync(fixturePath, "utf8"));
const { environment, input, output: expectedOutput } = fixtureData;
const req = {
body: {
job: input,
client: dummyClient
},
user: {}
};
const computedOutput =
environment === "us" ? await TotalsServerSideUS(req, dummyRes) : await TotalsServerSideCA(req, dummyRes);
const normalizedComputed = normalizeOutput(computedOutput);
const normalizedExpected = normalizeOutput(expectedOutput);
expect(normalizedComputed).toEqual(normalizedExpected);
});
});
});

View File

@@ -0,0 +1,58 @@
const fs = require("fs");
const path = require("path");
const { default: InstanceMgr } = require("../../utils/instanceMgr");
const fixtureDir = path.join(__dirname, "..", "test", "fixtures", "job-totals");
/**
* Custom serializer for Dinero.js objects.
* @param key
* @param value
* @returns {*}
*/
const serializeDinero = (key, value) => {
if (value && typeof value === "object" && typeof value.toObject === "function") {
return value.toObject();
}
return value;
};
/**
* Capture a fixture for job totals.
* @param inputData
* @param outputData
* @param saveLocally
*/
const captureFixture = (inputData, outputData, saveLocally) => {
const fileName = `${inputData.id}.json`;
const filePath = path.join(fixtureDir, fileName);
const dataToSave = {
environment: InstanceMgr({
imex: "ca",
rome: "us"
}),
meta: {
ro_number: inputData.ro_number,
updated_at: inputData.updated_at
},
input: inputData,
output: outputData
};
// Save the file using our custom serializer.
if (saveLocally) {
if (!fs.existsSync(fixtureDir)) {
fs.mkdirSync(fixtureDir, { recursive: true });
}
fs.writeFileSync(filePath, JSON.stringify(dataToSave, serializeDinero, 2), "utf8");
}
return dataToSave;
};
module.exports = {
captureFixture,
serializeDinero
};

View File

@@ -7,6 +7,7 @@ const eventAuthorizationMiddleware = require("../middleware/eventAuthorizationMI
const validateFirebaseIdTokenMiddleware = require("../middleware/validateFirebaseIdTokenMiddleware");
const { totals, statustransition, totalsSsu, costing, lifecycle, costingmulti, jobUpdated } = require("../job/job");
const withUserGraphQLClientMiddleware = require("../middleware/withUserGraphQLClientMiddleware");
const jobTotalsRecorder = require("../job/job-totals-recorder");
router.post("/totals", validateFirebaseIdTokenMiddleware, withUserGraphQLClientMiddleware, totals);
router.post("/statustransition", eventAuthorizationMiddleware, statustransition);
@@ -17,5 +18,6 @@ router.post("/costingmulti", validateFirebaseIdTokenMiddleware, withUserGraphQLC
router.post("/partsscan", validateFirebaseIdTokenMiddleware, withUserGraphQLClientMiddleware, partsScan);
router.post("/ppc", validateFirebaseIdTokenMiddleware, withUserGraphQLClientMiddleware, ppc.generatePpc);
router.post("/job-updated", eventAuthorizationMiddleware, jobUpdated);
router.post("/totals-recorder", validateFirebaseIdTokenMiddleware, withUserGraphQLClientMiddleware, jobTotalsRecorder);
module.exports = router;