merge aio

This commit is contained in:
Dave Richer
2024-03-26 10:09:29 -04:00
34 changed files with 1018 additions and 768 deletions

View File

@@ -41,9 +41,8 @@ jobs:
imex-app-build: imex-app-build:
docker: docker:
- image: cimg/node:18.18.2 - image: cimg/node:18.18.2
resource_class: large
working_directory: ~/repo/client working_directory: ~/repo/client
steps: steps:
- checkout: - checkout:
path: ~/repo path: ~/repo
@@ -63,6 +62,31 @@ jobs:
to: "s3://imex-online-production/" to: "s3://imex-online-production/"
arguments: "--exclude '*.map'" arguments: "--exclude '*.map'"
imex-app-beta-build:
docker:
- image: cimg/node:18.18.2
resource_class: large
working_directory: ~/repo/client
steps:
- checkout:
path: ~/repo
- run:
name: Install Dependencies
command: npm i
- run: npm run build:production:imex
- aws-cli/setup:
aws_access_key_id: AWS_ACCESS_KEY_ID
aws_secret_access_key: AWS_SECRET_ACCESS_KEY
region: AWS_REGION
- aws-s3/sync:
from: dist
to: "s3://imex-online-beta/"
arguments: "--exclude '*.map'"
rome-api-deploy: rome-api-deploy:
docker: docker:
- image: "cimg/base:stable" - image: "cimg/base:stable"
@@ -181,7 +205,7 @@ jobs:
imex-test-app-build: imex-test-app-build:
docker: docker:
- image: cimg/node:16.15.0 - image: cimg/node:18.18.2
resource_class: large resource_class: large
working_directory: ~/repo/client working_directory: ~/repo/client
@@ -199,6 +223,32 @@ jobs:
to: "s3://imex-online-test/" to: "s3://imex-online-test/"
arguments: "--exclude '*.map'" arguments: "--exclude '*.map'"
imex-test-app-beta-build:
docker:
- image: cimg/node:18.18.2
resource_class: large
working_directory: ~/repo/client
steps:
- checkout:
path: ~/repo
- run:
name: Install Dependencies
command: npm i
- run: npm run build:test:imex
- aws-cli/setup:
aws_access_key_id: AWS_ACCESS_KEY_ID
aws_secret_access_key: AWS_SECRET_ACCESS_KEY
region: AWS_REGION
- aws-s3/sync:
from: build
to: "s3://imex-online-test-beta/"
arguments: "--exclude '*.map'"
admin-app-build: admin-app-build:
docker: docker:
@@ -236,12 +286,16 @@ workflows:
- imex-api-deploy: - imex-api-deploy:
filters: filters:
branches: branches:
only: master only: master-AIO
- imex-app-build: - imex-app-build:
filters: filters:
branches: branches:
only: master only: master
- hasura-migrate: - imex-app-beta-build:
filters:
branches:
only: master-AIO
- imex-hasura-migrate:
secret: ${HASURA_PROD_SECRET} secret: ${HASURA_PROD_SECRET}
filters: filters:
branches: branches:
@@ -263,7 +317,10 @@ workflows:
filters: filters:
branches: branches:
only: test only: test
- imex-test-app-beta-build:
filters:
branches:
only: test-AIO
- test-hasura-migrate: - test-hasura-migrate:
secret: ${HASURA_TEST_SECRET} secret: ${HASURA_TEST_SECRET}
filters: filters:

View File

@@ -37126,6 +37126,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>parts</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>partssublet</name> <name>partssublet</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>

288
client/package-lock.json generated
View File

@@ -20,7 +20,7 @@
"@splitsoftware/splitio-react": "^1.11.0", "@splitsoftware/splitio-react": "^1.11.0",
"@tanem/react-nprogress": "^5.0.51", "@tanem/react-nprogress": "^5.0.51",
"@vitejs/plugin-react": "^4.2.1", "@vitejs/plugin-react": "^4.2.1",
"antd": "^5.14.2", "antd": "^5.15.3",
"apollo-link-logger": "^2.0.1", "apollo-link-logger": "^2.0.1",
"apollo-link-sentry": "^3.3.0", "apollo-link-sentry": "^3.3.0",
"axios": "^1.6.7", "axios": "^1.6.7",
@@ -54,6 +54,7 @@
"react-joyride": "^2.7.4", "react-joyride": "^2.7.4",
"react-markdown": "^9.0.1", "react-markdown": "^9.0.1",
"react-number-format": "^5.3.3", "react-number-format": "^5.3.3",
"react-product-fruits": "^2.2.6",
"react-redux": "^9.1.0", "react-redux": "^9.1.0",
"react-resizable": "^3.0.5", "react-resizable": "^3.0.5",
"react-router-dom": "^6.22.2", "react-router-dom": "^6.22.2",
@@ -71,6 +72,7 @@
"styled-components": "^6.1.8", "styled-components": "^6.1.8",
"subscriptions-transport-ws": "^0.11.0", "subscriptions-transport-ws": "^0.11.0",
"terser-webpack-plugin": "^5.3.10", "terser-webpack-plugin": "^5.3.10",
"userpilot": "^1.3.1",
"vite-plugin-ejs": "^1.7.0", "vite-plugin-ejs": "^1.7.0",
"web-vitals": "^3.5.2", "web-vitals": "^3.5.2",
"workbox-core": "^7.0.0", "workbox-core": "^7.0.0",
@@ -186,8 +188,9 @@
} }
}, },
"node_modules/@ant-design/icons": { "node_modules/@ant-design/icons": {
"version": "5.3.0", "version": "5.3.4",
"license": "MIT", "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-5.3.4.tgz",
"integrity": "sha512-U5eTSeSFr2V9SeJzYOo5mybAZfsoNuiIA8bvFoZUe+h9LBLs8UwrVaVwcMQC4AhBuojXkLMlmtnIlvUczXXHaQ==",
"dependencies": { "dependencies": {
"@ant-design/colors": "^7.0.0", "@ant-design/colors": "^7.0.0",
"@ant-design/icons-svg": "^4.4.0", "@ant-design/icons-svg": "^4.4.0",
@@ -2104,8 +2107,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@babel/runtime": { "node_modules/@babel/runtime": {
"version": "7.23.9", "version": "7.24.1",
"license": "MIT", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.1.tgz",
"integrity": "sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==",
"dependencies": { "dependencies": {
"regenerator-runtime": "^0.14.0" "regenerator-runtime": "^0.14.0"
}, },
@@ -4970,6 +4974,32 @@
"version": "2.0.4", "version": "2.0.4",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@ndhoule/each": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@ndhoule/each/-/each-2.0.1.tgz",
"integrity": "sha512-wHuJw6x+rF6Q9Skgra++KccjBozCr9ymtna0FhxmV/8xT/hZ2ExGYR8SV8prg8x4AH/7mzDYErNGIVHuzHeybw==",
"dependencies": {
"@ndhoule/keys": "^2.0.0"
}
},
"node_modules/@ndhoule/includes": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@ndhoule/includes/-/includes-2.0.1.tgz",
"integrity": "sha512-Q8zN6f3yIhxgBwZ5ldLozHqJlc/fRQ5+hFFsPMFeC9SJvz0nq8vG9hoRXL1c1iaNFQd7yAZIy2igQpERoFqxqg==",
"dependencies": {
"@ndhoule/each": "^2.0.1"
}
},
"node_modules/@ndhoule/keys": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@ndhoule/keys/-/keys-2.0.0.tgz",
"integrity": "sha512-vtCqKBC1Av6dsBA8xpAO+cgk051nfaI+PnmTZep2Px0vYrDvpUmLxv7z40COlWH5yCpu3gzNhepk+02yiQiZNw=="
},
"node_modules/@ndhoule/pick": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@ndhoule/pick/-/pick-2.0.0.tgz",
"integrity": "sha512-xkYtpf1pRd8egwvl5tJcdGu+GBd6ZZH3S/zoIQ9txEI+pHF9oTIlxMC9G4CB3sRugAeLgu8qYJGl3tnxWq74Qw=="
},
"node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": {
"version": "5.1.1-v1", "version": "5.1.1-v1",
"license": "MIT", "license": "MIT",
@@ -5150,8 +5180,9 @@
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
}, },
"node_modules/@rc-component/color-picker": { "node_modules/@rc-component/color-picker": {
"version": "1.5.2", "version": "1.5.3",
"license": "MIT", "resolved": "https://registry.npmjs.org/@rc-component/color-picker/-/color-picker-1.5.3.tgz",
"integrity": "sha512-+tGGH3nLmYXTalVe0L8hSZNs73VTP5ueSHwUlDC77KKRaN7G4DS4wcpG5DTDzdcV/Yas+rzA6UGgIyzd8fS4cw==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.23.6", "@babel/runtime": "^7.23.6",
"@ctrl/tinycolor": "^3.6.1", "@ctrl/tinycolor": "^3.6.1",
@@ -5165,7 +5196,8 @@
}, },
"node_modules/@rc-component/context": { "node_modules/@rc-component/context": {
"version": "1.4.0", "version": "1.4.0",
"license": "MIT", "resolved": "https://registry.npmjs.org/@rc-component/context/-/context-1.4.0.tgz",
"integrity": "sha512-kFcNxg9oLRMoL3qki0OMxK+7g5mypjgaaJp/pkOis/6rVxma9nJBF/8kCIuTYHUQNr0ii7MxqE33wirPZLJQ2w==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.10.1", "@babel/runtime": "^7.10.1",
"rc-util": "^5.27.0" "rc-util": "^5.27.0"
@@ -5203,7 +5235,8 @@
}, },
"node_modules/@rc-component/portal": { "node_modules/@rc-component/portal": {
"version": "1.1.2", "version": "1.1.2",
"license": "MIT", "resolved": "https://registry.npmjs.org/@rc-component/portal/-/portal-1.1.2.tgz",
"integrity": "sha512-6f813C0IsasTZms08kfA8kPAGxbbkYToa8ALaiDIGGECU4i9hj8Plgbx0sNJDrey3EtHO30hmdaxtT0138xZcg==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.18.0", "@babel/runtime": "^7.18.0",
"classnames": "^2.3.2", "classnames": "^2.3.2",
@@ -5218,12 +5251,13 @@
} }
}, },
"node_modules/@rc-component/tour": { "node_modules/@rc-component/tour": {
"version": "1.12.3", "version": "1.14.2",
"license": "MIT", "resolved": "https://registry.npmjs.org/@rc-component/tour/-/tour-1.14.2.tgz",
"integrity": "sha512-A75DZ8LVvahBIvxooj3Gvf2sxe+CGOkmzPNX7ek0i0AJHyKZ1HXe5ieIGo3m0FMdZfVOlbCJ952Duq8VKAHk6g==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.18.0", "@babel/runtime": "^7.18.0",
"@rc-component/portal": "^1.0.0-9", "@rc-component/portal": "^1.0.0-9",
"@rc-component/trigger": "^1.3.6", "@rc-component/trigger": "^2.0.0",
"classnames": "^2.3.2", "classnames": "^2.3.2",
"rc-util": "^5.24.4" "rc-util": "^5.24.4"
}, },
@@ -5236,8 +5270,9 @@
} }
}, },
"node_modules/@rc-component/trigger": { "node_modules/@rc-component/trigger": {
"version": "1.18.3", "version": "2.0.0",
"license": "MIT", "resolved": "https://registry.npmjs.org/@rc-component/trigger/-/trigger-2.0.0.tgz",
"integrity": "sha512-niwKADPdY5dhdIblV6uwSayVivwo2uUISfJqri+/ovYQcH/omxDYBJKo755QKeoIIsWptxnRpgr7reEnNEZGFg==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.23.2", "@babel/runtime": "^7.23.2",
"@rc-component/portal": "^1.1.0", "@rc-component/portal": "^1.1.0",
@@ -7522,54 +7557,56 @@
} }
}, },
"node_modules/antd": { "node_modules/antd": {
"version": "5.14.2", "version": "5.15.3",
"license": "MIT", "resolved": "https://registry.npmjs.org/antd/-/antd-5.15.3.tgz",
"integrity": "sha512-53dpdGbfwipHVbqITmppp8N16i+BscMzz8NUNwaJgxwSvO9VQh/NfC/90lqGq3I2oBmxQ8TzRIxzFVKD/9OhlQ==",
"dependencies": { "dependencies": {
"@ant-design/colors": "^7.0.2", "@ant-design/colors": "^7.0.2",
"@ant-design/cssinjs": "^1.18.4", "@ant-design/cssinjs": "^1.18.4",
"@ant-design/icons": "^5.3.0", "@ant-design/icons": "^5.3.3",
"@ant-design/react-slick": "~1.0.2", "@ant-design/react-slick": "~1.0.2",
"@babel/runtime": "^7.24.0",
"@ctrl/tinycolor": "^3.6.1", "@ctrl/tinycolor": "^3.6.1",
"@rc-component/color-picker": "~1.5.2", "@rc-component/color-picker": "~1.5.3",
"@rc-component/mutate-observer": "^1.1.0", "@rc-component/mutate-observer": "^1.1.0",
"@rc-component/tour": "~1.12.3", "@rc-component/tour": "~1.14.2",
"@rc-component/trigger": "^1.18.3", "@rc-component/trigger": "^2.0.0",
"classnames": "^2.5.1", "classnames": "^2.5.1",
"copy-to-clipboard": "^3.3.3", "copy-to-clipboard": "^3.3.3",
"dayjs": "^1.11.10", "dayjs": "^1.11.10",
"qrcode.react": "^3.1.0", "qrcode.react": "^3.1.0",
"rc-cascader": "~3.21.2", "rc-cascader": "~3.24.0",
"rc-checkbox": "~3.1.0", "rc-checkbox": "~3.2.0",
"rc-collapse": "~3.7.2", "rc-collapse": "~3.7.2",
"rc-dialog": "~9.3.4", "rc-dialog": "~9.4.0",
"rc-drawer": "~7.0.0", "rc-drawer": "~7.1.0",
"rc-dropdown": "~4.1.0", "rc-dropdown": "~4.2.0",
"rc-field-form": "~1.41.0", "rc-field-form": "~1.42.1",
"rc-image": "~7.5.1", "rc-image": "~7.6.0",
"rc-input": "~1.4.3", "rc-input": "~1.4.5",
"rc-input-number": "~9.0.0", "rc-input-number": "~9.0.0",
"rc-mentions": "~2.10.1", "rc-mentions": "~2.11.1",
"rc-menu": "~9.12.4", "rc-menu": "~9.13.0",
"rc-motion": "^2.9.0", "rc-motion": "^2.9.0",
"rc-notification": "~5.3.0", "rc-notification": "~5.3.0",
"rc-pagination": "~4.0.4", "rc-pagination": "~4.0.4",
"rc-picker": "~4.1.4", "rc-picker": "~4.3.0",
"rc-progress": "~3.5.1", "rc-progress": "~3.5.1",
"rc-rate": "~2.12.0", "rc-rate": "~2.12.0",
"rc-resize-observer": "^1.4.0", "rc-resize-observer": "^1.4.0",
"rc-segmented": "~2.3.0", "rc-segmented": "~2.3.0",
"rc-select": "~14.11.0", "rc-select": "~14.13.0",
"rc-slider": "~10.5.0", "rc-slider": "~10.5.0",
"rc-steps": "~6.0.1", "rc-steps": "~6.0.1",
"rc-switch": "~4.1.0", "rc-switch": "~4.1.0",
"rc-table": "~7.39.0", "rc-table": "~7.42.0",
"rc-tabs": "~14.0.0", "rc-tabs": "~14.1.1",
"rc-textarea": "~1.6.3", "rc-textarea": "~1.6.3",
"rc-tooltip": "~6.1.3", "rc-tooltip": "~6.2.0",
"rc-tree": "~5.8.5", "rc-tree": "~5.8.5",
"rc-tree-select": "~5.17.0", "rc-tree-select": "~5.19.0",
"rc-upload": "~4.5.2", "rc-upload": "~4.5.2",
"rc-util": "^5.38.2", "rc-util": "^5.39.1",
"scroll-into-view-if-needed": "^3.1.0", "scroll-into-view-if-needed": "^3.1.0",
"throttle-debounce": "^5.0.0" "throttle-debounce": "^5.0.0"
}, },
@@ -7698,7 +7735,8 @@
}, },
"node_modules/array-tree-filter": { "node_modules/array-tree-filter": {
"version": "2.1.0", "version": "2.1.0",
"license": "MIT" "resolved": "https://registry.npmjs.org/array-tree-filter/-/array-tree-filter-2.1.0.tgz",
"integrity": "sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw=="
}, },
"node_modules/array-union": { "node_modules/array-union": {
"version": "2.1.0", "version": "2.1.0",
@@ -7887,7 +7925,8 @@
}, },
"node_modules/async-validator": { "node_modules/async-validator": {
"version": "4.2.5", "version": "4.2.5",
"license": "MIT" "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz",
"integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg=="
}, },
"node_modules/asynciterator.prototype": { "node_modules/asynciterator.prototype": {
"version": "1.0.0", "version": "1.0.0",
@@ -9625,6 +9664,11 @@
"version": "1.0.1", "version": "1.0.1",
"license": "MIT" "license": "MIT"
}, },
"node_modules/component-indexof": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/component-indexof/-/component-indexof-0.0.3.tgz",
"integrity": "sha512-puDQKvx/64HZXb4hBwIcvQLaLgux8o1CbWl39s41hrIIZDl1lJiD5jc22gj3RBeGK0ovxALDYpIbyjqDUUl0rw=="
},
"node_modules/compressible": { "node_modules/compressible": {
"version": "2.0.18", "version": "2.0.18",
"license": "MIT", "license": "MIT",
@@ -14347,6 +14391,14 @@
"node": ">= 10" "node": ">= 10"
} }
}, },
"node_modules/is": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/is/-/is-3.3.0.tgz",
"integrity": "sha512-nW24QBoPcFGGHJGUwnfpI7Yc5CdqWNdsyHQszVE/z2pKHXzh7FZ5GWhJqSyaQ9wMkQnsTx+kAI8bHlCX4tKdbg==",
"engines": {
"node": "*"
}
},
"node_modules/is-alphabetical": { "node_modules/is-alphabetical": {
"version": "2.0.1", "version": "2.0.1",
"license": "MIT", "license": "MIT",
@@ -18809,6 +18861,11 @@
"version": "2.2.7", "version": "2.2.7",
"license": "MIT" "license": "MIT"
}, },
"node_modules/obj-case": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/obj-case/-/obj-case-0.2.1.tgz",
"integrity": "sha512-PquYBBTy+Y6Ob/O2574XHhDtHJlV1cJHMCgW+rDRc9J5hhmRelJB3k5dTK/3cVmFVtzvAKuENeuLpoyTzMzkOg=="
},
"node_modules/object-assign": { "node_modules/object-assign": {
"version": "4.1.1", "version": "4.1.1",
"license": "MIT", "license": "MIT",
@@ -20836,6 +20893,11 @@
"version": "2.0.1", "version": "2.0.1",
"license": "MIT" "license": "MIT"
}, },
"node_modules/product-fruits": {
"version": "1.0.25",
"resolved": "https://registry.npmjs.org/product-fruits/-/product-fruits-1.0.25.tgz",
"integrity": "sha512-w//YC14ZBv3AJ9Ki/XEYPPltodXGJYLue/Wkv/E0Q6BnB/mZ4UvFZMcVYqTCMKUJWdsaeqwO840JC0BGaG3g1w=="
},
"node_modules/progress": { "node_modules/progress": {
"version": "2.0.3", "version": "2.0.3",
"license": "MIT", "license": "MIT",
@@ -21136,13 +21198,14 @@
} }
}, },
"node_modules/rc-cascader": { "node_modules/rc-cascader": {
"version": "3.21.2", "version": "3.24.0",
"license": "MIT", "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-3.24.0.tgz",
"integrity": "sha512-NwkYsVULA61S085jbOYbq8Z7leyIxVmLwf+71mWLjA3kCfUf/rAKC0WfjQbqBDaLGlU9d4z1EzyPaHBKLYWv6A==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.12.5", "@babel/runtime": "^7.12.5",
"array-tree-filter": "^2.1.0", "array-tree-filter": "^2.1.0",
"classnames": "^2.3.1", "classnames": "^2.3.1",
"rc-select": "~14.11.0", "rc-select": "~14.13.0",
"rc-tree": "~5.8.1", "rc-tree": "~5.8.1",
"rc-util": "^5.37.0" "rc-util": "^5.37.0"
}, },
@@ -21152,8 +21215,9 @@
} }
}, },
"node_modules/rc-checkbox": { "node_modules/rc-checkbox": {
"version": "3.1.0", "version": "3.2.0",
"license": "MIT", "resolved": "https://registry.npmjs.org/rc-checkbox/-/rc-checkbox-3.2.0.tgz",
"integrity": "sha512-8inzw4y9dAhZmv/Ydl59Qdy5tdp9CKg4oPVcRigi+ga/yKPZS5m5SyyQPtYSgbcqHRYOdUhiPSeKfktc76du1A==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.10.1", "@babel/runtime": "^7.10.1",
"classnames": "^2.3.2", "classnames": "^2.3.2",
@@ -21179,8 +21243,9 @@
} }
}, },
"node_modules/rc-dialog": { "node_modules/rc-dialog": {
"version": "9.3.4", "version": "9.4.0",
"license": "MIT", "resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-9.4.0.tgz",
"integrity": "sha512-AScCexaLACvf8KZRqCPz12BJ8olszXOS4lKlkMyzDQHS1m0zj1KZMYgmMCh39ee0Dcv8kyrj8mTqxuLyhH+QuQ==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.10.1", "@babel/runtime": "^7.10.1",
"@rc-component/portal": "^1.0.0-8", "@rc-component/portal": "^1.0.0-8",
@@ -21194,14 +21259,15 @@
} }
}, },
"node_modules/rc-drawer": { "node_modules/rc-drawer": {
"version": "7.0.0", "version": "7.1.0",
"license": "MIT", "resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-7.1.0.tgz",
"integrity": "sha512-nBE1rF5iZvpavoyqhSSz2mk/yANltA7g3aF0U45xkx381n3we/RKs9cJfNKp9mSWCedOKWt9FLEwZDaAaOGn2w==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.10.1", "@babel/runtime": "^7.23.9",
"@rc-component/portal": "^1.1.1", "@rc-component/portal": "^1.1.1",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"rc-motion": "^2.6.1", "rc-motion": "^2.6.1",
"rc-util": "^5.36.0" "rc-util": "^5.38.1"
}, },
"peerDependencies": { "peerDependencies": {
"react": ">=16.9.0", "react": ">=16.9.0",
@@ -21209,11 +21275,12 @@
} }
}, },
"node_modules/rc-dropdown": { "node_modules/rc-dropdown": {
"version": "4.1.0", "version": "4.2.0",
"license": "MIT", "resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-4.2.0.tgz",
"integrity": "sha512-odM8Ove+gSh0zU27DUj5cG1gNKg7mLWBYzB5E4nNLrLwBmYEgYP43vHKDGOVZcJSVElQBI0+jTQgjnq0NfLjng==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.18.3", "@babel/runtime": "^7.18.3",
"@rc-component/trigger": "^1.7.0", "@rc-component/trigger": "^2.0.0",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"rc-util": "^5.17.0" "rc-util": "^5.17.0"
}, },
@@ -21223,8 +21290,9 @@
} }
}, },
"node_modules/rc-field-form": { "node_modules/rc-field-form": {
"version": "1.41.0", "version": "1.42.1",
"license": "MIT", "resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-1.42.1.tgz",
"integrity": "sha512-SqiEmWNP+I61Lt80+ofPvT+3l8Ij6vb35IS+x14gheVnCJN0SRnOwEgsqCEB5FslT7xqjUqDnU845hRZ1jzlAA==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.18.0", "@babel/runtime": "^7.18.0",
"async-validator": "^4.1.0", "async-validator": "^4.1.0",
@@ -21271,13 +21339,14 @@
} }
}, },
"node_modules/rc-image": { "node_modules/rc-image": {
"version": "7.5.1", "version": "7.6.0",
"license": "MIT", "resolved": "https://registry.npmjs.org/rc-image/-/rc-image-7.6.0.tgz",
"integrity": "sha512-tL3Rvd1sS+frZQ01i+tkeUPaOeFz2iG9/scAt/Cfs0hyCRVA/w0Pu1J/JxIX8blalvmHE0bZQRYdOmRAzWu4Hg==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.11.2", "@babel/runtime": "^7.11.2",
"@rc-component/portal": "^1.0.2", "@rc-component/portal": "^1.0.2",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"rc-dialog": "~9.3.4", "rc-dialog": "~9.4.0",
"rc-motion": "^2.6.2", "rc-motion": "^2.6.2",
"rc-util": "^5.34.1" "rc-util": "^5.34.1"
}, },
@@ -21287,8 +21356,9 @@
} }
}, },
"node_modules/rc-input": { "node_modules/rc-input": {
"version": "1.4.3", "version": "1.4.5",
"license": "MIT", "resolved": "https://registry.npmjs.org/rc-input/-/rc-input-1.4.5.tgz",
"integrity": "sha512-AjzykhwnwYTRSwwgCu70CGKBIAv6bP2nqnFptnNTprph/TF1BAs0Qxl91mie/BR6n827WIJB6ZjaRf9iiMwAfw==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.11.1", "@babel/runtime": "^7.11.1",
"classnames": "^2.2.1", "classnames": "^2.2.1",
@@ -21315,14 +21385,15 @@
} }
}, },
"node_modules/rc-mentions": { "node_modules/rc-mentions": {
"version": "2.10.1", "version": "2.11.1",
"license": "MIT", "resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-2.11.1.tgz",
"integrity": "sha512-upb4AK1SRFql7qGnbLEvJqLMugVVIyjmwBJW9L0eLoN9po4JmJZaBzmKA4089fNtsU8k6l/tdZiVafyooeKnLw==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.22.5", "@babel/runtime": "^7.22.5",
"@rc-component/trigger": "^1.5.0", "@rc-component/trigger": "^2.0.0",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"rc-input": "~1.4.0", "rc-input": "~1.4.0",
"rc-menu": "~9.12.0", "rc-menu": "~9.13.0",
"rc-textarea": "~1.6.1", "rc-textarea": "~1.6.1",
"rc-util": "^5.34.1" "rc-util": "^5.34.1"
}, },
@@ -21332,11 +21403,12 @@
} }
}, },
"node_modules/rc-menu": { "node_modules/rc-menu": {
"version": "9.12.4", "version": "9.13.0",
"license": "MIT", "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-9.13.0.tgz",
"integrity": "sha512-1l8ooCB3HcYJKCltC/s7OxRKRjgymdl9htrCeGZcXNaMct0RxZRK6OPV3lPhVksIvAGMgzPd54ClpZ5J4b8cZA==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.10.1", "@babel/runtime": "^7.10.1",
"@rc-component/trigger": "^1.17.0", "@rc-component/trigger": "^2.0.0",
"classnames": "2.x", "classnames": "2.x",
"rc-motion": "^2.4.3", "rc-motion": "^2.4.3",
"rc-overflow": "^1.3.1", "rc-overflow": "^1.3.1",
@@ -21379,7 +21451,8 @@
}, },
"node_modules/rc-overflow": { "node_modules/rc-overflow": {
"version": "1.3.2", "version": "1.3.2",
"license": "MIT", "resolved": "https://registry.npmjs.org/rc-overflow/-/rc-overflow-1.3.2.tgz",
"integrity": "sha512-nsUm78jkYAoPygDAcGZeC2VwIg/IBGSodtOY3pMof4W3M9qRJgqaDYm03ZayHlde3I6ipliAxbN0RUcGf5KOzw==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.11.1", "@babel/runtime": "^7.11.1",
"classnames": "^2.2.1", "classnames": "^2.2.1",
@@ -21405,11 +21478,12 @@
} }
}, },
"node_modules/rc-picker": { "node_modules/rc-picker": {
"version": "4.1.4", "version": "4.3.0",
"license": "MIT", "resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-4.3.0.tgz",
"integrity": "sha512-bQNB/+NdW55jlQ5lPnNqF5J90Tq4SihLbAF7tzPBvGDJyoYmDgwLm4FN0ZB3Ot9i1v6vJY/1mgqZZTT9jbYc5w==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.10.1", "@babel/runtime": "^7.10.1",
"@rc-component/trigger": "^1.5.0", "@rc-component/trigger": "^2.0.0",
"classnames": "^2.2.1", "classnames": "^2.2.1",
"rc-overflow": "^1.3.2", "rc-overflow": "^1.3.2",
"rc-resize-observer": "^1.4.0", "rc-resize-observer": "^1.4.0",
@@ -21499,11 +21573,12 @@
} }
}, },
"node_modules/rc-select": { "node_modules/rc-select": {
"version": "14.11.0", "version": "14.13.0",
"license": "MIT", "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-14.13.0.tgz",
"integrity": "sha512-ew34FsaqHokK4dxVrcIxSYrgWJ2XJYlkk32eiOIiEo3GkHUExdCzmozMYaUc2P67c5QJRUvvY0uqCs3QG67h5A==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.10.1", "@babel/runtime": "^7.10.1",
"@rc-component/trigger": "^1.5.0", "@rc-component/trigger": "^2.0.0",
"classnames": "2.x", "classnames": "2.x",
"rc-motion": "^2.0.1", "rc-motion": "^2.0.1",
"rc-overflow": "^1.3.1", "rc-overflow": "^1.3.1",
@@ -21564,8 +21639,9 @@
} }
}, },
"node_modules/rc-table": { "node_modules/rc-table": {
"version": "7.39.0", "version": "7.42.0",
"license": "MIT", "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-7.42.0.tgz",
"integrity": "sha512-GwHV9Zs3HvWxBkoXatO/IeKoElzy3Ojf3dcyw1Rj3cyQVb+ZHtexslKdyzsrKRPJ0mUa62BoX+ZAg3zgTEql8w==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.10.1", "@babel/runtime": "^7.10.1",
"@rc-component/context": "^1.4.0", "@rc-component/context": "^1.4.0",
@@ -21583,13 +21659,14 @@
} }
}, },
"node_modules/rc-tabs": { "node_modules/rc-tabs": {
"version": "14.0.0", "version": "14.1.1",
"license": "MIT", "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-14.1.1.tgz",
"integrity": "sha512-5nOr9PVpJy2SWHTLgv1+kESDOb0tFzl0cYU9r9d8LfL0Wg9i/n1B558rmkxdQHgBwMqxmwoyPSAbQROxMQe8nw==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.11.2", "@babel/runtime": "^7.11.2",
"classnames": "2.x", "classnames": "2.x",
"rc-dropdown": "~4.1.0", "rc-dropdown": "~4.2.0",
"rc-menu": "~9.12.0", "rc-menu": "~9.13.0",
"rc-motion": "^2.6.2", "rc-motion": "^2.6.2",
"rc-resize-observer": "^1.0.0", "rc-resize-observer": "^1.0.0",
"rc-util": "^5.34.1" "rc-util": "^5.34.1"
@@ -21604,7 +21681,8 @@
}, },
"node_modules/rc-textarea": { "node_modules/rc-textarea": {
"version": "1.6.3", "version": "1.6.3",
"license": "MIT", "resolved": "https://registry.npmjs.org/rc-textarea/-/rc-textarea-1.6.3.tgz",
"integrity": "sha512-8k7+8Y2GJ/cQLiClFMg8kUXOOdvcFQrnGeSchOvI2ZMIVvX5a3zQpLxoODL0HTrvU63fPkRmMuqaEcOF9dQemA==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.10.1", "@babel/runtime": "^7.10.1",
"classnames": "^2.2.1", "classnames": "^2.2.1",
@@ -21618,11 +21696,12 @@
} }
}, },
"node_modules/rc-tooltip": { "node_modules/rc-tooltip": {
"version": "6.1.3", "version": "6.2.0",
"license": "MIT", "resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-6.2.0.tgz",
"integrity": "sha512-iS/3iOAvtDh9GIx1ulY7EFUXUtktFccNLsARo3NPgLf0QW9oT0w3dA9cYWlhqAKmD+uriEwdWz1kH0Qs4zk2Aw==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.11.2", "@babel/runtime": "^7.11.2",
"@rc-component/trigger": "^1.18.0", "@rc-component/trigger": "^2.0.0",
"classnames": "^2.3.1" "classnames": "^2.3.1"
}, },
"peerDependencies": { "peerDependencies": {
@@ -21632,7 +21711,8 @@
}, },
"node_modules/rc-tree": { "node_modules/rc-tree": {
"version": "5.8.5", "version": "5.8.5",
"license": "MIT", "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-5.8.5.tgz",
"integrity": "sha512-PRfcZtVDNkR7oh26RuNe1hpw11c1wfgzwmPFL0lnxGnYefe9lDAO6cg5wJKIAwyXFVt5zHgpjYmaz0CPy1ZtKg==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.10.1", "@babel/runtime": "^7.10.1",
"classnames": "2.x", "classnames": "2.x",
@@ -21649,12 +21729,13 @@
} }
}, },
"node_modules/rc-tree-select": { "node_modules/rc-tree-select": {
"version": "5.17.0", "version": "5.19.0",
"license": "MIT", "resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-5.19.0.tgz",
"integrity": "sha512-f4l5EsmSGF3ggj76YTzKNPY9SnXfFaer7ZccTSGb3urUf54L+cCqyT+UsPr+S5TAr8mZSxJ7g3CgkCe+cVQ6sw==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.10.1", "@babel/runtime": "^7.10.1",
"classnames": "2.x", "classnames": "2.x",
"rc-select": "~14.11.0-0", "rc-select": "~14.13.0",
"rc-tree": "~5.8.1", "rc-tree": "~5.8.1",
"rc-util": "^5.16.1" "rc-util": "^5.16.1"
}, },
@@ -21677,8 +21758,9 @@
} }
}, },
"node_modules/rc-util": { "node_modules/rc-util": {
"version": "5.38.2", "version": "5.39.1",
"license": "MIT", "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.39.1.tgz",
"integrity": "sha512-OW/ERynNDgNr4y0oiFmtes3rbEamXw7GHGbkbNd9iRr7kgT03T6fT0b9WpJ3mbxKhyOcAHnGcIoh5u/cjrC2OQ==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.18.3", "@babel/runtime": "^7.18.3",
"react-is": "^18.2.0" "react-is": "^18.2.0"
@@ -21694,7 +21776,8 @@
}, },
"node_modules/rc-virtual-list": { "node_modules/rc-virtual-list": {
"version": "3.11.4", "version": "3.11.4",
"license": "MIT", "resolved": "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-3.11.4.tgz",
"integrity": "sha512-NbBi0fvyIu26gP69nQBiWgUMTPX3mr4FcuBQiVqagU0BnuX8WQkiivnMs105JROeuUIFczLrlgUhLQwTWV1XDA==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.0", "@babel/runtime": "^7.20.0",
"classnames": "^2.2.6", "classnames": "^2.2.6",
@@ -22225,6 +22308,17 @@
"react-dom": ">=16.3.0" "react-dom": ">=16.3.0"
} }
}, },
"node_modules/react-product-fruits": {
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/react-product-fruits/-/react-product-fruits-2.2.6.tgz",
"integrity": "sha512-f57m1rCD+Cu8QfFQSpkHJjLaWauPbD01GNrbh4icQaOHA/6bHJGpcoSSEQfAtk3g2PyQBpsDdRvL9jC+hyxhhQ==",
"dependencies": {
"product-fruits": "^1.0.25"
},
"peerDependencies": {
"react": ">= 17.0.0"
}
},
"node_modules/react-redux": { "node_modules/react-redux": {
"version": "9.1.0", "version": "9.1.0",
"license": "MIT", "license": "MIT",
@@ -25941,6 +26035,18 @@
"react": "^16.8.0 || ^17.0.0 || ^18.0.0" "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
} }
}, },
"node_modules/userpilot": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/userpilot/-/userpilot-1.3.1.tgz",
"integrity": "sha512-HwOqRhTY829m++tx76E/4wMHLpqG39JPAESXnC54zdYIBASoX1wOO8ItaqpBlf5sH1rdIxU8/dUFa8nMQ60KYQ==",
"dependencies": {
"@ndhoule/includes": "^2.0.1",
"@ndhoule/pick": "^2.0.0",
"component-indexof": "0.0.3",
"is": "^3.1.0",
"obj-case": "^0.2.0"
}
},
"node_modules/util": { "node_modules/util": {
"version": "0.12.5", "version": "0.12.5",
"dev": true, "dev": true,

View File

@@ -20,7 +20,7 @@
"@splitsoftware/splitio-react": "^1.11.0", "@splitsoftware/splitio-react": "^1.11.0",
"@tanem/react-nprogress": "^5.0.51", "@tanem/react-nprogress": "^5.0.51",
"@vitejs/plugin-react": "^4.2.1", "@vitejs/plugin-react": "^4.2.1",
"antd": "^5.14.2", "antd": "^5.15.3",
"apollo-link-logger": "^2.0.1", "apollo-link-logger": "^2.0.1",
"apollo-link-sentry": "^3.3.0", "apollo-link-sentry": "^3.3.0",
"axios": "^1.6.7", "axios": "^1.6.7",
@@ -54,6 +54,7 @@
"react-joyride": "^2.7.4", "react-joyride": "^2.7.4",
"react-markdown": "^9.0.1", "react-markdown": "^9.0.1",
"react-number-format": "^5.3.3", "react-number-format": "^5.3.3",
"react-product-fruits": "^2.2.6",
"react-redux": "^9.1.0", "react-redux": "^9.1.0",
"react-resizable": "^3.0.5", "react-resizable": "^3.0.5",
"react-router-dom": "^6.22.2", "react-router-dom": "^6.22.2",
@@ -71,6 +72,7 @@
"styled-components": "^6.1.8", "styled-components": "^6.1.8",
"subscriptions-transport-ws": "^0.11.0", "subscriptions-transport-ws": "^0.11.0",
"terser-webpack-plugin": "^5.3.10", "terser-webpack-plugin": "^5.3.10",
"userpilot": "^1.3.1",
"vite-plugin-ejs": "^1.7.0", "vite-plugin-ejs": "^1.7.0",
"web-vitals": "^3.5.2", "web-vitals": "^3.5.2",
"workbox-core": "^7.0.0", "workbox-core": "^7.0.0",
@@ -121,6 +123,9 @@
"resolutions": { "resolutions": {
"react-error-overlay": "6.0.9" "react-error-overlay": "6.0.9"
}, },
"optionalDependencies": {
"@rollup/rollup-linux-x64-gnu": "4.6.1"
},
"devDependencies": { "devDependencies": {
"@babel/plugin-proposal-private-property-in-object": "^7.21.11", "@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@babel/preset-react": "^7.23.3", "@babel/preset-react": "^7.23.3",

View File

@@ -12,6 +12,12 @@ import App from "./App";
import * as Sentry from "@sentry/react"; import * as Sentry from "@sentry/react";
import themeProvider from "./themeProvider"; import themeProvider from "./themeProvider";
import { Userpilot } from 'userpilot'
// Initialize Userpilot
if(import.meta.env.DEV){
Userpilot.initialize('NX-69145f08');
}
dayjs.locale("en"); dayjs.locale("en");

View File

@@ -27,6 +27,8 @@ import "./App.styles.scss";
import handleBeta from "../utils/betaHandler"; import handleBeta from "../utils/betaHandler";
import Eula from "../components/eula/eula.component"; import Eula from "../components/eula/eula.component";
import InstanceRenderMgr from "../utils/instanceRenderMgr"; import InstanceRenderMgr from "../utils/instanceRenderMgr";
import { ProductFruits } from 'react-product-fruits';
const ResetPassword = lazy(() => const ResetPassword = lazy(() =>
import("../pages/reset-password/reset-password.component") import("../pages/reset-password/reset-password.component")
); );
@@ -149,6 +151,7 @@ export function App({
// Any route that is not assigned and matched will default to the Landing Page component // Any route that is not assigned and matched will default to the Landing Page component
return ( return (
<Suspense <Suspense
fallback={ fallback={
<LoadingSpinner <LoadingSpinner
@@ -160,6 +163,12 @@ export function App({
/> />
} }
> >
<ProductFruits //workspaceCode="aoJoEifvezYI0Z0P"
language="en" user={{
email: currentUser.email,
username: currentUser.email,
}} />
<Routes> <Routes>
<Route <Route
path="*" path="*"

View File

@@ -1,5 +1,5 @@
import {useMutation, useQuery} from "@apollo/client"; import {useMutation, useQuery} from "@apollo/client";
import {Button, Form, Popconfirm, Space} from "antd"; import {Button, Divider, Form, Popconfirm, Space} from "antd";
import dayjs from "../../utils/day"; import dayjs from "../../utils/day";
import queryString from "query-string"; import queryString from "query-string";
import React, {useState} from "react"; import React, {useState} from "react";
@@ -203,7 +203,7 @@ export function BillDetailEditcontainer({setPartsOrderContext, insertAuditTrail,
layout="vertical" layout="vertical"
> >
<BillFormContainer form={form} billEdit disabled={exported}/> <BillFormContainer form={form} billEdit disabled={exported}/>
<Divider orientation="left">{t("general.labels.media")}</Divider>
{bodyshop.uselocalmediaserver ? ( {bodyshop.uselocalmediaserver ? (
<JobsDocumentsLocalGallery <JobsDocumentsLocalGallery
job={{id: data ? data.bills_by_pk.jobid : null}} job={{id: data ? data.bills_by_pk.jobid : null}}

View File

@@ -173,7 +173,11 @@ export function BillDetailEditReturn({
</Form> </Form>
</Modal> </Modal>
<Button <Button
disabled={data.bills_by_pk.is_credit_memo || disabled} disabled={
data.bills_by_pk.is_credit_memo ||
data.bills_by_pk.isinhouse ||
disabled
}
onClick={() => { onClick={() => {
setOpen(true); setOpen(true);
}} }}

View File

@@ -172,6 +172,7 @@ function BillEnterModalContainer({
], ],
}, },
refetchQueries: ["QUERY_PARTS_BILLS_BY_JOBID", "GET_JOB_BY_PK"], refetchQueries: ["QUERY_PARTS_BILLS_BY_JOBID", "GET_JOB_BY_PK"],
awaitRefetchQueries: true
}); });
await Promise.all( await Promise.all(

View File

@@ -1,27 +1,27 @@
import Icon, { UploadOutlined } from "@ant-design/icons"; import Icon, { UploadOutlined } from '@ant-design/icons';
import { useApolloClient } from "@apollo/client"; import { useApolloClient } from '@apollo/client';
import { useSplitTreatments } from "@splitsoftware/splitio-react"; import { useSplitTreatments } from '@splitsoftware/splitio-react';
import { Alert, Divider, Form, Input, Select, Space, Statistic, Switch, Upload, } from "antd"; import { Alert, Divider, Form, Input, Select, Space, Statistic, Switch, Upload } from 'antd';
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from 'react';
import { useTranslation } from "react-i18next"; import { useTranslation } from 'react-i18next';
import { MdOpenInNew } from "react-icons/md"; import { MdOpenInNew } from 'react-icons/md';
import { connect } from "react-redux"; import { connect } from 'react-redux';
import { Link } from "react-router-dom"; import { Link } from 'react-router-dom';
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from 'reselect';
import { CHECK_BILL_INVOICE_NUMBER } from "../../graphql/bills.queries"; import { CHECK_BILL_INVOICE_NUMBER } from '../../graphql/bills.queries';
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from '../../redux/user/user.selectors';
import dayjs from "../../utils/day"; import dayjs from '../../utils/day';
import InstanceRenderManager from "../../utils/instanceRenderMgr"; import InstanceRenderManager from '../../utils/instanceRenderMgr';
import AlertComponent from "../alert/alert.component"; import AlertComponent from '../alert/alert.component';
import BillFormLinesExtended from "../bill-form-lines-extended/bill-form-lines-extended.component"; import BillFormLinesExtended from '../bill-form-lines-extended/bill-form-lines-extended.component';
import FormDatePicker from "../form-date-picker/form-date-picker.component"; import FormDatePicker from '../form-date-picker/form-date-picker.component';
import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component"; import FormFieldsChanged from '../form-fields-changed-alert/form-fields-changed-alert.component';
import CurrencyInput from "../form-items-formatted/currency-form-item.component"; import CurrencyInput from '../form-items-formatted/currency-form-item.component';
import JobSearchSelect from "../job-search-select/job-search-select.component"; import JobSearchSelect from '../job-search-select/job-search-select.component';
import LayoutFormRow from "../layout-form-row/layout-form-row.component"; import LayoutFormRow from '../layout-form-row/layout-form-row.component';
import VendorSearchSelect from "../vendor-search-select/vendor-search-select.component"; import VendorSearchSelect from '../vendor-search-select/vendor-search-select.component';
import BillFormLines from "./bill-form.lines.component"; import BillFormLines from './bill-form.lines.component';
import { CalculateBillTotal } from "./bill-form.totals.utility"; import { CalculateBillTotal } from './bill-form.totals.utility';
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
@@ -41,20 +41,20 @@ export function BillFormComponent({
job, job,
loadOutstandingReturns, loadOutstandingReturns,
loadInventory, loadInventory,
preferredMake preferredMake,
}) { }) {
const { t } = useTranslation();
const {t} = useTranslation();
const client = useApolloClient(); const client = useApolloClient();
const [discount, setDiscount] = useState(0); const [discount, setDiscount] = useState(0);
const {treatments: {Extended_Bill_Posting, ClosingPeriod}} = useSplitTreatments({ const {
treatments: { Extended_Bill_Posting, ClosingPeriod },
} = useSplitTreatments({
attributes: {}, attributes: {},
names: ["Extended_Bill_Posting", "ClosingPeriod"], names: ['Extended_Bill_Posting', 'ClosingPeriod'],
splitKey: bodyshop.imexshopid, splitKey: bodyshop.imexshopid,
}); });
const handleVendorSelect = (props, opt) => { const handleVendorSelect = (props, opt) => {
setDiscount(opt.discount); setDiscount(opt.discount);
@@ -62,7 +62,7 @@ export function BillFormComponent({
!billEdit && !billEdit &&
loadOutstandingReturns({ loadOutstandingReturns({
variables: { variables: {
jobId: form.getFieldValue("jobid"), jobId: form.getFieldValue('jobid'),
vendorId: opt.value, vendorId: opt.value,
}, },
}); });
@@ -71,7 +71,7 @@ export function BillFormComponent({
const handleFederalTaxExemptSwitchToggle = (checked) => { const handleFederalTaxExemptSwitchToggle = (checked) => {
// Early gate // Early gate
if (!checked) return; if (!checked) return;
const values = form.getFieldsValue("billlines"); const values = form.getFieldsValue('billlines');
// Gate bill lines // Gate bill lines
if (!values?.billlines?.length) return; if (!values?.billlines?.length) return;
@@ -83,23 +83,21 @@ export function BillFormComponent({
}; };
useEffect(() => { useEffect(() => {
if (job) form.validateFields(["is_credit_memo"]); if (job) form.validateFields(['is_credit_memo']);
}, [job, form]); }, [job, form]);
useEffect(() => { useEffect(() => {
const vendorId = form.getFieldValue("vendorid"); const vendorId = form.getFieldValue('vendorid');
if (vendorId && vendorAutoCompleteOptions) { if (vendorId && vendorAutoCompleteOptions) {
const matchingVendors = vendorAutoCompleteOptions.filter( const matchingVendors = vendorAutoCompleteOptions.filter((v) => v.id === vendorId);
(v) => v.id === vendorId
);
if (matchingVendors.length === 1) { if (matchingVendors.length === 1) {
setDiscount(matchingVendors[0].discount); setDiscount(matchingVendors[0].discount);
} }
} }
const jobId = form.getFieldValue("jobid"); const jobId = form.getFieldValue('jobid');
if (jobId) { if (jobId) {
loadLines({variables: {id: jobId}}); loadLines({ variables: { id: jobId } });
if (form.getFieldValue("is_credit_memo") && vendorId && !billEdit) { if (form.getFieldValue('is_credit_memo') && vendorId && !billEdit) {
loadOutstandingReturns({ loadOutstandingReturns({
variables: { variables: {
jobId: jobId, jobId: jobId,
@@ -125,18 +123,14 @@ export function BillFormComponent({
return ( return (
<div> <div>
<FormFieldsChanged form={form}/> <FormFieldsChanged form={form} />
<Form.Item <Form.Item style={{ display: 'none' }} name="isinhouse" valuePropName="checked">
style={{display: "none"}} <Switch />
name="isinhouse"
valuePropName="checked"
>
<Switch/>
</Form.Item> </Form.Item>
<LayoutFormRow grow> <LayoutFormRow grow>
<Form.Item <Form.Item
name="jobid" name="jobid"
label={t("bills.fields.ro_number")} label={t('bills.fields.ro_number')}
rules={[ rules={[
{ {
required: true, required: true,
@@ -149,13 +143,19 @@ export function BillFormComponent({
convertedOnly convertedOnly
notExported={false} notExported={false}
onBlur={() => { onBlur={() => {
if (form.getFieldValue("jobid") !== null && form.getFieldValue("jobid") !== undefined) { if (
loadLines({variables: {id: form.getFieldValue("jobid")}}); form.getFieldValue('jobid') !== null &&
if (form.getFieldValue("vendorid") !== null && form.getFieldValue("vendorid") !== undefined) { form.getFieldValue('jobid') !== undefined
) {
loadLines({ variables: { id: form.getFieldValue('jobid') } });
if (
form.getFieldValue('vendorid') !== null &&
form.getFieldValue('vendorid') !== undefined
) {
loadOutstandingReturns({ loadOutstandingReturns({
variables: { variables: {
jobId: form.getFieldValue("jobid"), jobId: form.getFieldValue('jobid'),
vendorId: form.getFieldValue("vendorid"), vendorId: form.getFieldValue('vendorid'),
}, },
}); });
} }
@@ -164,7 +164,7 @@ export function BillFormComponent({
/> />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t("bills.fields.vendor")} label={t('bills.fields.vendor')}
name="vendorid" name="vendorid"
// style={{ display: billEdit ? "none" : null }} // style={{ display: billEdit ? "none" : null }}
rules={[ rules={[
@@ -172,14 +172,10 @@ export function BillFormComponent({
required: true, required: true,
//message: t("general.validation.required"), //message: t("general.validation.required"),
}, },
({getFieldValue}) => ({ ({ getFieldValue }) => ({
validator(rule, value) { validator(rule, value) {
if ( if (value && !getFieldValue(['isinhouse']) && value === bodyshop.inhousevendorid) {
value && return Promise.reject(t('bills.validation.manualinhouse'));
!getFieldValue(["isinhouse"]) &&
value === bodyshop.inhousevendorid
) {
return Promise.reject(t("bills.validation.manualinhouse"));
} }
return Promise.resolve(); return Promise.resolve();
}, },
@@ -203,7 +199,7 @@ export function BillFormComponent({
type="warning" type="warning"
message={ message={
<Space> <Space>
{t("bills.labels.iouexists")} {t('bills.labels.iouexists')}
<Link <Link
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
@@ -211,7 +207,7 @@ export function BillFormComponent({
> >
<Space> <Space>
{iou.ro_number} {iou.ro_number}
<Icon component={MdOpenInNew}/> <Icon component={MdOpenInNew} />
</Space> </Space>
</Link> </Link>
</Space> </Space>
@@ -220,7 +216,7 @@ export function BillFormComponent({
))} ))}
<LayoutFormRow> <LayoutFormRow>
<Form.Item <Form.Item
label={t("bills.fields.invoice_number")} label={t('bills.fields.invoice_number')}
name="invoice_number" name="invoice_number"
validateTrigger="onBlur" validateTrigger="onBlur"
hasFeedback hasFeedback
@@ -229,9 +225,9 @@ export function BillFormComponent({
required: true, required: true,
//message: t("general.validation.required"), //message: t("general.validation.required"),
}, },
({getFieldValue}) => ({ ({ getFieldValue }) => ({
async validator(rule, value) { async validator(rule, value) {
const vendorid = getFieldValue("vendorid"); const vendorid = getFieldValue('vendorid');
if (vendorid && value) { if (vendorid && value) {
const response = await client.query({ const response = await client.query({
query: CHECK_BILL_INVOICE_NUMBER, query: CHECK_BILL_INVOICE_NUMBER,
@@ -245,14 +241,11 @@ export function BillFormComponent({
return Promise.resolve(); return Promise.resolve();
} else if ( } else if (
response.data.bills_aggregate.nodes.length === 1 && response.data.bills_aggregate.nodes.length === 1 &&
response.data.bills_aggregate.nodes[0].id === response.data.bills_aggregate.nodes[0].id === form.getFieldValue('id')
form.getFieldValue("id")
) { ) {
return Promise.resolve(); return Promise.resolve();
} }
return Promise.reject( return Promise.reject(t('bills.validation.unique_invoice_number'));
t("bills.validation.unique_invoice_number")
);
} else { } else {
return Promise.resolve(); return Promise.resolve();
} }
@@ -260,41 +253,34 @@ export function BillFormComponent({
}), }),
]} ]}
> >
<Input disabled={disabled || disableInvNumber}/> <Input disabled={disabled || disableInvNumber} />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t("bills.fields.date")} label={t('bills.fields.date')}
name="date" name="date"
rules={[ rules={[
{ {
required: true, required: true,
//message: t("general.validation.required"), //message: t("general.validation.required"),
}, },
({getFieldValue}) => ({ ({ getFieldValue }) => ({
validator(rule, value) { validator(rule, value) {
if ( if (ClosingPeriod.treatment === 'on' && bodyshop.accountingconfig.ClosingPeriod) {
ClosingPeriod.treatment === "on" &&
bodyshop.accountingconfig.ClosingPeriod
) {
if ( if (
dayjs(value) dayjs(value)
.startOf("day") .startOf('day')
.isSameOrAfter( .isSameOrAfter(
dayjs( dayjs(bodyshop.accountingconfig.ClosingPeriod[0]).startOf('day')
bodyshop.accountingconfig.ClosingPeriod[0]
).startOf("day")
) && ) &&
dayjs(value) dayjs(value)
.startOf("day") .startOf('day')
.isSameOrBefore( .isSameOrBefore(
dayjs( dayjs(bodyshop.accountingconfig.ClosingPeriod[1]).endOf('day')
bodyshop.accountingconfig.ClosingPeriod[1]
).endOf("day")
) )
) { ) {
return Promise.resolve(); return Promise.resolve();
} else { } else {
return Promise.reject(t("bills.validation.closingperiod")); return Promise.reject(t('bills.validation.closingperiod'));
} }
} else { } else {
return Promise.resolve(); return Promise.resolve();
@@ -303,20 +289,16 @@ export function BillFormComponent({
}), }),
]} ]}
> >
<FormDatePicker disabled={disabled}/> <FormDatePicker disabled={disabled} />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t("bills.fields.is_credit_memo")} label={t('bills.fields.is_credit_memo')}
name="is_credit_memo" name="is_credit_memo"
valuePropName="checked" valuePropName="checked"
rules={[ rules={[
({getFieldValue}) => ({ ({ getFieldValue }) => ({
validator(rule, value) { validator(rule, value) {
if ( if (value === true && getFieldValue('jobid') && getFieldValue('vendorid')) {
value === true &&
getFieldValue("jobid") &&
getFieldValue("vendorid")
) {
//Removed as this would cause an additional reload when validating the form on submit and clear the values. //Removed as this would cause an additional reload when validating the form on submit and clear the values.
// loadOutstandingReturns({ // loadOutstandingReturns({
// variables: { // variables: {
@@ -334,7 +316,7 @@ export function BillFormComponent({
job.status === bodyshop.md_ro_statuses.default_void) && job.status === bodyshop.md_ro_statuses.default_void) &&
(value === false || !value) (value === false || !value)
) { ) {
return Promise.reject(t("bills.labels.onlycmforinvoiced")); return Promise.reject(t('bills.labels.onlycmforinvoiced'));
} }
return Promise.resolve(); return Promise.resolve();
@@ -342,10 +324,10 @@ export function BillFormComponent({
}), }),
]} ]}
> >
<Switch/> <Switch />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t("bills.fields.total")} label={t('bills.fields.total')}
name="total" name="total"
rules={[ rules={[
{ {
@@ -354,11 +336,11 @@ export function BillFormComponent({
}, },
]} ]}
> >
<CurrencyInput min={0} disabled={disabled}/> <CurrencyInput min={0} disabled={disabled} />
</Form.Item> </Form.Item>
{!billEdit && ( {!billEdit && (
<Form.Item label={t("bills.fields.allpartslocation")} name="location"> <Form.Item label={t('bills.fields.allpartslocation')} name="location">
<Select style={{width: "10rem"}} disabled={disabled} allowClear> <Select style={{ width: '10rem' }} disabled={disabled} allowClear>
{bodyshop.md_parts_locations.map((loc, idx) => ( {bodyshop.md_parts_locations.map((loc, idx) => (
<Select.Option key={idx} value={loc}> <Select.Option key={idx} value={loc}>
{loc} {loc}
@@ -369,115 +351,99 @@ export function BillFormComponent({
)} )}
</LayoutFormRow> </LayoutFormRow>
<LayoutFormRow> <LayoutFormRow>
{ {InstanceRenderManager({
InstanceRenderManager({imex: imex: (
<Form.Item <Form.Item span={3} label={t('bills.fields.federal_tax_rate')} name="federal_tax_rate">
span={3}
label={t("bills.fields.federal_tax_rate")}
name="federal_tax_rate"
>
<CurrencyInput min={0} disabled={disabled} /> <CurrencyInput min={0} disabled={disabled} />
</Form.Item> })
}
<Form.Item
span={3}
label={t("bills.fields.state_tax_rate")}
name="state_tax_rate"
>
<CurrencyInput min={0} disabled={disabled}/>
</Form.Item> </Form.Item>
{ ),
InstanceRenderManager({imex: <> })}
<Form.Item <Form.Item span={3} label={t('bills.fields.state_tax_rate')} name="state_tax_rate">
span={3} <CurrencyInput min={0} disabled={disabled} />
label={t("bills.fields.local_tax_rate")} </Form.Item>
name="local_tax_rate" {InstanceRenderManager({
> imex: (
<>
<Form.Item span={3} label={t('bills.fields.local_tax_rate')} name="local_tax_rate">
<CurrencyInput min={0} /> <CurrencyInput min={0} />
</Form.Item> </Form.Item>
{bodyshop.pbs_serialnumber || bodyshop.cdk_dealerid ? ( {bodyshop.pbs_serialnumber || bodyshop.cdk_dealerid ? (
<Form.Item <Form.Item
span={2} span={2}
label={t("bills.labels.federal_tax_exempt")} label={t('bills.labels.federal_tax_exempt')}
name="federal_tax_exempt" name="federal_tax_exempt"
> >
<Switch onChange={handleFederalTaxExemptSwitchToggle} /> <Switch onChange={handleFederalTaxExemptSwitchToggle} />
</Form.Item> </Form.Item>
) : null} ) : null}
</>}) </>
} ),
})}
<Form.Item shouldUpdate span={13}> <Form.Item shouldUpdate span={13}>
{() => { {() => {
const values = form.getFieldsValue([ const values = form.getFieldsValue([
"billlines", 'billlines',
"total", 'total',
"federal_tax_rate", 'federal_tax_rate',
"state_tax_rate", 'state_tax_rate',
"local_tax_rate", 'local_tax_rate',
]); ]);
let totals; let totals;
if ( if (!!values.total && !!values.billlines && values.billlines.length > 0)
!!values.total &&
!!values.billlines &&
values.billlines.length > 0
)
totals = CalculateBillTotal(values); totals = CalculateBillTotal(values);
if (!!totals) if (!!totals)
return ( return (
<div align="right"> <div align="right">
<Space wrap> <Space wrap>
<Statistic <Statistic
title={t("bills.labels.subtotal")} title={t('bills.labels.subtotal')}
value={totals.subtotal.toFormat()} value={totals.subtotal.toFormat()}
precision={2} precision={2}
/> />
{ {InstanceRenderManager({
InstanceRenderManager({imex: <Statistic imex: (
title={t("bills.labels.federal_tax")} <Statistic
title={t('bills.labels.federal_tax')}
value={totals.federalTax.toFormat()} value={totals.federalTax.toFormat()}
precision={2} precision={2}
/> }) />
} ),
})}
<Statistic <Statistic
title={t("bills.labels.state_tax")} title={t('bills.labels.state_tax')}
value={totals.stateTax.toFormat()} value={totals.stateTax.toFormat()}
precision={2} precision={2}
/> />
{ {InstanceRenderManager({
InstanceRenderManager({imex: <Statistic imex: (
title={t("bills.labels.local_tax")} <Statistic
title={t('bills.labels.local_tax')}
value={totals.localTax.toFormat()} value={totals.localTax.toFormat()}
precision={2} precision={2}
/>}) />
} ),
})}
<Statistic <Statistic
title={t("bills.labels.entered_total")} title={t('bills.labels.entered_total')}
value={totals.enteredTotal.toFormat()} value={totals.enteredTotal.toFormat()}
precision={2} precision={2}
/> />
<Statistic <Statistic
title={t("bills.labels.bill_total")} title={t('bills.labels.bill_total')}
value={totals.invoiceTotal.toFormat()} value={totals.invoiceTotal.toFormat()}
precision={2} precision={2}
/> />
<Statistic <Statistic
title={t("bills.labels.discrepancy")} title={t('bills.labels.discrepancy')}
valueStyle={{ valueStyle={{
color: color: totals.discrepancy.getAmount() === 0 ? 'green' : 'red',
totals.discrepancy.getAmount() === 0
? "green"
: "red",
}} }}
value={totals.discrepancy.toFormat()} value={totals.discrepancy.toFormat()}
precision={2} precision={2}
/> />
</Space> </Space>
{form.getFieldValue("is_credit_memo") ? ( {form.getFieldValue('is_credit_memo') ? (
<AlertComponent <AlertComponent type="warning" message={t('bills.labels.enteringcreditmemo')} />
type="warning"
message={t("bills.labels.enteringcreditmemo")}
/>
) : null} ) : null}
</div> </div>
); );
@@ -485,9 +451,9 @@ export function BillFormComponent({
}} }}
</Form.Item> </Form.Item>
</LayoutFormRow> </LayoutFormRow>
<Divider orientation="left">{t("bills.labels.bill_lines")}</Divider> <Divider orientation="left">{t('bills.labels.bill_lines')}</Divider>
{Extended_Bill_Posting.treatment === "on" ? ( {Extended_Bill_Posting.treatment === 'on' ? (
<BillFormLinesExtended <BillFormLinesExtended
lineData={lineData} lineData={lineData}
discount={discount} discount={discount}
@@ -505,11 +471,13 @@ export function BillFormComponent({
billEdit={billEdit} billEdit={billEdit}
/> />
)} )}
<Divider orientation="left" style={{ display: billEdit ? 'none' : null }}>
{t('documents.labels.upload')}
</Divider>
<Form.Item <Form.Item
name="upload" name="upload"
label="Upload" label="Upload"
style={{display: billEdit ? "none" : null}} style={{ display: billEdit ? 'none' : null }}
valuePropName="fileList" valuePropName="fileList"
getValueFromEvent={(e) => { getValueFromEvent={(e) => {
if (Array.isArray(e)) { if (Array.isArray(e)) {
@@ -518,19 +486,12 @@ export function BillFormComponent({
return e && e.fileList; return e && e.fileList;
}} }}
> >
<Upload.Dragger <Upload.Dragger multiple={true} name="logo" beforeUpload={() => false} listType="picture">
multiple={true}
name="logo"
beforeUpload={() => false}
listType="picture"
>
<> <>
<p className="ant-upload-drag-icon"> <p className="ant-upload-drag-icon">
<UploadOutlined/> <UploadOutlined />
</p>
<p className="ant-upload-text">
Click or drag files to this area to upload.
</p> </p>
<p className="ant-upload-text">Click or drag files to this area to upload.</p>
</> </>
</Upload.Dragger> </Upload.Dragger>
</Form.Item> </Form.Item>

View File

@@ -12,6 +12,7 @@ import "./chat-affix.styles.scss";
export function ChatAffixContainer({bodyshop, chatVisible}) { export function ChatAffixContainer({bodyshop, chatVisible}) {
const {t} = useTranslation(); const {t} = useTranslation();
const client = useApolloClient(); const client = useApolloClient();
useEffect(() => { useEffect(() => {
if (!bodyshop || !bodyshop.messagingservicesid) return; if (!bodyshop || !bodyshop.messagingservicesid) return;
@@ -31,6 +32,7 @@ export function ChatAffixContainer({bodyshop, chatVisible}) {
error error
); );
notification.open({ notification.open({
key: 'fcm',
type: "warning", type: "warning",
message: t("general.errors.fcm"), message: t("general.errors.fcm"),
btn: ( btn: (
@@ -62,7 +64,7 @@ export function ChatAffixContainer({bodyshop, chatVisible}) {
SubscribeToTopic(); SubscribeToTopic();
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, []); }, [bodyshop]);
useEffect(() => { useEffect(() => {
function handleMessage(payload) { function handleMessage(payload) {

View File

@@ -60,6 +60,10 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
text: t("courtesycars.status.in"), text: t("courtesycars.status.in"),
value: "courtesycars.status.in", value: "courtesycars.status.in",
}, },
{
text: t("courtesycars.status.inservice"),
value: "courtesycars.status.inservice",
},
{ {
text: t("courtesycars.status.out"), text: t("courtesycars.status.out"),
value: "courtesycars.status.out", value: "courtesycars.status.out",
@@ -73,7 +77,7 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
value: "courtesycars.status.leasereturn", value: "courtesycars.status.leasereturn",
}, },
], ],
onFilter: (value, record) => value.includes(record.status), onFilter: (value, record) => record.status === value,
sortOrder: sortOrder:
state.sortedInfo.columnKey === "status" && state.sortedInfo.order, state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
render: (text, record) => { render: (text, record) => {
@@ -176,7 +180,7 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
title: t("courtesycars.fields.fuel"), title: t("courtesycars.fields.fuel"),
dataIndex: "fuel", dataIndex: "fuel",
key: "fuel", key: "fuel",
sorter: (a, b) => alphaSort(a.fuel, b.fuel), sorter: (a, b) => a.fuel - b.fuel,
sortOrder: sortOrder:
state.sortedInfo.columnKey === "fuel" && state.sortedInfo.order, state.sortedInfo.columnKey === "fuel" && state.sortedInfo.order,
render: (text, record) => { render: (text, record) => {
@@ -185,12 +189,14 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
return t("courtesycars.labels.fuel.full"); return t("courtesycars.labels.fuel.full");
case 88: case 88:
return t("courtesycars.labels.fuel.78"); return t("courtesycars.labels.fuel.78");
case 75:
return t("courtesycars.labels.fuel.34");
case 63: case 63:
return t("courtesycars.labels.fuel.58"); return t("courtesycars.labels.fuel.58");
case 50: case 50:
return t("courtesycars.labels.fuel.12"); return t("courtesycars.labels.fuel.12");
case 38: case 38:
return t("courtesycars.labels.fuel.34"); return t("courtesycars.labels.fuel.38");
case 25: case 25:
return t("courtesycars.labels.fuel.14"); return t("courtesycars.labels.fuel.14");
case 13: case 13:

View File

@@ -23,7 +23,6 @@ export function JobEmployeeAssignments({
jobRO, jobRO,
body, body,
refinish, refinish,
prep, prep,
csr, csr,
handleAdd, handleAdd,
@@ -78,7 +77,7 @@ export function JobEmployeeAssignments({
setVisibility(false); setVisibility(false);
}} }}
> >
Assign {t("allocations.actions.assign")}
</Button> </Button>
<Button onClick={() => setVisibility(false)}>Close</Button> <Button onClick={() => setVisibility(false)}>Close</Button>
</Space> </Space>

View File

@@ -44,13 +44,13 @@ export function JobEmployeeAssignmentsContainer({
}); });
if (refetch) refetch(); if (refetch) refetch();
if (!!!result.errors) {
insertAuditTrail({ insertAuditTrail({
jobid: job.id, jobid: job.id,
operation: AuditTrailMapping.jobassignmentchange(operation, name), operation: AuditTrailMapping.jobassignmentchange(operation, name),
type: "jobassignmentchange", type: "jobassignmentchange",
}); });
} else {
if (!!result.errors) {
notification["error"]({ notification["error"]({
message: t("jobs.errors.assigning", { message: t("jobs.errors.assigning", {
message: JSON.stringify(result.errors), message: JSON.stringify(result.errors),
@@ -68,17 +68,19 @@ export function JobEmployeeAssignmentsContainer({
variables: {jobId: job.id, job: {[empAssignment]: null}}, variables: {jobId: job.id, job: {[empAssignment]: null}},
}); });
if (!!result.errors) { if (!!!result.errors) {
insertAuditTrail({
jobid: job.id,
operation: AuditTrailMapping.jobassignmentremoved(operation),
type: "jobassignmentremoved",
});
} else {
notification["error"]({ notification["error"]({
message: t("jobs.errors.assigning", { message: t("jobs.errors.assigning", {
message: JSON.stringify(result.errors), message: JSON.stringify(result.errors),
}), }),
}); });
} }
insertAuditTrail({
jobid: job.id,
operation: AuditTrailMapping.jobassignmentremoved(operation),
type: "jobassignmentremoved",});
setLoading(false); setLoading(false);
}; };

View File

@@ -82,7 +82,7 @@ export default function JobReconciliationBillsTable({
state.sortedInfo.order, state.sortedInfo.order,
render: (text, record) => ( render: (text, record) => (
<Checkbox disabled checked={record.bill.is_credit_memo}/> <Checkbox checked={record.bill.is_credit_memo}/>
), ),
}, },
]; ];

View File

@@ -217,6 +217,12 @@ export function JobsDetailHeader({job, bodyshop, disabled}) {
{job.owner?.tax_number || ""} {job.owner?.tax_number || ""}
</DataLabel> </DataLabel>
)} )}
<DataLabel
label={t("owners.fields.note")}
valueStyle={{ overflow: "hidden", textOverflow: "ellipsis" }}
>
{job.owner?.note || ""}
</DataLabel>
</div> </div>
</Card> </Card>
</Col> </Col>

View File

@@ -327,7 +327,7 @@ const {Enhanced_Payroll} = treatments;
onFilter: (value, record) => onFilter: (value, record) =>
value.includes(record.special_coverage_policy), value.includes(record.special_coverage_policy),
render: (text, record) => ( render: (text, record) => (
<Checkbox disabled checked={record.special_coverage_policy} /> <Checkbox checked={record.special_coverage_policy} />
), ),
}, },

View File

@@ -242,7 +242,7 @@ export function ShopInfoResponsibilityCenterComponent({bodyshop, form}) {
</Form.Item> </Form.Item>
<Space align="center"> <Space align="center">
d <DeleteFilled
onClick={() => { onClick={() => {
remove(field.name); remove(field.name);
}} }}

View File

@@ -1,14 +1,14 @@
import {HeartOutlined} from "@ant-design/icons"; import { HeartOutlined } from '@ant-design/icons';
import {Select, Space, Tag} from "antd"; import { Select, Space, Tag } from 'antd';
import React, {forwardRef, useEffect, useState} from "react"; import React, { forwardRef, useEffect, useState } from 'react';
import PhoneNumberFormatter from "../../utils/PhoneFormatter"; import PhoneNumberFormatter from '../../utils/PhoneFormatter';
const {Option} = Select; const { Option } = Select;
//To be used as a form element only. //To be used as a form element only.
const VendorSearchSelect = ( const VendorSearchSelect = (
{value, onChange, options, onSelect, disabled, preferredMake, showPhone}, { value, onChange, options, onSelect, disabled, preferredMake, showPhone },
ref ref
) => { ) => {
const [option, setOption] = useState(value); const [option, setOption] = useState(value);
@@ -23,9 +23,7 @@ const VendorSearchSelect = (
preferredMake && options preferredMake && options
? options.filter( ? options.filter(
(o) => (o) =>
o.favorite.filter( o.favorite.filter((f) => f.toLowerCase() === preferredMake.toLowerCase()).length > 0
(f) => f.toLowerCase() === preferredMake.toLowerCase()
).length > 0
) )
: []; : [];
@@ -35,30 +33,34 @@ const VendorSearchSelect = (
showSearch showSearch
value={option} value={option}
style={{ style={{
width: "100%", width: '100%',
}}
labelRender={({ label, value, ...rest }) => {
if (!value || !options) return label;
const discount = options?.find((o) => o.id === value)?.discount;
return (
<div className="imex-flex-row" style={{ width: '100%' }}>
<div style={{ flex: 1 }}>{label}</div>
{discount && discount !== 0 ? <Tag color="green">{`${discount * 100}%`}</Tag> : null}
</div>
);
}} }}
popupMatchSelectWidth={false} popupMatchSelectWidth={false}
onChange={setOption} onChange={setOption}
optionFilterProp="name" optionFilterProp="name"
onSelect={onSelect} onSelect={onSelect}
disabled={disabled || false} disabled={disabled || false}
optionLabelProp={"name"} optionLabelProp={'name'}
> >
{favorites {favorites
? favorites.map((o) => ( ? favorites.map((o) => (
<Option <Option key={`favorite-${o.id}`} value={o.id} name={o.name} discount={o.discount}>
key={`favorite-${o.id}`}
value={o.id}
name={o.name}
discount={o.discount}
>
<div className="imex-flex-row"> <div className="imex-flex-row">
<div style={{flex: 1}}>{o.name}</div> <div style={{ flex: 1 }}>{o.name}</div>
<Space style={{marginLeft: "1rem"}}> <Space style={{ marginLeft: '1rem' }}>
<HeartOutlined style={{color: "red"}}/> <HeartOutlined style={{ color: 'red' }} />
{o.phone && showPhone && ( {o.phone && showPhone && <PhoneNumberFormatter>{o.phone}</PhoneNumberFormatter>}
<PhoneNumberFormatter>{o.phone}</PhoneNumberFormatter>
)}
{o.discount && o.discount !== 0 ? ( {o.discount && o.discount !== 0 ? (
<Tag color="green">{`${o.discount * 100}%`}</Tag> <Tag color="green">{`${o.discount * 100}%`}</Tag>
) : null} ) : null}
@@ -70,20 +72,17 @@ const VendorSearchSelect = (
{options {options
? options.map((o) => ( ? options.map((o) => (
<Option key={o.id} value={o.id} name={o.name} discount={o.discount}> <Option key={o.id} value={o.id} name={o.name} discount={o.discount}>
<div className="imex-flex-row" style={{width: "100%"}}> <div className="imex-flex-row" style={{ width: '100%' }}>
<div style={{flex: 1}}>{o.name}</div> <div style={{ flex: 1 }}>{o.name}</div>
<Space style={{marginLeft: "1rem"}}> <Space style={{ marginLeft: '1rem' }}>
{o.phone && showPhone && ( {o.phone && showPhone && <PhoneNumberFormatter>{o.phone}</PhoneNumberFormatter>}
<PhoneNumberFormatter>{o.phone}</PhoneNumberFormatter>
)}
{o.discount && o.discount !== 0 ? ( {o.discount && o.discount !== 0 ? (
<Tag color="green">{`${o.discount * 100}%`}</Tag> <Tag color="green">{`${o.discount * 100}%`}</Tag>
) : null} ) : null}
</Space> </Space>
</div> </div>
</Option> </Option>
)) ))
: null} : null}
</Select> </Select>

View File

@@ -721,6 +721,7 @@ export const GET_JOB_BY_PK = gql`
other_amount_payable other_amount_payable
owner { owner {
id id
note
ownr_addr1 ownr_addr1
ownr_addr2 ownr_addr2
ownr_city ownr_city

View File

@@ -126,7 +126,7 @@ export function BillsListPage({
state.sortedInfo.columnKey === "is_credit_memo" && state.sortedInfo.columnKey === "is_credit_memo" &&
state.sortedInfo.order, state.sortedInfo.order,
render: (text, record) => ( render: (text, record) => (
<Checkbox disabled checked={record.is_credit_memo}/> <Checkbox checked={record.is_credit_memo}/>
), ),
}, },
{ {
@@ -136,7 +136,7 @@ export function BillsListPage({
sorter: (a, b) => a.exported - b.exported, sorter: (a, b) => a.exported - b.exported,
sortOrder: sortOrder:
state.sortedInfo.columnKey === "exported" && state.sortedInfo.order, state.sortedInfo.columnKey === "exported" && state.sortedInfo.order,
render: (text, record) => <Checkbox disabled checked={record.exported}/>, render: (text, record) => <Checkbox checked={record.exported}/>,
}, },
{ {
title: t("general.labels.actions"), title: t("general.labels.actions"),

View File

@@ -162,9 +162,7 @@ sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
{ text: "False", value: false }, { text: "False", value: false },
], ],
onFilter: (value, record) => record.successful === value, onFilter: (value, record) => record.successful === value,
render: (text, record) => ( render: (text, record) => <Checkbox checked={record.successful} />,
<Checkbox disabled checked={record.successful}/>
),
}, },
{ {
title: t("general.labels.message"), title: t("general.labels.message"),

View File

@@ -371,8 +371,9 @@ export function JobsCloseComponent({job, bodyshop, jobRO, insertAuditTrail}) {
</Form.Item> </Form.Item>
)} )}
</LayoutFormRow> </LayoutFormRow>
<Divider>{t("jobs.labels.multipayers")}</Divider>
{Qb_Multi_Ar.treatment === "on" && ( {Qb_Multi_Ar.treatment === "on" && (
<><Divider>{t("jobs.labels.multipayers")}</Divider>
<Row gutter={[16, 16]}> <Row gutter={[16, 16]}>
<Col lg={8} md={24}> <Col lg={8} md={24}>
<Form.List <Form.List
@@ -451,7 +452,9 @@ export function JobsCloseComponent({job, bodyshop, jobRO, insertAuditTrail}) {
<DeleteFilled <DeleteFilled
disabled={jobRO} disabled={jobRO}
onClick={() => { onClick={() => {
if(!jobRO){
remove(field.name); remove(field.name);
}
}} }}
/> />
</Space> </Space>
@@ -529,6 +532,7 @@ export function JobsCloseComponent({job, bodyshop, jobRO, insertAuditTrail}) {
</Form.Item> </Form.Item>
</Col> </Col>
</Row> </Row>
</>
)} )}
<Divider/> <Divider/>
<JobsCloseLines job={job}/> <JobsCloseLines job={job}/>

View File

@@ -332,7 +332,7 @@ export function JobsDetailPage({
{ {
key: "partssublet", key: "partssublet",
icon: <ToolFilled/>, icon: <ToolFilled/>,
label: t("menus.jobsdetail.partssublet"), label: HasFeatureAccess({featureName: "bills", bodyshop}) ? t("menus.jobsdetail.partssublet") : t("menus.jobsdetail.parts"),
children: <JobsDetailPliContainer job={job}/>, children: <JobsDetailPliContainer job={job}/>,
}, },
...InstanceRenderManager({ imex: true, rome: true, promanager: HasFeatureAccess({ featureName: 'timetickets', bodyshop }) }) ? [ { ...InstanceRenderManager({ imex: true, rome: true, promanager: HasFeatureAccess({ featureName: 'timetickets', bodyshop }) }) ? [ {

View File

@@ -541,13 +541,12 @@ export function Manage({conflict, bodyshop,enableJoyRide,joyRideSteps,setJoyRide
}} }}
> >
<div style={{ display: 'flex' }}> <div style={{ display: 'flex' }}>
{`Joy Ride Status: ${enableJoyRide}`}
<div> <div>
{`${InstanceRenderManager({ {`${InstanceRenderManager({
imex: t('titles.imexonline'), imex: t('titles.imexonline'),
rome: t('titles.romeonline'), rome: t('titles.romeonline'),
promanager: t('titles.promanager'), promanager: t('titles.promanager'),
})} ${import.meta.env.VITE_APP_GIT_SHA || 'Local Build'} - ${ })} - ${
import.meta.env.VITE_APP_GIT_SHA_DATE import.meta.env.VITE_APP_GIT_SHA_DATE
}`} }`}
</div> </div>

View File

@@ -47,6 +47,7 @@ import client from "../../utils/GraphQLClient";
import {QUERY_EULA} from "../../graphql/bodyshop.queries"; import {QUERY_EULA} from "../../graphql/bodyshop.queries";
import day from "../../utils/day"; import day from "../../utils/day";
import InstanceRenderManager from "../../utils/instanceRenderMgr"; import InstanceRenderManager from "../../utils/instanceRenderMgr";
import { Userpilot } from "userpilot";
const fpPromise = FingerprintJS.load(); const fpPromise = FingerprintJS.load();
@@ -227,6 +228,15 @@ export function* signInSuccessSaga({payload}) {
window.$crisp.push(['set', 'user:nickname', [payload.displayName || payload.email]]); window.$crisp.push(['set', 'user:nickname', [payload.displayName || payload.email]]);
window.$crisp.push(['set', 'session:segments', [['user']]]); window.$crisp.push(['set', 'session:segments', [['user']]]);
}, },
promanager: () =>{
Userpilot.identify(
payload.email,
{
email: payload.email,
}
);
console.log("*** Userpilot identified.")
}
}); });
} catch (error) { } catch (error) {

View File

@@ -1165,6 +1165,7 @@
"loadingshop": "Loading shop data...", "loadingshop": "Loading shop data...",
"loggingin": "Authorizing...", "loggingin": "Authorizing...",
"markedexported": "Manually marked as exported.", "markedexported": "Manually marked as exported.",
"media": "Media",
"message": "Message", "message": "Message",
"monday": "Monday", "monday": "Monday",
"na": "N/A", "na": "N/A",
@@ -2174,6 +2175,7 @@
"insurance": "Insurance Information", "insurance": "Insurance Information",
"labor": "Labor", "labor": "Labor",
"lifecycle": "Lifecycle", "lifecycle": "Lifecycle",
"parts": "Parts",
"partssublet": "Parts & Bills", "partssublet": "Parts & Bills",
"rates": "Rates", "rates": "Rates",
"repairdata": "Repair Data", "repairdata": "Repair Data",

View File

@@ -2174,6 +2174,7 @@
"insurance": "", "insurance": "",
"labor": "Labor", "labor": "Labor",
"lifecycle": "", "lifecycle": "",
"parts": "",
"partssublet": "Piezas / Subarrendamiento", "partssublet": "Piezas / Subarrendamiento",
"rates": "", "rates": "",
"repairdata": "Datos de reparación", "repairdata": "Datos de reparación",

View File

@@ -2174,6 +2174,7 @@
"insurance": "", "insurance": "",
"labor": "La main d'oeuvre", "labor": "La main d'oeuvre",
"lifecycle": "", "lifecycle": "",
"parts": "",
"partssublet": "Pièces / Sous-location", "partssublet": "Pièces / Sous-location",
"rates": "", "rates": "",
"repairdata": "Données de réparation", "repairdata": "Données de réparation",

View File

@@ -105,6 +105,9 @@ export default defineConfig({
react(), react(),
// CompressionPlugin(), //Cloudfront already compresses assets, so not needed. // CompressionPlugin(), //Cloudfront already compresses assets, so not needed.
], ],
define:{
"APP_VERSION": JSON.stringify(process.env.npm_package_version)
},
server: { server: {
host: true, host: true,
port: 3000, port: 3000,

View File

@@ -832,6 +832,13 @@
table: table:
name: ioevents name: ioevents
schema: public schema: public
- name: ioevents
using:
foreign_key_constraint_on:
column: bodyshopid
table:
name: ioevents
schema: public
- name: jobs - name: jobs
using: using:
foreign_key_constraint_on: foreign_key_constraint_on:
@@ -867,6 +874,13 @@
table: table:
name: tasks name: tasks
schema: public schema: public
- name: tasks
using:
foreign_key_constraint_on:
column: bodyshopid
table:
name: tasks
schema: public
- name: timetickets - name: timetickets
using: using:
foreign_key_constraint_on: foreign_key_constraint_on:
@@ -3353,6 +3367,13 @@
table: table:
name: tasks name: tasks
schema: public schema: public
- name: tasks
using:
foreign_key_constraint_on:
column: jobid
table:
name: tasks
schema: public
- name: timetickets - name: timetickets
using: using:
foreign_key_constraint_on: foreign_key_constraint_on:
@@ -5057,6 +5078,13 @@
table: table:
name: tasks name: tasks
schema: public schema: public
- name: tasks
using:
foreign_key_constraint_on:
column: partsorderid
table:
name: tasks
schema: public
insert_permissions: insert_permissions:
- role: user - role: user
permission: permission:

View File

@@ -0,0 +1 @@
DROP TABLE "public"."tasks";

View File

@@ -0,0 +1,18 @@
CREATE TABLE "public"."tasks" ("id" uuid NOT NULL DEFAULT gen_random_uuid(), "created_at" timestamptz NOT NULL DEFAULT now(), "updated_at" timestamptz NOT NULL DEFAULT now(), "title" text NOT NULL, "description" Text, "deleted" boolean NOT NULL DEFAULT false, "deleted_at" timestamptz, "due_date" timestamptz, "created_by" text NOT NULL, "assigned_to" Text, "completed" boolean NOT NULL DEFAULT false, "completed_at" timestamptz, "remind_at" timestamptz, "priority" numeric, "bodyshopid" UUID NOT NULL, "jobid" UUID NOT NULL, "joblineid" UUID, "partsorderid" UUID, "billid" UUID, PRIMARY KEY ("id") , FOREIGN KEY ("created_by") REFERENCES "public"."users"("email") ON UPDATE restrict ON DELETE restrict, FOREIGN KEY ("assigned_to") REFERENCES "public"."users"("email") ON UPDATE restrict ON DELETE restrict, FOREIGN KEY ("bodyshopid") REFERENCES "public"."bodyshops"("id") ON UPDATE restrict ON DELETE restrict, FOREIGN KEY ("jobid") REFERENCES "public"."jobs"("id") ON UPDATE cascade ON DELETE cascade, FOREIGN KEY ("joblineid") REFERENCES "public"."joblines"("id") ON UPDATE set null ON DELETE set null, FOREIGN KEY ("partsorderid") REFERENCES "public"."parts_orders"("id") ON UPDATE set null ON DELETE set null, FOREIGN KEY ("billid") REFERENCES "public"."bills"("id") ON UPDATE set null ON DELETE set null);
CREATE OR REPLACE FUNCTION "public"."set_current_timestamp_updated_at"()
RETURNS TRIGGER AS $$
DECLARE
_new record;
BEGIN
_new := NEW;
_new."updated_at" = NOW();
RETURN _new;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER "set_public_tasks_updated_at"
BEFORE UPDATE ON "public"."tasks"
FOR EACH ROW
EXECUTE PROCEDURE "public"."set_current_timestamp_updated_at"();
COMMENT ON TRIGGER "set_public_tasks_updated_at" ON "public"."tasks"
IS 'trigger to set value of column "updated_at" to current timestamp on row update';
CREATE EXTENSION IF NOT EXISTS pgcrypto;

View File

@@ -16,7 +16,7 @@ const CalculateAllocations =
const CdkBase = require("../../web-sockets/web-socket"); const CdkBase = require("../../web-sockets/web-socket");
const moment = require("moment-timezone"); const moment = require("moment-timezone");
const Dinero = require("dinero.js"); const Dinero = require("dinero.js");
const { default: InstanceManager } = require("../../utils/instanceMgr").default; const InstanceManager = require("../../utils/instanceMgr").default;
const axios = AxiosLib.create(); const axios = AxiosLib.create();
axios.interceptors.request.use((x) => { axios.interceptors.request.use((x) => {
@@ -661,7 +661,7 @@ async function InsertAccountPostingData(socket) {
.toISOString(), //"0001-01-01T00:00:00.0000000Z", .toISOString(), //"0001-01-01T00:00:00.0000000Z",
Description: socket.txEnvelope.story, Description: socket.txEnvelope.story,
//AdditionalInfo: "String", //AdditionalInfo: "String",
Source: InstanceManager({imex: t("titles.imexonline"), rome:t("titles.romeonline")}), Source: InstanceManager({imex: "ImEX Online", rome:"Rome Online"}),
Lines: wips, Lines: wips,
}, },
}, },