Compare commits

..

57 Commits

Author SHA1 Message Date
Allan Carr
33ec18986d IO-2556 CC Sort Order
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-02-20 13:10:57 -08:00
Allan Carr
2427c14b7b Merged in release/2024-02-16 (pull request #1296)
IO-2631 Correct Import Statement for moment

Approved-by: Dave Richer
2024-02-16 21:37:49 +00:00
Allan Carr
66655d449e Merged in feature/IO-2631-Update-Schedule-Completion-on-Import (pull request #1294)
IO-2631 Correct Import Statement for moment

Approved-by: Dave Richer
2024-02-16 20:33:05 +00:00
Allan Carr
845a84c4c8 IO-2631 Correct Import Statement for moment 2024-02-16 12:30:12 -08:00
Dave Richer
0ff5ea3d59 Merged in release/2024-02-16 (pull request #1291)
Release/2024 02 16

Approved-by: Patrick Fic
2024-02-16 20:21:35 +00:00
Allan Carr
09492e647e Merged in feature/IO-2631-Update-Schedule-Completion-on-Import (pull request #1292)
IO-2631 Correct for Business Days

Approved-by: Dave Richer
2024-02-16 19:19:08 +00:00
Allan Carr
2d6594cc73 IO-2631 Correct for Business Days 2024-02-16 11:08:59 -08:00
Allan Carr
601fdbba39 Merged in feature/IO-2637-Add-Scoreboard-Date (pull request #1287)
IO-2637 Correct for Timezone offset

Approved-by: Dave Richer
2024-02-16 17:23:05 +00:00
Allan Carr
830adc4ef3 IO-2637 Correct for Timezone offset 2024-02-16 08:52:33 -08:00
Dave Richer
3f216195ca Merge branch 'feature/IO-2456-Report-Filters-From-Master' into release/2024-02-16 2024-02-15 21:03:30 -05:00
Dave Richer
bcb8de0937 - Fix issues with labels on sorters
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-02-15 21:03:04 -05:00
Dave Richer
4c07632ee6 Merged in feature/IO-2456-Report-Filters-From-Master (pull request #1283)
- Report Center Filters Version 1 retargeted to Master

Approved-by: Patrick Fic
2024-02-15 17:32:38 +00:00
Dave Richer
767c219af8 - Remove additional console.log
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-02-15 11:59:56 -05:00
Dave Richer
cfc301570e - Remove redundant CSS
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-02-15 11:57:27 -05:00
Allan Carr
fb718f9f37 Merged in feature/IO-2631-Update-Schedule-Completion-on-Import (pull request #1284)
IO-2631 Update Scheduled Completion on Supp

Approved-by: Dave Richer
2024-02-15 16:53:41 +00:00
Dave Richer
cafc0e5628 - Update GUI and provide loading state
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-02-15 11:49:02 -05:00
Dave Richer
a635725839 - Remove console.log statements
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-02-15 10:58:19 -05:00
Allan Carr
eb8e9b10ef IO-2631 Update Scheduled Completion on Supp 2024-02-14 16:47:25 -08:00
Dave Richer
2584f7129c - Report Center Filters Version 1 retargeted to Master
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-02-14 14:31:35 -05:00
Allan Carr
6c996037d6 Merged in release/2024-02-02 (pull request #1274)
Release/2024 02 02

Approved-by: Patrick Fic
2024-02-09 18:47:24 +00:00
Allan Carr
f421b45222 Merged in feature/IO-2630-Parts-Queue-Mods (pull request #1272)
IO-2630 Adjust Query to match Tags
2024-02-09 17:54:46 +00:00
Allan Carr
30cf46a158 IO-2630 Adjust Query to match Tags 2024-02-09 09:54:22 -08:00
Allan Carr
8d37c54f89 Merged in feature/IO-2630-Parts-Queue-Mods (pull request #1269)
Feature/IO-2630 Parts Queue Mods

Approved-by: Dave Richer
2024-02-09 16:14:51 +00:00
Allan Carr
f9b9f39418 IO-2630 Add in Drawer for Parts Queue 2024-02-08 17:18:14 -08:00
Allan Carr
05a5df789b IO-2030 Change & Add Columns, Add Sorters and Filters 2024-02-08 13:22:00 -08:00
Allan Carr
bed87eda97 Merged in feature/IO-2626-CSI-Pages (pull request #1267)
IO-2626 Adjust Image Prop on customer page
2024-02-08 17:58:21 +00:00
Allan Carr
67008c35b8 IO-2626 Adjust Image Prop on customer page 2024-02-08 09:57:39 -08:00
Patrick Fic
9b95e40a13 Merge branch 'release/2024-02-02' of bitbucket.org:snaptsoft/bodyshop into release/2024-02-02 2024-02-06 10:05:26 -08:00
Patrick Fic
e3a998b6f8 Merge branch 'feature/IO-2626-CSI-Pages' into release/2024-02-02 2024-02-06 10:05:11 -08:00
Patrick Fic
3c7ede0155 IO-2626 Prevent crisp from loading on anon CSI page. 2024-02-06 10:04:59 -08:00
Allan Carr
82c7aa1347 Merged in feature/IO-2626-CSI-Pages (pull request #1265)
IO-2626 Resource Class for Test
2024-02-06 17:37:46 +00:00
Allan Carr
4ccd912363 Merge branch 'feature/IO-2626-CSI-Pages' of bitbucket.org:snaptsoft/bodyshop into feature/IO-2626-CSI-Pages 2024-02-06 09:36:16 -08:00
Patrick Fic
c0525842fd Merge branch 'feature/IO-2626-CSI-Pages' into release/2024-02-02 2024-02-06 09:29:39 -08:00
Patrick Fic
dd5ca5d233 Add resource class to test build as well. 2024-02-06 09:29:22 -08:00
Allan Carr
616a4b04a0 IO-2626 Resource Class for Test 2024-02-06 09:10:32 -08:00
Allan Carr
9a34640c88 Merged in feature/IO-2626-CSI-Pages (pull request #1263)
IO-2626 CICD Resource Size Change
2024-02-06 16:55:55 +00:00
Allan Carr
3110be4703 IO-2626 CICD Resource Size Change 2024-02-06 08:52:51 -08:00
Allan Carr
971c8d41ff Merged in feature/IO-2626-CSI-Pages (pull request #1253)
IO-2626 CSI Pages
2024-02-06 16:17:50 +00:00
Allan Carr
7c303a5154 IO-2626 Change Server Variable Name for response 2024-02-05 20:06:28 -08:00
Allan Carr
9383b37a41 IO-2626 Modify seachparm and fix linking 2024-02-05 20:03:17 -08:00
Allan Carr
205d507097 IO-2626 Update Translations 2024-02-02 22:50:40 -08:00
Allan Carr
97a1bd66d1 IO-2626 Correct Sorting, Linking, Pagination and Update Response Container 2024-02-02 22:45:06 -08:00
Allan Carr
0d1ff6390c IO-2626 Correct Error Page footer 2024-02-02 12:35:18 -08:00
Allan Carr
830d2c87d2 IO-2626 CSI Pages
Move to Server side initial commit
2024-02-02 11:55:57 -08:00
Allan Carr
da98e7b886 Merged in feature/IO-2624-Federal-Tax-Exempt-Destructure (pull request #1251)
IO-2624 federal_tax_exempt destructure

Approved-by: Dave Richer
2024-02-02 17:18:24 +00:00
Allan Carr
a74a9ba5a1 IO-2624 federal_tax_exempt destructure 2024-01-31 09:59:56 -08:00
Patrick Fic
b8a3081488 Merged in feature/Sentry-Improvements (pull request #1247)
Change tracing targets.
2024-01-31 01:09:03 +00:00
Patrick Fic
c8fc1b0f68 Merged in feature/Sentry-Improvements (pull request #1246)
Change tracing targets.
2024-01-31 01:08:37 +00:00
Patrick Fic
da1ddb874f Change tracing targets. 2024-01-30 16:58:11 -08:00
Patrick Fic
771f9ceaa8 Merged in feature/Sentry-Improvements (pull request #1242)
Feature/Sentry Improvements
2024-01-30 21:45:22 +00:00
Patrick Fic
9b61da5c62 Merged in feature/Sentry-Improvements (pull request #1239)
Feature/Sentry Improvements
2024-01-30 21:42:33 +00:00
Patrick Fic
7daf7540b3 Resolve Typo in CI. 2024-01-30 13:32:58 -08:00
Patrick Fic
ce6940629d Exclude source map upload in CI. 2024-01-30 13:25:48 -08:00
Patrick Fic
b706b96d32 Remove sentry test button. 2024-01-30 13:14:27 -08:00
Patrick Fic
2427bc72f2 Updated CI. 2024-01-30 12:53:07 -08:00
Patrick Fic
8bc1a9d9ee Initial sentry improvements to deploy and verify against test. 2024-01-30 12:47:12 -08:00
Patrick Fic
ba30225ba1 Merged in release/2024-01-29 (pull request #1230)
IO-1532 resolve update logic issue for status timings.
2024-01-29 17:06:31 +00:00
189 changed files with 4574 additions and 18148 deletions

View File

@@ -42,185 +42,23 @@ jobs:
app-build:
docker:
- image: cimg/node:16.15.0
resource_class: large
working_directory: ~/repo/client
steps:
- checkout:
path: ~/repo
- restore_cache:
name: Restore Yarn Package Cache
keys:
- yarn-packages-{{ checksum "yarn.lock" }}
- run:
name: Install Dependencies
command: yarn install --frozen-lockfile --cache-folder ~/.cache/yarn
- save_cache:
name: Save Yarn Package Cache
key: yarn-packages-{{ checksum "yarn.lock" }}
paths:
- ~/.cache/yarn
command: npm i
- run: yarn run build
- run: npm run build
- aws-s3/sync:
from: build
to: "s3://imex-online-production/"
arguments: "--exclude '*.map'"
- jira/notify
rome-api-deploy:
docker:
- image: "cimg/base:stable"
steps:
- checkout
- eb/setup
- run:
command: |
eb init romeonline-productionapi -r us-east-2 -p "Node.js 18 running on 64bit Amazon Linux 2"
eb status --verbose
eb deploy
eb status
- jira/notify
rome-hasura-migrate:
docker:
- image: cimg/node:16.15.0
parameters:
secret:
type: string
default: $HASURA_PROD_SECRET
working_directory: ~/repo/hasura
steps:
- checkout:
path: ~/repo
- run:
name: Execute migration
command: |
npm install hasura-cli -g
hasura migrate apply --endpoint https://db.romeonline.io/ --admin-secret << parameters.secret >>
hasura metadata apply --endpoint https://db.romeonline.io/ --admin-secret << parameters.secret >>
hasura metadata reload --endpoint https://db.romeonline.io/ --admin-secret << parameters.secret >>
rome-app-build:
docker:
- image: cimg/node:16.15.0
working_directory: ~/repo/client
steps:
- checkout:
path: ~/repo
- restore_cache:
name: Restore Yarn Package Cache
keys:
- yarn-packages-{{ checksum "yarn.lock" }}
- run:
name: Install Dependencies
command: yarn install --frozen-lockfile --cache-folder ~/.cache/yarn
- save_cache:
name: Save Yarn Package Cache
key: yarn-packages-{{ checksum "yarn.lock" }}
paths:
- ~/.cache/yarn
- run: yarn run build
- aws-s3/sync:
from: build
to: "s3://rome-online-production/"
- jira/notify
test-rome-hasura-migrate:
docker:
- image: cimg/node:16.15.0
parameters:
secret:
type: string
default: $HASURA_ROME_TEST_SECRET
working_directory: ~/repo/hasura
steps:
- checkout:
path: ~/repo
- run:
name: Execute migration
command: |
npm install hasura-cli -g
echo ${HASURA_TEST_SECRET}
hasura migrate apply --endpoint https://db.test.romeonline.io/ --admin-secret << parameters.secret >>
hasura metadata apply --endpoint https://db.test.romeonline.io/ --admin-secret << parameters.secret >>
hasura metadata reload --endpoint https://db.test.romeonline.io/ --admin-secret << parameters.secret >>
test-rome-app-build:
docker:
- image: cimg/node:16.15.0
working_directory: ~/repo/client
steps:
- checkout:
path: ~/repo
- restore_cache:
name: Restore Yarn Package Cache
keys:
- yarn-packages-{{ checksum "yarn.lock" }}
- run:
name: Install Dependencies
command: yarn install --frozen-lockfile --cache-folder ~/.cache/yarn
- save_cache:
name: Save Yarn Package Cache
key: yarn-packages-{{ checksum "yarn.lock" }}
paths:
- ~/.cache/yarn
- run: yarn run build:test
- aws-s3/sync:
from: build
to: "s3://rome-online-test/"
- jira/notify
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
- aws-s3/sync:
from: build
to: "s3://imex-online-beta/"
- jira/notify
rome-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
- aws-s3/sync:
from: build
to: "s3://rome-online-production-beta/"
- jira/notify
test-hasura-migrate:
docker:
@@ -245,76 +83,24 @@ jobs:
test-app-build:
docker:
- image: cimg/node:16.15.0
resource_class: large
working_directory: ~/repo/client
steps:
- checkout:
path: ~/repo
- restore_cache:
name: Restore Yarn Package Cache
keys:
- yarn-packages-{{ checksum "yarn.lock" }}
- run:
name: Install Dependencies
command: yarn install --frozen-lockfile --cache-folder ~/.cache/yarn
- save_cache:
name: Save Yarn Package Cache
key: yarn-packages-{{ checksum "yarn.lock" }}
paths:
- ~/.cache/yarn
command: npm i
- run: yarn run build:test
- run: npm run build:test
- aws-s3/sync:
from: build
to: "s3://imex-online-test/"
arguments: "--exclude '*.map'"
- jira/notify
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
- aws-s3/sync:
from: build
to: "s3://imex-online-test-beta/"
- jira/notify
rome-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
- aws-s3/sync:
from: build
to: "s3://rome-online-test-beta/"
- jira/notify
admin-app-build:
docker:
- image: cimg/node:16.15.0
@@ -356,59 +142,21 @@ workflows:
filters:
branches:
only: master
- app-beta-build:
filters:
branches:
only: master-beta
- rome-app-beta-build:
filters:
branches:
only: rome/master-beta
- hasura-migrate:
secret: ${HASURA_PROD_SECRET}
filters:
branches:
only: master
- rome-api-deploy:
filters:
branches:
only: rome/master
- rome-app-build:
filters:
branches:
only: rome/master
- rome-hasura-migrate:
secret: ${HASURA_PROD_SECRET}
filters:
branches:
only: rome/master
- test-app-build:
filters:
branches:
only: test
- rome-test-app-beta-build:
filters:
branches:
only: rome/test-beta
- test-app-beta-build:
filters:
branches:
only: test-beta
- test-hasura-migrate:
secret: ${HASURA_TEST_SECRET}
filters:
branches:
only: test
- test-rome-app-build:
filters:
branches:
only: rome/test
- test-rome-hasura-migrate:
secret: ${HASURA_ROME_TEST_SECRET}
filters:
branches:
only: rome/test
#- admin-app-build:
#filters:
#branches:
#only: master
#only: master

View File

@@ -0,0 +1,120 @@
# Filters and Sorters
This documentation details the schema required for `.filters` files on the report server. It is used to dynamically
modify the graphQL query and provide the user more power over their reports.
## High level Schema Overview
```javascript
const schema = {
"filters": [
{
"name": "jobs.joblines.mod_lb_hrs", // Name and path of the field in the graphQL query
"translation": "jobs.joblines.mod_lb_hrs_1", // Translation key for the label used in the GUI
"label": "mod_lb_hrs_1", // Label used in the case the GUI does not contain a translation
"type": "number" // Type of field, can be number or string currently
},
// ... more filters
],
"sorters": [
{
"name": "jobs.joblines.mod_lb_hrs", // Name and path of the field in the graphQL query
"translation": "jobs.joblines.mod_lb_hrs_1", // Translation key for the label used in the GUI
"label": "mod_lb_hrs_1", // Label used in the case the GUI does not contain a translation
"type": "number" // Type of field, can be number or string currently
},
// ... more sorters
],
"dates": {
// This is not yet implemented and will be added in a future release
}
}
```
## Filters
Filters effect the where clause of the graphQL query. They are used to filter the data returned from the server.
A note on special notation used in the `name` field.
### Path without brackets, multi level
`"name": "jobs.joblines.mod_lb_hrs",`
This will produce a where clause at the `joblines` level of the graphQL query,
```graphql
query gendoc_hours_sold_detail_open($starttz: timestamptz!, $endtz: timestamptz!) {
jobs(
where: {date_invoiced: {_is_null: true}, date_open: {_gte: $starttz, _lte: $endtz}, ro_number: {_is_null: false}, voided: {_eq: false}}
) {
joblines(
order_by: {line_no: asc}
where: {removed: {_eq: false}, mod_lb_hrs: {_lt: 3}}
) {
line_no
mod_lbr_ty
mod_lb_hrs
convertedtolbr
convertedtolbr_data
}
ownr_co_nm
ownr_fn
ownr_ln
plate_no
ro_number
status
v_make_desc
v_model_desc
v_model_yr
v_vin
v_color
}
}
```
### Path with brackets,top level
`"name": "[jobs].joblines.mod_lb_hrs",`
This will produce a where clause at the `jobs` level of the graphQL query.
```graphql
query gendoc_hours_sold_detail_open($starttz: timestamptz!, $endtz: timestamptz!) {
jobs(
where: {date_invoiced: {_is_null: true}, date_open: {_gte: $starttz, _lte: $endtz}, ro_number: {_is_null: false}, voided: {_eq: false}, joblines: {mod_lb_hrs: {_gt: 4}}}
) {
joblines(
order_by: {line_no: asc}
where: {removed: {_eq: false}}
) {
line_no
mod_lbr_ty
mod_lb_hrs
convertedtolbr
convertedtolbr_data
}
ownr_co_nm
ownr_fn
ownr_ln
plate_no
ro_number
status
v_make_desc
v_model_desc
v_model_yr
v_vin
v_color
}
}
```
## Known Caveats
- Will only support two level of nesting in the graphQL query `jobs.joblines.mod_lb_hrs` vs `[jobs].joblines.mod_lb_hrs` is fine, but `jobs.[joblines.].some_table.mod_lb_hrs` is not.
- The `dates` object is not yet implemented and will be added in a future release.
- The type object must be 'string' or 'number' and is case-sensitive.
- The `translation` key is used to look up the label in the GUI, if it is not found, the `label` key is used.
- Do not add the ability to filter things that are already filtered as part of the original query, this would be redundant and could cause issues.
- Do not add the ability to filter on things like FK constraints, must like the above example.
## Sorters
- Sorters follow the same schema as filters, however, they do not do square bracket wrapping to indicate level hoisting, a filter added on `job.md_status` would be added at the top level, and a filter added on `jobs.joblines.mod_lb_hrs` would be added at the `joblines` level.
- Most of the reports currently do sorting on a template level, this will need to change to actually see the results using the sorters.

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1,13 @@
REACT_APP_GRAPHQL_ENDPOINT=https://db.dev.bodyshop.app/v1/graphql
REACT_APP_GRAPHQL_ENDPOINT_WS=wss://db.dev.bodyshop.app/v1/graphql
REACT_APP_GA_CODE=231099835
REACT_APP_FIREBASE_CONFIG={ "apiKey": "AIzaSyAuLQR9SV5LsVxjU8wh9hvFLdhcAHU6cxE", "authDomain": "rome-prod-1.firebaseapp.com", "projectId": "rome-prod-1", "storageBucket": "rome-prod-1.appspot.com", "messagingSenderId": "147786367145", "appId": "1:147786367145:web:9d4cba68071c3f29a8a9b8", "measurementId": "G-G8Z9DRHTZS"}
REACT_APP_FIREBASE_CONFIG={"apiKey":"AIzaSyDPLT8GiDHDR1R4nI66Qi0BY1aYviDPioc","authDomain":"imex-dev.firebaseapp.com","databaseURL":"https://imex-dev.firebaseio.com","projectId":"imex-dev","storageBucket":"imex-dev.appspot.com","messagingSenderId":"759548147434","appId":"1:759548147434:web:e8239868a48ceb36700993","measurementId":"G-K5XRBVVB4S"}
REACT_APP_CLOUDINARY_ENDPOINT_API=https://api.cloudinary.com/v1_1/io-test
REACT_APP_CLOUDINARY_ENDPOINT=https://res.cloudinary.com/io-test
REACT_APP_CLOUDINARY_API_KEY=957865933348715
REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS=c_fill,h_250,w_250
REACT_APP_FIREBASE_PUBLIC_VAPID_KEY='BP1B7ZTYpn-KMt6nOxlld6aS8Skt3Q7ZLEqP0hAvGHxG4UojPYiXZ6kPlzZkUC5jH-EcWXomTLtmadAIxurfcHo'
REACT_APP_FIREBASE_PUBLIC_VAPID_KEY='BG3tzU7L2BXlGZ_3VLK4PNaRceoEXEnmHfxcVbRMF5o5g05ejslhVPki9kBM9cBBT-08Ad9kN3HSpS6JmrWD6h4'
REACT_APP_STRIPE_PUBLIC_KEY=pk_test_51GqB4TJl3nQjrZ0wCQWAxAhlNF8jKe0tipIa6ExBaxwJGitwvFsIZUEua4dUzaMIAuXp4qwYHXx7lgjyQSwP0Pe900vzm38C7g
REACT_APP_AXIOS_BASE_API_URL=http://localhost:4000
REACT_APP_REPORTS_SERVER_URL=https://reports3.test.imex.online
REACT_APP_SPLIT_API=ts615lqgnmk84thn72uk18uu5pgce6e0l4rc
REACT_APP_COUNTRY=USA
REACT_APP_SPLIT_API=ts615lqgnmk84thn72uk18uu5pgce6e0l4rc

View File

@@ -1,13 +1,14 @@
REACT_APP_GRAPHQL_ENDPOINT=https://db.romeonline.io/v1/graphql
REACT_APP_GRAPHQL_ENDPOINT_WS=wss://db.romeonline.io/v1/graphql
GENERATE_SOURCEMAP=true
REACT_APP_GRAPHQL_ENDPOINT=https://db.imex.online/v1/graphql
REACT_APP_GRAPHQL_ENDPOINT_WS=wss://db.imex.online/v1/graphql
REACT_APP_GA_CODE=231103507
REACT_APP_FIREBASE_CONFIG={ "apiKey": "AIzaSyAuLQR9SV5LsVxjU8wh9hvFLdhcAHU6cxE", "authDomain": "rome-prod-1.firebaseapp.com", "projectId": "rome-prod-1", "storageBucket": "rome-prod-1.appspot.com", "messagingSenderId": "147786367145", "appId": "1:147786367145:web:9d4cba68071c3f29a8a9b8", "measurementId": "G-G8Z9DRHTZS"}
REACT_APP_FIREBASE_CONFIG={"apiKey":"AIzaSyDSezy-jGJreo7ulgpLdlpOwAOrgcaEkhU","authDomain":"imex-prod.firebaseapp.com","databaseURL":"https://imex-prod.firebaseio.com","projectId":"imex-prod","storageBucket":"imex-prod.appspot.com","messagingSenderId":"253497221485","appId":"1:253497221485:web:3c81c483b94db84b227a64","measurementId":"G-NTWBKG2L0M"}
REACT_APP_CLOUDINARY_ENDPOINT_API=https://api.cloudinary.com/v1_1/bodyshop
REACT_APP_CLOUDINARY_ENDPOINT=https://res.cloudinary.com/bodyshop
REACT_APP_CLOUDINARY_API_KEY=473322739956866
REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS=c_fill,h_250,w_250
REACT_APP_FIREBASE_PUBLIC_VAPID_KEY='BP1B7ZTYpn-KMt6nOxlld6aS8Skt3Q7ZLEqP0hAvGHxG4UojPYiXZ6kPlzZkUC5jH-EcWXomTLtmadAIxurfcHo'
REACT_APP_FIREBASE_PUBLIC_VAPID_KEY='BMgZT1NZztW2DsJl8Mg2L04hgY9FzAg6b8fbzgNAfww2VDzH3VE63Ot9EaP_U7KWS2JT-7HPHaw0T_Tw_5vkZc8'
REACT_APP_STRIPE_PUBLIC_KEY=pk_test_51GqB4TJl3nQjrZ0wCQWAxAhlNF8jKe0tipIa6ExBaxwJGitwvFsIZUEua4dUzaMIAuXp4qwYHXx7lgjyQSwP0Pe900vzm38C7g
REACT_APP_AXIOS_BASE_API_URL=https://api.romeonline.io/
REACT_APP_REPORTS_SERVER_URL=https://reports.romeonline.io
REACT_APP_AXIOS_BASE_API_URL=https://api.imex.online/
REACT_APP_REPORTS_SERVER_URL=https://reports.imex.online
REACT_APP_SPLIT_API=et9pjkik6bn67he5evpmpr1agoo7gactphgk

View File

@@ -1,14 +1,14 @@
REACT_APP_GRAPHQL_ENDPOINT=https://db.test.romeonline.io/v1/graphql
REACT_APP_GRAPHQL_ENDPOINT_WS=wss://db.test.romeonline.io/v1/graphql
REACT_APP_GA_CODE=231103507
REACT_APP_FIREBASE_CONFIG={ "apiKey": "AIzaSyAuLQR9SV5LsVxjU8wh9hvFLdhcAHU6cxE", "authDomain": "rome-prod-1.firebaseapp.com", "projectId": "rome-prod-1", "storageBucket": "rome-prod-1.appspot.com", "messagingSenderId": "147786367145", "appId": "1:147786367145:web:9d4cba68071c3f29a8a9b8", "measurementId": "G-G8Z9DRHTZS"}
REACT_APP_GRAPHQL_ENDPOINT=https://db.test.bodyshop.app/v1/graphql
REACT_APP_GRAPHQL_ENDPOINT_WS=wss://db.test.bodyshop.app/v1/graphql
REACT_APP_GA_CODE=231099835
REACT_APP_FIREBASE_CONFIG={ "apiKey":"AIzaSyBw7_GTy7GtQyfkIRPVrWHEGKfcqeyXw0c", "authDomain":"imex-test.firebaseapp.com", "projectId":"imex-test", "storageBucket":"imex-test.appspot.com", "messagingSenderId":"991923618608", "appId":"1:991923618608:web:633437569cdad78299bef5", "measurementId":"G-TW0XLZEH18"}
REACT_APP_CLOUDINARY_ENDPOINT_API=https://api.cloudinary.com/v1_1/bodyshop
REACT_APP_CLOUDINARY_ENDPOINT=https://res.cloudinary.com/bodyshop
REACT_APP_CLOUDINARY_API_KEY=473322739956866
REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS=c_fill,h_250,w_250
REACT_APP_FIREBASE_PUBLIC_VAPID_KEY='BP1B7ZTYpn-KMt6nOxlld6aS8Skt3Q7ZLEqP0hAvGHxG4UojPYiXZ6kPlzZkUC5jH-EcWXomTLtmadAIxurfcHo'
REACT_APP_FIREBASE_PUBLIC_VAPID_KEY='BN2GcDPjipR5MTEosO5dT4CfQ3cmrdBIsI4juoOQrRijn_5aRiHlwj1mlq0W145mOusx6xynEKl_tvYJhpCc9lo'
REACT_APP_STRIPE_PUBLIC_KEY=pk_test_51GqB4TJl3nQjrZ0wCQWAxAhlNF8jKe0tipIa6ExBaxwJGitwvFsIZUEua4dUzaMIAuXp4qwYHXx7lgjyQSwP0Pe900vzm38C7g
REACT_APP_AXIOS_BASE_API_URL=https://api.test.romeonline.io/
REACT_APP_REPORTS_SERVER_URL=https://reports.test.romeonline.io
REACT_APP_AXIOS_BASE_API_URL=https://api.test.imex.online/
REACT_APP_REPORTS_SERVER_URL=https://reports3.test.imex.online
REACT_APP_IS_TEST=true
REACT_APP_SPLIT_API=ts615lqgnmk84thn72uk18uu5pgce6e0l4rc

3
client/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
# Sentry Config File
.sentryclirc

View File

@@ -1,25 +1,25 @@
// craco.config.js
const TerserPlugin = require("terser-webpack-plugin");
const CracoLessPlugin = require("craco-less");
const SentryWebpackPlugin = require("@sentry/webpack-plugin");
//const SentryWebpackPlugin = require("@sentry/webpack-plugin");
module.exports = {
plugins: [
{
plugin: SentryWebpackPlugin,
options: {
// sentry-cli configuration
authToken:
"6b45b028a02342db97a9a2f92c0959058665443d379d4a3a876430009e744260",
org: "snapt-software",
project: "rome-online",
release: process.env.REACT_APP_GIT_SHA,
// {
// plugin: SentryWebpackPlugin,
// options: {
// // sentry-cli configuration
// authToken:
// "6b45b028a02342db97a9a2f92c0959058665443d379d4a3a876430009e744260",
// org: "snapt-software",
// project: "imexonline",
// release: process.env.REACT_APP_GIT_SHA,
// webpack-specific configuration
include: ".",
ignore: ["node_modules", "webpack.config.js"],
},
},
// // webpack-specific configuration
// include: ".",
// ignore: ["node_modules", "webpack.config.js"],
// },
// },
{
plugin: CracoLessPlugin,
options: {
@@ -27,7 +27,7 @@ module.exports = {
lessOptions: {
modifyVars: {
...(process.env.NODE_ENV === "development"
? { "@primary-color": "#B22234" }
? { "@primary-color": "#a51d1d" }
: {
//"@primary-color": "#1DA57A"
}),

634
client/package-lock.json generated
View File

@@ -13,12 +13,14 @@
"@craco/craco": "^7.0.0",
"@fingerprintjs/fingerprintjs": "^3.4.2",
"@jsreport/browser-client": "^3.1.0",
"@sentry/react": "^7.40.0",
"@sentry/cli": "^2.27.0",
"@sentry/react": "^7.99.0",
"@sentry/tracing": "^7.40.0",
"@splitsoftware/splitio-react": "^1.8.1",
"@tanem/react-nprogress": "^5.0.8",
"antd": "^4.24.8",
"apollo-link-logger": "^2.0.1",
"apollo-link-sentry": "^3.3.0",
"axios": "^1.3.4",
"craco-less": "^2.0.0",
"dinero.js": "^1.9.1",
@@ -4214,40 +4216,195 @@
"integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==",
"license": "MIT"
},
"node_modules/@sentry/browser": {
"version": "7.40.0",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.40.0.tgz",
"integrity": "sha512-07rZ+cTcpmYB1r84/oZtmSPJJvLCxW8yIh/5s4MdKRyZpqIDKhOz6cCS/4j+l1V+MeLcNLZBjFtNdKA2eocTpg==",
"license": "MIT",
"node_modules/@sentry-internal/feedback": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-7.99.0.tgz",
"integrity": "sha512-exIO1o+bE0MW4z30FxC0cYzJ4ZHSMlDPMHCBDPzU+MWGQc/fb8s58QUrx5Dnm6HTh9G3H+YlroCxIo9u0GSwGQ==",
"dependencies": {
"@sentry/core": "7.40.0",
"@sentry/replay": "7.40.0",
"@sentry/types": "7.40.0",
"@sentry/utils": "7.40.0",
"tslib": "^1.9.3"
"@sentry/core": "7.99.0",
"@sentry/types": "7.99.0",
"@sentry/utils": "7.99.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@sentry-internal/feedback/node_modules/@sentry/core": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.99.0.tgz",
"integrity": "sha512-vOAtzcAXEUtS/oW7wi3wMkZ3hsb5Ch96gKyrrj/mXdOp2zrcwdNV6N9/pawq2E9P/7Pw8AXw4CeDZztZrjQLuA==",
"dependencies": {
"@sentry/types": "7.99.0",
"@sentry/utils": "7.99.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/browser/node_modules/tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"license": "0BSD"
"node_modules/@sentry-internal/feedback/node_modules/@sentry/types": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.99.0.tgz",
"integrity": "sha512-94qwOw4w40sAs5mCmzcGyj8ZUu/KhnWnuMZARRq96k+SjRW/tHFAOlIdnFSrt3BLPvSOK7R3bVAskZQ0N4FTmA==",
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry-internal/feedback/node_modules/@sentry/utils": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.99.0.tgz",
"integrity": "sha512-cYZy5WNTkWs5GgggGnjfGqC44CWir0pAv4GVVSx0fsup4D4pMKBJPrtub15f9uC+QkUf3vVkqwpBqeFxtmJQTQ==",
"dependencies": {
"@sentry/types": "7.99.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry-internal/replay-canvas": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-7.99.0.tgz",
"integrity": "sha512-PoIkfusToDq0snfl2M6HJx/1KJYtXxYhQplrn11kYadO04SdG0XGXf4h7wBTMEQ7LDEAtQyvsOu4nEQtTO3YjQ==",
"dependencies": {
"@sentry/core": "7.99.0",
"@sentry/replay": "7.99.0",
"@sentry/types": "7.99.0",
"@sentry/utils": "7.99.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@sentry-internal/replay-canvas/node_modules/@sentry/core": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.99.0.tgz",
"integrity": "sha512-vOAtzcAXEUtS/oW7wi3wMkZ3hsb5Ch96gKyrrj/mXdOp2zrcwdNV6N9/pawq2E9P/7Pw8AXw4CeDZztZrjQLuA==",
"dependencies": {
"@sentry/types": "7.99.0",
"@sentry/utils": "7.99.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry-internal/replay-canvas/node_modules/@sentry/types": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.99.0.tgz",
"integrity": "sha512-94qwOw4w40sAs5mCmzcGyj8ZUu/KhnWnuMZARRq96k+SjRW/tHFAOlIdnFSrt3BLPvSOK7R3bVAskZQ0N4FTmA==",
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry-internal/replay-canvas/node_modules/@sentry/utils": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.99.0.tgz",
"integrity": "sha512-cYZy5WNTkWs5GgggGnjfGqC44CWir0pAv4GVVSx0fsup4D4pMKBJPrtub15f9uC+QkUf3vVkqwpBqeFxtmJQTQ==",
"dependencies": {
"@sentry/types": "7.99.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry-internal/tracing": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.99.0.tgz",
"integrity": "sha512-z3JQhHjoM1KdM20qrHwRClKJrNLr2CcKtCluq7xevLtXHJWNAQQbafnWD+Aoj85EWXBzKt9yJMv2ltcXJ+at+w==",
"dependencies": {
"@sentry/core": "7.99.0",
"@sentry/types": "7.99.0",
"@sentry/utils": "7.99.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry-internal/tracing/node_modules/@sentry/core": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.99.0.tgz",
"integrity": "sha512-vOAtzcAXEUtS/oW7wi3wMkZ3hsb5Ch96gKyrrj/mXdOp2zrcwdNV6N9/pawq2E9P/7Pw8AXw4CeDZztZrjQLuA==",
"dependencies": {
"@sentry/types": "7.99.0",
"@sentry/utils": "7.99.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry-internal/tracing/node_modules/@sentry/types": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.99.0.tgz",
"integrity": "sha512-94qwOw4w40sAs5mCmzcGyj8ZUu/KhnWnuMZARRq96k+SjRW/tHFAOlIdnFSrt3BLPvSOK7R3bVAskZQ0N4FTmA==",
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry-internal/tracing/node_modules/@sentry/utils": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.99.0.tgz",
"integrity": "sha512-cYZy5WNTkWs5GgggGnjfGqC44CWir0pAv4GVVSx0fsup4D4pMKBJPrtub15f9uC+QkUf3vVkqwpBqeFxtmJQTQ==",
"dependencies": {
"@sentry/types": "7.99.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/browser": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.99.0.tgz",
"integrity": "sha512-bgfoUv3wkwwLgN5YUOe0ibB3y268ZCnamZh6nLFqnY/UBKC1+FXWFdvzVON/XKUm62LF8wlpCybOf08ebNj2yg==",
"dependencies": {
"@sentry-internal/feedback": "7.99.0",
"@sentry-internal/replay-canvas": "7.99.0",
"@sentry-internal/tracing": "7.99.0",
"@sentry/core": "7.99.0",
"@sentry/replay": "7.99.0",
"@sentry/types": "7.99.0",
"@sentry/utils": "7.99.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/browser/node_modules/@sentry/core": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.99.0.tgz",
"integrity": "sha512-vOAtzcAXEUtS/oW7wi3wMkZ3hsb5Ch96gKyrrj/mXdOp2zrcwdNV6N9/pawq2E9P/7Pw8AXw4CeDZztZrjQLuA==",
"dependencies": {
"@sentry/types": "7.99.0",
"@sentry/utils": "7.99.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/browser/node_modules/@sentry/types": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.99.0.tgz",
"integrity": "sha512-94qwOw4w40sAs5mCmzcGyj8ZUu/KhnWnuMZARRq96k+SjRW/tHFAOlIdnFSrt3BLPvSOK7R3bVAskZQ0N4FTmA==",
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/browser/node_modules/@sentry/utils": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.99.0.tgz",
"integrity": "sha512-cYZy5WNTkWs5GgggGnjfGqC44CWir0pAv4GVVSx0fsup4D4pMKBJPrtub15f9uC+QkUf3vVkqwpBqeFxtmJQTQ==",
"dependencies": {
"@sentry/types": "7.99.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/cli": {
"version": "1.74.6",
"resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-1.74.6.tgz",
"integrity": "sha512-pJ7JJgozyjKZSTjOGi86chIngZMLUlYt2HOog+OJn+WGvqEkVymu8m462j1DiXAnex9NspB4zLLNuZ/R6rTQHg==",
"dev": true,
"version": "2.27.0",
"resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-2.27.0.tgz",
"integrity": "sha512-pc0opd71W8lGhYvmB1keQtJkarxzCS9f9ErKYv6TfXOOX6drvwkyA6vD/6xEnpzyvqGAuGRU4T4sEeLD3irwUQ==",
"hasInstallScript": true,
"license": "BSD-3-Clause",
"dependencies": {
"https-proxy-agent": "^5.0.0",
"mkdirp": "^0.5.5",
"node-fetch": "^2.6.7",
"npmlog": "^4.1.2",
"progress": "^2.0.3",
"proxy-from-env": "^1.1.0",
"which": "^2.0.2"
@@ -4256,7 +4413,124 @@
"sentry-cli": "bin/sentry-cli"
},
"engines": {
"node": ">= 8"
"node": ">= 10"
},
"optionalDependencies": {
"@sentry/cli-darwin": "2.27.0",
"@sentry/cli-linux-arm": "2.27.0",
"@sentry/cli-linux-arm64": "2.27.0",
"@sentry/cli-linux-i686": "2.27.0",
"@sentry/cli-linux-x64": "2.27.0",
"@sentry/cli-win32-i686": "2.27.0",
"@sentry/cli-win32-x64": "2.27.0"
}
},
"node_modules/@sentry/cli-darwin": {
"version": "2.27.0",
"resolved": "https://registry.npmjs.org/@sentry/cli-darwin/-/cli-darwin-2.27.0.tgz",
"integrity": "sha512-/DOZlN5rK19g7YP2OaVNauQhUrRfJ88RDr6qURFiqdxYHDc3isPFGHZJmeZBTwOnDDepyZb4XLaOyfwvAOxHig==",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@sentry/cli-linux-arm": {
"version": "2.27.0",
"resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm/-/cli-linux-arm-2.27.0.tgz",
"integrity": "sha512-JmMQ9zgFhkZUEN5WIYuJisu4Jif/ThRHDjbsbXBRbUkkgRn88hgUfg299djMvlZZxjpl3K9AEua+1TIUeQd0Sg==",
"cpu": [
"arm"
],
"optional": true,
"os": [
"linux",
"freebsd"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@sentry/cli-linux-arm64": {
"version": "2.27.0",
"resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.27.0.tgz",
"integrity": "sha512-f+zuB9XGfB8pNamNgSDhqsavuLuzi6saZxbr3uQf30bA5AESI5hspOd1zPcidOORCVZxiPzQe3+T7avBI1XLuw==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux",
"freebsd"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@sentry/cli-linux-i686": {
"version": "2.27.0",
"resolved": "https://registry.npmjs.org/@sentry/cli-linux-i686/-/cli-linux-i686-2.27.0.tgz",
"integrity": "sha512-/4eyz7jnYp20mZqNtpvCEBkxFW0nEjEZRo2BiASQ5/7K8CmoJRe1vhpDA0WOfzi1zTFIfpdE1/RZm2CjHS6DHQ==",
"cpu": [
"x86",
"ia32"
],
"optional": true,
"os": [
"linux",
"freebsd"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@sentry/cli-linux-x64": {
"version": "2.27.0",
"resolved": "https://registry.npmjs.org/@sentry/cli-linux-x64/-/cli-linux-x64-2.27.0.tgz",
"integrity": "sha512-ptu7wXecnYssihzHlxEOaqbFHWmNEfbepBKGXTdWK2kC+D51+7yHsR9xRdThwVID1bisFgjAveKmBQjmKuXjHQ==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux",
"freebsd"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@sentry/cli-win32-i686": {
"version": "2.27.0",
"resolved": "https://registry.npmjs.org/@sentry/cli-win32-i686/-/cli-win32-i686-2.27.0.tgz",
"integrity": "sha512-Db4/xmdE5qV4Aq7Yc8vRw22Y46JJdGMdsMsl5jIf0GVSQPgO23O/2uTiDGpPOdeq91K9EtvpH1zQfDLIfLMaXw==",
"cpu": [
"x86",
"ia32"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@sentry/cli-win32-x64": {
"version": "2.27.0",
"resolved": "https://registry.npmjs.org/@sentry/cli-win32-x64/-/cli-win32-x64-2.27.0.tgz",
"integrity": "sha512-q7y/BH4iGfs0TD5PXh2Q8oqnTbOIufoT1NWJcKqvZcOiqCLK3PNUiq7xUeX1PMTrFYAh3Bm6EekOnMavqvbGmg==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@sentry/core": {
@@ -4280,16 +4554,15 @@
"license": "0BSD"
},
"node_modules/@sentry/react": {
"version": "7.40.0",
"resolved": "https://registry.npmjs.org/@sentry/react/-/react-7.40.0.tgz",
"integrity": "sha512-7yYagpOCdsXnVTtLL8Y7wAf2xXgsk2ncuju3O/G4kEckkLewZWmQeoknOSGFlAgVdGNhTaXc2WGzgOiBMOkhug==",
"license": "MIT",
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/react/-/react-7.99.0.tgz",
"integrity": "sha512-RtHwgzMHJhzJfSQpVG0SDPQYMTGDX3Q37/YWI59S4ALMbSW4/F6n/eQAvGVYZKbh2UCSqgFuRWaXOYkSZT17wA==",
"dependencies": {
"@sentry/browser": "7.40.0",
"@sentry/types": "7.40.0",
"@sentry/utils": "7.40.0",
"hoist-non-react-statics": "^3.3.2",
"tslib": "^1.9.3"
"@sentry/browser": "7.99.0",
"@sentry/core": "7.99.0",
"@sentry/types": "7.99.0",
"@sentry/utils": "7.99.0",
"hoist-non-react-statics": "^3.3.2"
},
"engines": {
"node": ">=8"
@@ -4298,26 +4571,82 @@
"react": "15.x || 16.x || 17.x || 18.x"
}
},
"node_modules/@sentry/react/node_modules/tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"license": "0BSD"
"node_modules/@sentry/react/node_modules/@sentry/core": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.99.0.tgz",
"integrity": "sha512-vOAtzcAXEUtS/oW7wi3wMkZ3hsb5Ch96gKyrrj/mXdOp2zrcwdNV6N9/pawq2E9P/7Pw8AXw4CeDZztZrjQLuA==",
"dependencies": {
"@sentry/types": "7.99.0",
"@sentry/utils": "7.99.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/react/node_modules/@sentry/types": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.99.0.tgz",
"integrity": "sha512-94qwOw4w40sAs5mCmzcGyj8ZUu/KhnWnuMZARRq96k+SjRW/tHFAOlIdnFSrt3BLPvSOK7R3bVAskZQ0N4FTmA==",
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/react/node_modules/@sentry/utils": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.99.0.tgz",
"integrity": "sha512-cYZy5WNTkWs5GgggGnjfGqC44CWir0pAv4GVVSx0fsup4D4pMKBJPrtub15f9uC+QkUf3vVkqwpBqeFxtmJQTQ==",
"dependencies": {
"@sentry/types": "7.99.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/replay": {
"version": "7.40.0",
"resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.40.0.tgz",
"integrity": "sha512-Y9Kvo9jKouUdrHQhHVv5SmWZClF5o7BFI6oVpLlv4zXORPQlyoZONM/9sxiMvvH73alDSpxzCoxyhlypAOH4ww==",
"license": "MIT",
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.99.0.tgz",
"integrity": "sha512-gyN/I2WpQrLAZDT+rScB/0jnFL2knEVBo8U8/OVt8gNP20Pq8T/rDZKO/TG0cBfvULDUbJj2P4CJryn2p/O2rA==",
"dependencies": {
"@sentry/core": "7.40.0",
"@sentry/types": "7.40.0",
"@sentry/utils": "7.40.0"
"@sentry-internal/tracing": "7.99.0",
"@sentry/core": "7.99.0",
"@sentry/types": "7.99.0",
"@sentry/utils": "7.99.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@sentry/replay/node_modules/@sentry/core": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.99.0.tgz",
"integrity": "sha512-vOAtzcAXEUtS/oW7wi3wMkZ3hsb5Ch96gKyrrj/mXdOp2zrcwdNV6N9/pawq2E9P/7Pw8AXw4CeDZztZrjQLuA==",
"dependencies": {
"@sentry/types": "7.99.0",
"@sentry/utils": "7.99.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/replay/node_modules/@sentry/types": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.99.0.tgz",
"integrity": "sha512-94qwOw4w40sAs5mCmzcGyj8ZUu/KhnWnuMZARRq96k+SjRW/tHFAOlIdnFSrt3BLPvSOK7R3bVAskZQ0N4FTmA==",
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/replay/node_modules/@sentry/utils": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.99.0.tgz",
"integrity": "sha512-cYZy5WNTkWs5GgggGnjfGqC44CWir0pAv4GVVSx0fsup4D4pMKBJPrtub15f9uC+QkUf3vVkqwpBqeFxtmJQTQ==",
"dependencies": {
"@sentry/types": "7.99.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/tracing": {
"version": "7.40.0",
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.40.0.tgz",
@@ -4381,6 +4710,27 @@
"node": ">= 8"
}
},
"node_modules/@sentry/webpack-plugin/node_modules/@sentry/cli": {
"version": "1.77.3",
"resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-1.77.3.tgz",
"integrity": "sha512-c3eDqcDRmy4TFz2bFU5Y6QatlpoBPPa8cxBooaS4aMQpnIdLYPF1xhyyiW0LQlDUNc3rRjNF7oN5qKoaRoMTQQ==",
"dev": true,
"hasInstallScript": true,
"dependencies": {
"https-proxy-agent": "^5.0.0",
"mkdirp": "^0.5.5",
"node-fetch": "^2.6.7",
"progress": "^2.0.3",
"proxy-from-env": "^1.1.0",
"which": "^2.0.2"
},
"bin": {
"sentry-cli": "bin/sentry-cli"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/@sinclair/typebox": {
"version": "0.24.51",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz",
@@ -6112,12 +6462,21 @@
"@apollo/client": "^3.0.0"
}
},
"node_modules/aproba": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
"dev": true,
"license": "ISC"
"node_modules/apollo-link-sentry": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/apollo-link-sentry/-/apollo-link-sentry-3.3.0.tgz",
"integrity": "sha512-wLffWmo5sRw3rHN1Ck6azM0oxObvtaBBf3AC8cLX4SxhyjmkRIagGDji6CFkyAhxupPz0b9/H1u4Ocx+63lNug==",
"dependencies": {
"deepmerge": "^4.2.2",
"dot-prop": "^6.0.0",
"tslib": "^2.0.3",
"zen-observable-ts": "^1.2.5"
},
"peerDependencies": {
"@apollo/client": "^3.2.3",
"@sentry/browser": "^7.41.0",
"graphql": "15 - 16"
}
},
"node_modules/arch": {
"version": "2.2.0",
@@ -6140,17 +6499,6 @@
],
"license": "MIT"
},
"node_modules/are-we-there-yet": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz",
"integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==",
"dev": true,
"license": "ISC",
"dependencies": {
"delegates": "^1.0.0",
"readable-stream": "^2.0.6"
}
},
"node_modules/arg": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
@@ -7571,16 +7919,6 @@
"node": ">=4"
}
},
"node_modules/code-point-at": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
"integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/collect-v8-coverage": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz",
@@ -7743,13 +8081,6 @@
"node": ">=0.8"
}
},
"node_modules/console-control-strings": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
"integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==",
"dev": true,
"license": "ISC"
},
"node_modules/content-disposition": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
@@ -8911,13 +9242,6 @@
"node": ">=0.4.0"
}
},
"node_modules/delegates": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
"integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==",
"dev": true,
"license": "MIT"
},
"node_modules/denque": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz",
@@ -9218,6 +9542,28 @@
"tslib": "^2.0.3"
}
},
"node_modules/dot-prop": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz",
"integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==",
"dependencies": {
"is-obj": "^2.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/dot-prop/node_modules/is-obj": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
"integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
"engines": {
"node": ">=8"
}
},
"node_modules/dotenv": {
"version": "16.0.1",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz",
@@ -11285,74 +11631,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/gauge": {
"version": "2.7.4",
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
"integrity": "sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==",
"dev": true,
"license": "ISC",
"dependencies": {
"aproba": "^1.0.3",
"console-control-strings": "^1.0.0",
"has-unicode": "^2.0.0",
"object-assign": "^4.1.0",
"signal-exit": "^3.0.0",
"string-width": "^1.0.1",
"strip-ansi": "^3.0.1",
"wide-align": "^1.1.0"
}
},
"node_modules/gauge/node_modules/ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/gauge/node_modules/is-fullwidth-code-point": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
"integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==",
"dev": true,
"license": "MIT",
"dependencies": {
"number-is-nan": "^1.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/gauge/node_modules/string-width": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==",
"dev": true,
"license": "MIT",
"dependencies": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
"strip-ansi": "^3.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/gauge/node_modules/strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-regex": "^2.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/gensync": {
"version": "1.0.0-beta.2",
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
@@ -11755,13 +12033,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-unicode": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
"integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==",
"dev": true,
"license": "ISC"
},
"node_modules/he": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
@@ -15746,19 +16017,6 @@
"node": ">=8"
}
},
"node_modules/npmlog": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
"dev": true,
"license": "ISC",
"dependencies": {
"are-we-there-yet": "~1.1.2",
"console-control-strings": "~1.1.0",
"gauge": "~2.7.3",
"set-blocking": "~2.0.0"
}
},
"node_modules/nth-check": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
@@ -15771,16 +16029,6 @@
"url": "https://github.com/fb55/nth-check?sponsor=1"
}
},
"node_modules/number-is-nan": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
"integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/nwsapi": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.1.tgz",
@@ -17796,7 +18044,6 @@
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.4.0"
@@ -20528,13 +20775,6 @@
"node": ">= 0.8.0"
}
},
"node_modules/set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
"dev": true,
"license": "ISC"
},
"node_modules/setprototypeof": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
@@ -23069,16 +23309,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/wide-align": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz",
"integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==",
"dev": true,
"license": "ISC",
"dependencies": {
"string-width": "^1.0.2 || 2 || 3 || 4"
}
},
"node_modules/wildcard": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz",

View File

@@ -9,12 +9,14 @@
"@craco/craco": "^7.0.0",
"@fingerprintjs/fingerprintjs": "^3.4.2",
"@jsreport/browser-client": "^3.1.0",
"@sentry/react": "^7.40.0",
"@sentry/cli": "^2.27.0",
"@sentry/react": "^7.99.0",
"@sentry/tracing": "^7.40.0",
"@splitsoftware/splitio-react": "^1.8.1",
"@tanem/react-nprogress": "^5.0.8",
"antd": "^4.24.8",
"apollo-link-logger": "^2.0.1",
"apollo-link-sentry": "^3.3.0",
"axios": "^1.3.4",
"craco-less": "^2.0.0",
"dinero.js": "^1.9.1",
@@ -88,13 +90,14 @@
"scripts": {
"analyze": "source-map-explorer 'build/static/js/*.js'",
"start": "craco start",
"build": "REACT_APP_GIT_SHA=`git rev-parse --short HEAD` craco build",
"build": "REACT_APP_GIT_SHA=`git rev-parse --short HEAD` craco build && npm run sentry:sourcemaps",
"build:test": "env-cmd -f .env.test npm run build",
"build-deploy:test": "npm run build:test && s3cmd sync build/* s3://imex-online-test && echo '🚀 TESTING Deployed!'",
"buildcra": "REACT_APP_GIT_SHA=`git rev-parse --short HEAD` craco build",
"test": "cypress open",
"eject": "react-scripts eject",
"madge": "madge --image ./madge-graph.svg --extensions js,jsx,ts,tsx --circular ."
"madge": "madge --image ./madge-graph.svg --extensions js,jsx,ts,tsx --circular .",
"sentry:sourcemaps": "sentry-cli sourcemaps inject --org imex --project imexonline ./build && sentry-cli sourcemaps upload --org imex --project imexonline ./build"
},
"eslintConfig": {
"extends": [

View File

@@ -28,17 +28,6 @@ switch (this.location.hostname) {
// measurementId: "${config.measurementId}",
};
break;
case "romeonline.io":
firebaseConfig = {
apiKey: "AIzaSyAuLQR9SV5LsVxjU8wh9hvFLdhcAHU6cxE",
authDomain: "rome-prod-1.firebaseapp.com",
projectId: "rome-prod-1",
storageBucket: "rome-prod-1.appspot.com",
messagingSenderId: "147786367145",
appId: "1:147786367145:web:9d4cba68071c3f29a8a9b8",
measurementId: "G-G8Z9DRHTZS",
};
break;
case "imex.online":
default:
firebaseConfig = {

View File

@@ -2,81 +2,23 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/ro-favicon.png" />
<link rel="icon" href="%PUBLIC_URL%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#002366" />
<meta name="description" content="Rome Online" />
<meta name="description" content="ImEX Online" />
<!-- <link rel="apple-touch-icon" href="logo192.png" /> -->
<!--Use the below code snippet to provide real time updates to the live chat plugin without the need of copying and paste each time to your website when changes are made via PBX-->
<call-us-selector phonesystem-url=https://rometech.east.3cx.us:5001 party="LiveChat528346"></call-us-selector>
<!--Incase you don't want real time updates to the live chat plugin when options are changed, use the below code snippet. Please note that each time you change the settings you will need to copy and paste the snippet code to your website-->
<!--<call-us
phonesystem-url=https://rometech.east.3cx.us:5001
style="position:fixed;font-size:16px;line-height:17px;z-index: 99999;right: 20px; bottom: 20px;"
id="wp-live-chat-by-3CX"
minimized="true"
animation-style="noanimation"
party="LiveChat528346"
minimized-style="bubbleright"
allow-call="true"
allow-video="false"
allow-soundnotifications="true"
enable-mute="true"
enable-onmobile="true"
offline-enabled="true"
enable="true"
ignore-queueownership="false"
authentication="both"
show-operator-actual-name="true"
aknowledge-received="true"
gdpr-enabled="false"
message-userinfo-format="name"
message-dateformat="both"
lang="browser"
button-icon-type="default"
greeting-visibility="none"
greeting-offline-visibility="none"
chat-delay="2000"
enable-direct-call="true"
enable-ga="false"
></call-us>-->
<script defer src=https://downloads-global.3cx.com/downloads/livechatandtalk/v1/callus.js id="tcx-callus-js" charset="utf-8"></script>
<link rel="apple-touch-icon" href="logo192.png" />
<script type="text/javascript">
window.$crisp = [];
window.CRISP_WEBSITE_ID = "36724f62-2eb0-4b29-9cdd-9905fb99913e";
(function () {
d = document;
s = d.createElement("script");
s.src = "https://client.crisp.chat/l.js";
s.async = 1;
d.getElementsByTagName("head")[0].appendChild(s);
})();
</script>
<script>
!(function () {
"use strict";
@@ -135,7 +77,7 @@ enable-ga="false"
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>Rome Online</title>
<title>ImEX Online</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>

View File

@@ -1,6 +1,6 @@
{
"short_name": "Rome Online",
"name": "Rome Online",
"short_name": "ImEX Online",
"name": "ImEX Online",
"description": "The ultimate bodyshop management system.",
"icons": [
{

Binary file not shown.

Before

Width:  |  Height:  |  Size: 376 B

View File

@@ -8,6 +8,7 @@ import { useTranslation } from "react-i18next";
import GlobalLoadingBar from "../components/global-loading-bar/global-loading-bar.component";
import client from "../utils/GraphQLClient";
import App from "./App";
import * as Sentry from "@sentry/react";
moment.locale("en-US");
@@ -18,7 +19,7 @@ export const factory = SplitSdk({
},
});
export default function AppContainer() {
function AppContainer() {
const { t } = useTranslation();
return (
@@ -27,12 +28,6 @@ export default function AppContainer() {
//componentSize="small"
input={{ autoComplete: "new-password" }}
locale={enLocale}
theme={{
token: {
colorPrimary: "#326ade",
colorInfo: "#326ade"
},
}}
form={{
validateMessages: {
// eslint-disable-next-line no-template-curly-in-string
@@ -48,3 +43,5 @@ export default function AppContainer() {
</ApolloProvider>
);
}
export default Sentry.withProfiler(AppContainer);

View File

@@ -78,9 +78,9 @@ export function App({
if (currentUser.authorized && bodyshop) {
client.setAttribute("imexshopid", bodyshop.imexshopid);
LogRocket.init("rome-online/rome-online");
if (client.getTreatment("LogRocket_Tracking") === "on") {
LogRocket.init("rome-online/rome-online");
console.log("LR Start");
LogRocket.init("gvfvfw/bodyshopapp");
}
}
}, [bodyshop, client, currentUser.authorized]);
@@ -112,7 +112,7 @@ export function App({
return (
<Switch>
<Suspense fallback={<LoadingSpinner />}>
<Suspense fallback={<LoadingSpinner message="ImEX Online" />}>
<ErrorBoundary>
<Route exact path="/" component={LandingPage} />
</ErrorBoundary>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

View File

@@ -1,5 +1,4 @@
import { useApolloClient, useMutation } from "@apollo/client";
import { useTreatments } from "@splitsoftware/splitio-react";
import { Button, Checkbox, Form, Modal, Space, notification } from "antd";
import _ from "lodash";
import React, { useEffect, useMemo, useState } from "react";
@@ -64,19 +63,9 @@ function BillEnterModalContainer({
"enter_bill_generate_label",
false
);
const { Enhanced_Payroll } = useTreatments(
["Enhanced_Payroll"],
{},
bodyshop.imexshopid
);
const formValues = useMemo(() => {
return {
...billEnterModal.context.bill,
//Added as a part of IO-2436 for capturing parts price changes.
billlines: billEnterModal.context?.bill?.billlines?.map((line) => ({
...line,
original_actual_price: line.actual_price,
})),
jobid:
(billEnterModal.context.job && billEnterModal.context.job.id) || null,
federal_tax_rate:
@@ -105,11 +94,11 @@ function BillEnterModalContainer({
location,
outstanding_returns,
inventory,
federal_tax_exempt,
...remainingValues
} = values;
let adjustmentsToInsert = {};
let payrollAdjustmentsToInsert = [];
const r1 = await insertBill({
variables: {
@@ -125,33 +114,14 @@ function BillEnterModalContainer({
lbr_adjustment,
location: lineLocation,
part_type,
create_ppc,
original_actual_price,
...restI
} = i;
if (Enhanced_Payroll.treatment === "on") {
if (
deductedfromlbr &&
true //payroll is on
) {
payrollAdjustmentsToInsert.push({
id: i.joblineid,
convertedtolbr: true,
convertedtolbr_data: {
mod_lb_hrs: lbr_adjustment.mod_lb_hrs * -1,
mod_lbr_ty: lbr_adjustment.mod_lbr_ty,
},
});
}
} else {
if (deductedfromlbr) {
adjustmentsToInsert[lbr_adjustment.mod_lbr_ty] =
(adjustmentsToInsert[lbr_adjustment.mod_lbr_ty] || 0) -
restI.actual_price / lbr_adjustment.rate;
}
if (deductedfromlbr) {
adjustmentsToInsert[lbr_adjustment.mod_lbr_ty] =
(adjustmentsToInsert[lbr_adjustment.mod_lbr_ty] || 0) -
restI.actual_price / lbr_adjustment.rate;
}
return {
...restI,
deductedfromlbr: deductedfromlbr,
@@ -177,20 +147,6 @@ function BillEnterModalContainer({
refetchQueries: ["QUERY_PARTS_BILLS_BY_JOBID", "GET_JOB_BY_PK"],
});
await Promise.all(
payrollAdjustmentsToInsert.map((li) => {
return updateJobLines({
variables: {
lineId: li.id,
line: {
convertedtolbr: li.convertedtolbr,
convertedtolbr_data: li.convertedtolbr_data,
},
},
});
})
);
const adjKeys = Object.keys(adjustmentsToInsert);
if (adjKeys.length > 0) {
//Query the adjustments, merge, and update them.
@@ -299,14 +255,6 @@ function BillEnterModalContainer({
location: li.location || location,
status:
bodyshop.md_order_statuses.default_received || "Received*",
//Added parts price changes.
...(li.create_ppc &&
li.original_actual_price !== li.actual_price
? {
act_price_before_ppc: li.original_actual_price,
act_price: li.actual_price,
}
: {}),
},
},
});
@@ -375,12 +323,12 @@ function BillEnterModalContainer({
});
if (enterAgain) {
// form.resetFields();
form.resetFields();
form.resetFields();
form.setFieldsValue({
...formValues,
billlines: [],
});
form.resetFields();
} else {
toggleModalVisible();
}

View File

@@ -79,19 +79,19 @@ export function BillFormComponent({
});
};
// const handleFederalTaxExemptSwitchToggle = (checked) => {
// // Early gate
// if (!checked) return;
// const values = form.getFieldsValue("billlines");
// // Gate bill lines
// if (!values?.billlines?.length) return;
const handleFederalTaxExemptSwitchToggle = (checked) => {
// Early gate
if (!checked) return;
const values = form.getFieldsValue("billlines");
// Gate bill lines
if (!values?.billlines?.length) return;
// const billlines = values.billlines.map((b) => {
// b.applicable_taxes.federal = false;
// return b;
// });
// form.setFieldsValue({ billlines });
// };
const billlines = values.billlines.map((b) => {
b.applicable_taxes.federal = false;
return b;
});
form.setFieldsValue({ billlines });
};
useEffect(() => {
if (job) form.validateFields(["is_credit_memo"]);
@@ -380,15 +380,13 @@ export function BillFormComponent({
)}
</LayoutFormRow>
<LayoutFormRow>
{
// <Form.Item
// span={3}
// label={t("bills.fields.federal_tax_rate")}
// name="federal_tax_rate"
// >
// <CurrencyInput min={0} disabled={disabled} />
// </Form.Item>
}
<Form.Item
span={3}
label={t("bills.fields.federal_tax_rate")}
name="federal_tax_rate"
>
<CurrencyInput min={0} disabled={disabled} />
</Form.Item>
<Form.Item
span={3}
label={t("bills.fields.state_tax_rate")}
@@ -396,27 +394,22 @@ export function BillFormComponent({
>
<CurrencyInput min={0} disabled={disabled} />
</Form.Item>
{
// <Form.Item
// span={3}
// label={t("bills.fields.local_tax_rate")}
// name="local_tax_rate"
// >
// <CurrencyInput min={0} />
// </Form.Item>
}
{
//Removed as a part of the merge to Rome Online. Federal tax not applicable.
// bodyshop.pbs_serialnumber || bodyshop.cdk_dealerid ? (
// <Form.Item
// span={2}
// label={t("bills.labels.federal_tax_exempt")}
// name="federal_tax_exempt"
// >
// <Switch onChange={handleFederalTaxExemptSwitchToggle} />
// </Form.Item>
// ) : null
}
<Form.Item
span={3}
label={t("bills.fields.local_tax_rate")}
name="local_tax_rate"
>
<CurrencyInput min={0} />
</Form.Item>
{bodyshop.pbs_serialnumber || bodyshop.cdk_dealerid ? (
<Form.Item
span={2}
label={t("bills.labels.federal_tax_exempt")}
name="federal_tax_exempt"
>
<Switch onChange={handleFederalTaxExemptSwitchToggle} />
</Form.Item>
) : null}
<Form.Item shouldUpdate span={13}>
{() => {
const values = form.getFieldsValue([
@@ -442,25 +435,21 @@ export function BillFormComponent({
value={totals.subtotal.toFormat()}
precision={2}
/>
{
// <Statistic
// title={t("bills.labels.federal_tax")}
// value={totals.federalTax.toFormat()}
// precision={2}
// />
}
<Statistic
title={t("bills.labels.federal_tax")}
value={totals.federalTax.toFormat()}
precision={2}
/>
<Statistic
title={t("bills.labels.state_tax")}
value={totals.stateTax.toFormat()}
precision={2}
/>
{
// <Statistic
// title={t("bills.labels.local_tax")}
// value={totals.localTax.toFormat()}
// precision={2}
// />
}
<Statistic
title={t("bills.labels.local_tax")}
value={totals.localTax.toFormat()}
precision={2}
/>
<Statistic
title={t("bills.labels.entered_total")}
value={totals.enteredTotal.toFormat()}

View File

@@ -2,7 +2,6 @@ import { DeleteFilled, DollarCircleFilled } from "@ant-design/icons";
import { useTreatments } from "@splitsoftware/splitio-react";
import {
Button,
Checkbox,
Form,
Input,
InputNumber,
@@ -47,13 +46,6 @@ export function BillEnterModalLinesComponent({
{},
bodyshop && bodyshop.imexshopid
);
const { Enhanced_Payroll } = useTreatments(
["Enhanced_Payroll"],
{},
bodyshop.imexshopid
);
const columns = (remove) => {
return [
{
@@ -102,7 +94,6 @@ export function BillEnterModalLinesComponent({
line_desc: opt.line_desc,
quantity: opt.part_qty || 1,
actual_price: opt.cost,
original_actual_price: opt.cost,
cost_center: opt.part_type
? bodyshop.pbs_serialnumber || bodyshop.cdk_dealerid
? opt.part_type !== "PAE"
@@ -229,43 +220,6 @@ export function BillEnterModalLinesComponent({
}}
/>
),
additional: (record, index) => (
<Form.Item
dependencies={["billlines", record.name, "actual_price"]}
noStyle
>
{() => {
const billLine = getFieldValue(["billlines", record.name]);
const jobLine = lineData.find(
(line) => line.id === billLine?.joblineid
);
if (
!billEdit &&
billLine &&
jobLine &&
billLine?.actual_price !== jobLine?.act_price
) {
return (
<Space size="small">
<Form.Item
noStyle
label={t("joblines.fields.create_ppc")}
key={`${index}ppc`}
valuePropName="checked"
name={[record.name, "create_ppc"]}
>
<Checkbox />
</Form.Item>
{t("joblines.fields.create_ppc")}
</Space>
);
} else {
return null;
}
}}
</Form.Item>
),
},
{
title: t("billlines.fields.actual_cost"),
@@ -407,7 +361,7 @@ export function BillEnterModalLinesComponent({
},
formInput: (record, index) => <Switch disabled={disabled} />,
additional: (record, index) => (
<Form.Item shouldUpdate noStyle style={{ display: "inline-block" }}>
<Form.Item shouldUpdate style={{ display: "inline-block" }}>
{() => {
const price = getFieldValue([
"billlines",
@@ -422,31 +376,12 @@ export function BillEnterModalLinesComponent({
"rate",
]);
const billline = getFieldValue(["billlines", record.name]);
const jobline = lineData.find(
(line) => line.id === billline?.joblineid
);
const employeeTeamName = bodyshop.employee_teams.find(
(team) => team.id === jobline?.assigned_team
);
if (getFieldValue(["billlines", record.name, "deductedfromlbr"]))
return (
<div>
<Space>
{t("joblines.fields.assigned_team", {
name: employeeTeamName?.name,
})}
{`${jobline.mod_lb_hrs} units/${t(
`joblines.fields.lbr_types.${jobline.mod_lbr_ty}`
)}`}
</Space>
<Form.Item
label={t("joblines.fields.mod_lbr_ty")}
key={`${index}modlbrty`}
initialValue={jobline ? jobline.mod_lbr_ty : null}
rules={[
{
required: true,
@@ -500,44 +435,22 @@ export function BillEnterModalLinesComponent({
</Select.Option>
</Select>
</Form.Item>
{Enhanced_Payroll.treatment === "on" ? (
<Form.Item
label={t("billlines.labels.mod_lbr_adjustment")}
name={[record.name, "lbr_adjustment", "mod_lb_hrs"]}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<InputNumber
precision={5}
min={0.01}
max={jobline ? jobline.mod_lb_hrs : 0}
/>
</Form.Item>
) : (
<Form.Item
label={t("jobs.labels.adjustmentrate")}
name={[record.name, "lbr_adjustment", "rate"]}
initialValue={bodyshop.default_adjustment_rate}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<InputNumber precision={2} min={0.01} />
</Form.Item>
)}
<Space>
{price &&
adjustmentRate &&
`${(price / adjustmentRate).toFixed(1)} hrs`}
</Space>
<Form.Item
label={t("jobs.labels.adjustmentrate")}
name={[record.name, "lbr_adjustment", "rate"]}
initialValue={bodyshop.default_adjustment_rate}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<InputNumber precision={2} min={0.01} />
</Form.Item>
{price &&
adjustmentRate &&
`${(price / adjustmentRate).toFixed(1)} hrs`}
</div>
);
return <></>;
@@ -545,21 +458,22 @@ export function BillEnterModalLinesComponent({
</Form.Item>
),
},
// {
// title: t("billlines.fields.federal_tax_applicable"),
// dataIndex: "applicable_taxes.federal",
// editable: true,
{
title: t("billlines.fields.federal_tax_applicable"),
dataIndex: "applicable_taxes.federal",
editable: true,
// formItemProps: (field) => {
// return {
// key: `${field.index}fedtax`,
// valuePropName: "checked",
// // initialValue: true,
// name: [field.name, "applicable_taxes", "federal"],
// };
// },
// formInput: (record, index) => <Switch disabled={disabled} />,
// },
formItemProps: (field) => {
return {
key: `${field.index}fedtax`,
valuePropName: "checked",
initialValue:
form.getFieldValue("federal_tax_exempt") === true ? false : true,
name: [field.name, "applicable_taxes", "federal"],
};
},
formInput: (record, index) => <Switch disabled={disabled} />,
},
{
title: t("billlines.fields.state_tax_applicable"),
dataIndex: "applicable_taxes.state",
@@ -574,20 +488,20 @@ export function BillEnterModalLinesComponent({
},
formInput: (record, index) => <Switch disabled={disabled} />,
},
// {
// title: t("billlines.fields.local_tax_applicable"),
// dataIndex: "applicable_taxes.local",
// editable: true,
{
title: t("billlines.fields.local_tax_applicable"),
dataIndex: "applicable_taxes.local",
editable: true,
// formItemProps: (field) => {
// return {
// key: `${field.index}localtax`,
// valuePropName: "checked",
// name: [field.name, "applicable_taxes", "local"],
// };
// },
// formInput: (record, index) => <Switch disabled={disabled} />,
// },
formItemProps: (field) => {
return {
key: `${field.index}localtax`,
valuePropName: "checked",
name: [field.name, "applicable_taxes", "local"],
};
},
formInput: (record, index) => <Switch disabled={disabled} />,
},
{
title: t("general.labels.actions"),
@@ -712,7 +626,7 @@ const EditableCell = ({
if (additional)
return (
<td {...restProps}>
<div size="small">
<Space size="small">
<Form.Item
name={dataIndex}
labelCol={{ span: 0 }}
@@ -721,7 +635,7 @@ const EditableCell = ({
{(formInput && formInput(record, record.name)) || children}
</Form.Item>
{additional && additional(record, record.name)}
</div>
</Space>
</td>
);
if (wrapper)

View File

@@ -19,14 +19,14 @@ export const CalculateBillTotal = (invoice) => {
}).multiply(i.quantity || 1);
subtotal = subtotal.add(itemTotal);
if (i.applicable_taxes?.federal) {
if (i.applicable_taxes.federal) {
federalTax = federalTax.add(
itemTotal.percentage(federal_tax_rate || 0)
);
}
if (i.applicable_taxes?.state)
if (i.applicable_taxes.state)
stateTax = stateTax.add(itemTotal.percentage(state_tax_rate || 0));
if (i.applicable_taxes?.local)
if (i.applicable_taxes.local)
localTax = localTax.add(itemTotal.percentage(local_tax_rate || 0));
}
});

View File

@@ -63,12 +63,6 @@ const BillLineSearchSelect = (
item.oem_partno ? ` - ${item.oem_partno}` : ""
}${item.alt_partno ? ` (${item.alt_partno})` : ""}`.trim()}
</span>
{item.act_price === 0 && item.mod_lb_hrs > 0 && (
<span style={{ float: "right", paddingleft: "1rem" }}>
{`${item.mod_lb_hrs} units`}
</span>
)}
<span style={{ float: "right", paddingleft: "1rem" }}>
{item.act_price
? `$${item.act_price && item.act_price.toFixed(2)}`

View File

@@ -5,6 +5,7 @@ import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { useLocation } from "react-router-dom";
import { QUERY_CSI_RESPONSE_BY_PK } from "../../graphql/csi.queries";
import { DateFormatter } from "../../utils/DateFormatter";
import AlertComponent from "../alert/alert.component";
import ConfigFormComponents from "../config-form-components/config-form-components.component";
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
@@ -44,6 +45,13 @@ export default function CsiResponseFormContainer() {
readOnly
componentList={data.csi_by_pk.csiquestion.config}
/>
{data.csi_by_pk.validuntil ? (
<>
{t("csi.fields.validuntil")}
{": "}
<DateFormatter>{data.csi_by_pk.validuntil}</DateFormatter>
</>
) : null}
</Form>
</Card>
);

View File

@@ -5,9 +5,11 @@ import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { Link, useHistory, useLocation } from "react-router-dom";
import { DateFormatter } from "../../utils/DateFormatter";
import { alphaSort } from "../../utils/sorters";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
import {pageLimit} from "../../utils/config";
import { pageLimit } from "../../utils/config";
import { alphaSort, dateSort } from "../../utils/sorters";
import OwnerNameDisplay, {
OwnerNameDisplayFunction,
} from "../owner-name-display/owner-name-display.component";
export default function CsiResponseListPaginated({
refetch,
@@ -16,23 +18,23 @@ export default function CsiResponseListPaginated({
total,
}) {
const search = queryString.parse(useLocation().search);
const { responseid, page, sortcolumn, sortorder } = search;
const { responseid } = search;
const history = useHistory();
const { t } = useTranslation();
const [state, setState] = useState({
sortedInfo: {},
filteredInfo: { text: "" },
page: "",
});
const { t } = useTranslation();
const columns = [
{
title: t("jobs.fields.ro_number"),
dataIndex: "ro_number",
key: "ro_number",
width: "8%",
sorter: (a, b) => alphaSort(a.job.ro_number, b.job.ro_number),
sortOrder: sortcolumn === "ro_number" && sortorder,
sortOrder:
state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
render: (text, record) => (
<Link to={"/manage/jobs/" + record.job.id}>
{record.job.ro_number || t("general.labels.na")}
@@ -41,15 +43,18 @@ export default function CsiResponseListPaginated({
},
{
title: t("jobs.fields.owner"),
dataIndex: "owner",
key: "owner",
ellipsis: true,
sorter: (a, b) => alphaSort(a.job.ownr_ln, b.job.ownr_ln),
width: "25%",
sortOrder: sortcolumn === "owner" && sortorder,
dataIndex: "owner_name",
key: "owner_name",
sorter: (a, b) =>
alphaSort(
OwnerNameDisplayFunction(a.job),
OwnerNameDisplayFunction(b.job)
),
sortOrder:
state.sortedInfo.columnKey === "owner_name" && state.sortedInfo.order,
render: (text, record) => {
return record.job.owner ? (
<Link to={"/manage/owners/" + record.job.owner.id}>
return record.job.ownerid ? (
<Link to={"/manage/owners/" + record.job.ownerid}>
<OwnerNameDisplay ownerObject={record.job} />
</Link>
) : (
@@ -64,9 +69,9 @@ export default function CsiResponseListPaginated({
dataIndex: "completedon",
key: "completedon",
ellipsis: true,
sorter: (a, b) => a.completedon - b.completedon,
width: "25%",
sortOrder: sortcolumn === "completedon" && sortorder,
sorter: (a, b) => dateSort(a.completedon, b.completedon),
sortOrder:
state.sortedInfo.columnKey === "completedon" && state.sortedInfo.order,
render: (text, record) => {
return record.completedon ? (
<DateFormatter>{record.completedon}</DateFormatter>
@@ -76,11 +81,12 @@ export default function CsiResponseListPaginated({
];
const handleTableChange = (pagination, filters, sorter) => {
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
search.page = pagination.current;
search.sortcolumn = sorter.columnKey;
search.sortorder = sorter.order;
history.push({ search: queryString.stringify(search) });
setState({
...state,
filteredInfo: filters,
sortedInfo: sorter,
page: pagination.current,
});
};
const handleOnRowClick = (record) => {
@@ -108,7 +114,7 @@ export default function CsiResponseListPaginated({
pagination={{
position: "top",
pageSize: pageLimit,
current: parseInt(page || 1),
current: parseInt(state.page || 1),
total: total,
}}
columns={columns}
@@ -122,13 +128,6 @@ export default function CsiResponseListPaginated({
selectedRowKeys: [responseid],
type: "radio",
}}
onRow={(record, rowIndex) => {
return {
onClick: (event) => {
handleOnRowClick(record);
}, // click row
};
}}
/>
</Card>
);

View File

@@ -1,10 +1,10 @@
import { Select, Space, Tag } from "antd";
import React from "react";
import React, { forwardRef } from "react";
import { useTranslation } from "react-i18next";
const { Option } = Select;
//To be used as a form element only.
const EmployeeSearchSelect = ({ options, ...props }) => {
const EmployeeSearchSelect = ({ options, ...props }, ref) => {
const { t } = useTranslation();
return (
@@ -39,4 +39,4 @@ const EmployeeSearchSelect = ({ options, ...props }) => {
</Select>
);
};
export default EmployeeSearchSelect;
export default forwardRef(EmployeeSearchSelect);

View File

@@ -1,33 +0,0 @@
import { useQuery } from "@apollo/client";
import { Select } from "antd";
import React, { forwardRef } from "react";
import { QUERY_TEAMS } from "../../graphql/employee_teams.queries";
import AlertComponent from "../alert/alert.component";
//To be used as a form element only.
const EmployeeTeamSearchSelect = ({ ...props }, ref) => {
const { loading, error, data } = useQuery(QUERY_TEAMS);
if (error) return <AlertComponent message={JSON.stringify(error)} />;
return (
<Select
showSearch
allowClear
loading={loading}
style={{
width: 400,
}}
options={
data
? data.employee_teams.map((e) => ({
value: JSON.stringify(e),
label: e.name,
}))
: []
}
{...props}
/>
);
};
export default forwardRef(EmployeeTeamSearchSelect);

View File

@@ -2,7 +2,7 @@ import { Button, Col, Collapse, Result, Row, Space } from "antd";
import React from "react";
import { withTranslation } from "react-i18next";
import { logImEXEvent } from "../../firebase/firebase.utils";
import * as Sentry from "@sentry/react";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import {
@@ -40,22 +40,22 @@ class ErrorBoundary extends React.Component {
}
handleErrorSubmit = () => {
// window.$crisp.push([
// "do",
// "message:send",
// [
// "text",
// `I hit the following error: \n\n
// ${this.state.error.message}\n\n
// ${this.state.error.stack}\n\n
// URL:${window.location} as ${this.props.currentUser.email} for ${
// this.props.bodyshop && this.props.bodyshop.name
// }
// `,
// ],
// ]);
window.$crisp.push([
"do",
"message:send",
[
"text",
`I hit the following error: \n\n
${this.state.error.message}\n\n
${this.state.error.stack}\n\n
URL:${window.location} as ${this.props.currentUser.email} for ${
this.props.bodyshop && this.props.bodyshop.name
}
`,
],
]);
// window.$crisp.push(["do", "chat:open"]);
window.$crisp.push(["do", "chat:open"]);
// const errorDescription = `**Please add relevant details about what you were doing before you encountered this issue**
// ----
@@ -138,7 +138,6 @@ class ErrorBoundary extends React.Component {
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(withTranslation()(ErrorBoundary));
export default Sentry.withErrorBoundary(
connect(mapStateToProps, mapDispatchToProps)(withTranslation()(ErrorBoundary))
);

View File

@@ -1,26 +1,9 @@
import Dinero from "dinero.js";
import React, { forwardRef } from "react";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
const ReadOnlyFormItem = (
{ bodyshop, value, type = "text", onChange },
ref
) => {
const ReadOnlyFormItem = ({ value, type = "text", onChange }, ref) => {
if (!value) return null;
switch (type) {
case "employee":
const emp = bodyshop.employees.find((e) => e.id === value);
return `${emp?.first_name} ${emp?.last_name}`;
case "text":
return <div>{value}</div>;
case "currency":
@@ -31,8 +14,4 @@ const ReadOnlyFormItem = (
return <div>{value}</div>;
}
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(forwardRef(ReadOnlyFormItem));
export default forwardRef(ReadOnlyFormItem);

View File

@@ -13,8 +13,7 @@ import Icon, {
FileFilled,
//GlobalOutlined,
HomeFilled,
ImportOutlined,
// InfoCircleOutlined,
ImportOutlined, InfoCircleOutlined,
LineChartOutlined,
PaperClipOutlined,
PhoneOutlined,
@@ -27,11 +26,8 @@ import Icon, {
UserOutlined,
} from "@ant-design/icons";
import { useTreatments } from "@splitsoftware/splitio-react";
import {
Layout,
Menu, // Switch, Tooltip
} from "antd";
import React from "react"; //, { useEffect, useState }
import {Layout, Menu, Switch, Tooltip} from "antd";
import React, {useEffect, useState} from "react";
import { useTranslation } from "react-i18next";
import { BsKanban } from "react-icons/bs";
import {
@@ -56,7 +52,7 @@ import {
selectBodyshop,
selectCurrentUser,
} from "../../redux/user/user.selectors";
//import { handleBeta, setBeta, checkBeta } from "../../utils/handleBeta";
import {handleBeta, setBeta, checkBeta} from "../../utils/handleBeta";
const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser,
@@ -107,20 +103,20 @@ function Header({
{},
bodyshop && bodyshop.imexshopid
);
//const [betaSwitch, setBetaSwitch] = useState(false);
const [betaSwitch, setBetaSwitch] = useState(false);
const { t } = useTranslation();
// useEffect(() => {
// const isBeta = checkBeta();
// setBetaSwitch(isBeta);
// }, []);
useEffect(() => {
const isBeta = checkBeta();
setBetaSwitch(isBeta);
}, []);
// const betaSwitchChange = (checked) => {
// setBeta(checked);
// setBetaSwitch(checked);
// handleBeta();
// };
const betaSwitchChange = (checked) => {
setBeta(checked);
setBetaSwitch(checked);
handleBeta();
}
return (
<Layout.Header>
@@ -285,13 +281,6 @@ function Header({
{t("menus.header.timetickets")}
</Link>
</Menu.Item>
{bodyshop?.md_tasks_presets?.use_approvals && (
<Menu.Item key="ttapprovals" icon={<FieldTimeOutlined />}>
<Link to="/manage/ttapprovals">
{t("menus.header.ttapprovals")}
</Link>
</Menu.Item>
)}
<Menu.Item
key="entertimetickets"
icon={<Icon component={GiPlayerTime} />}
@@ -406,12 +395,20 @@ function Header({
<Menu.Item
key="help"
onClick={() => {
window.open("https://rometech.com/", "_blank");
window.open("https://help.imex.online/", "_blank");
}}
icon={<Icon component={QuestionCircleFilled} />}
>
{t("menus.header.help")}
</Menu.Item>
<Menu.Item
key="rescue"
onClick={() => {
window.open("https://imexrescue.com/", "_blank");
}}
>
{t("menus.header.rescueme")}
</Menu.Item>
<Menu.Item key="shiftclock">
<Link to="/manage/shiftclock">{t("menus.header.shiftclock")}</Link>
</Menu.Item>
@@ -447,18 +444,17 @@ function Header({
</Menu.Item>
))}
</Menu.SubMenu>
{
// <Menu.Item style={{marginLeft: 'auto'}} key="profile">
// <Tooltip title="A more modern ImEX Online is ready for you to try! You can switch back at any time.">
// <InfoCircleOutlined/>
// <span style={{marginRight: 8}}>Try the new ImEX Online</span>
// <Switch
// checked={betaSwitch}
// onChange={betaSwitchChange}
// />
// </Tooltip>
// </Menu.Item>
}
<Menu.Item style={{marginLeft: 'auto'}} key="profile">
<Tooltip title="A more modern ImEX Online is ready for you to try! You can switch back at any time.">
<InfoCircleOutlined/>
<span style={{marginRight: 8}}>Try the new ImEX Online</span>
<Switch
checked={betaSwitch}
onChange={betaSwitchChange}
/>
</Tooltip>
</Menu.Item>
</Menu>
</Layout.Header>
);

View File

@@ -87,8 +87,7 @@ export default function JobBillsTotalComponent({
const totalPartsSublet = Dinero(totals.parts.parts.total)
.add(Dinero(totals.parts.sublets.total))
.add(Dinero(totals.additional.shipping))
.add(Dinero(totals.additional.towing))
.add(Dinero(totals.additional.additionalCosts));
.add(Dinero(totals.additional.towing));
const discrepancy = totalPartsSublet.subtract(billTotals);

View File

@@ -1,52 +1,47 @@
import { Button, notification } from "antd";
import Axios from "axios";
import React, { useState } from "react";
import { useMutation } from "@apollo/client";
import { useTranslation } from "react-i18next";
export default function JobCalculateTotals({ job, disabled, refetch }) {
import { UPDATE_JOB } from "../../graphql/jobs.queries";
import Dinero from "dinero.js";
export default function JobCalculateTotals({ job, disabled }) {
const { t } = useTranslation();
const [loading, setLoading] = useState(false);
const [updateJob] = useMutation(UPDATE_JOB);
const handleCalculate = async () => {
try {
setLoading(true);
setLoading(true);
const newTotals = (
await Axios.post("/job/totals", {
job: job,
})
).data;
await Axios.post("/job/totalsssu", {
id: job.id,
});
if (refetch) refetch();
// const result = await updateJob({
// refetchQueries: ["GET_JOB_BY_PK"],
// awaitRefetchQueries: true,
// variables: {
// jobId: job.id,
// job: {
// job_totals: newTotals,
// clm_total: Dinero(newTotals.totals.total_repairs).toFormat("0.00"),
// owner_owing: Dinero(newTotals.totals.custPayable.total).toFormat(
// "0.00"
// ),
// },
// },
// });
// if (!!!result.errors) {
// notification["success"]({ message: t("jobs.successes.updated") });
// } else {
// notification["error"]({
// message: t("jobs.errors.updating", {
// error: JSON.stringify(result.errors),
// }),
// });
// }
} catch (error) {
const result = await updateJob({
refetchQueries: ["GET_JOB_BY_PK"],
awaitRefetchQueries: true,
variables: {
jobId: job.id,
job: {
job_totals: newTotals,
clm_total: Dinero(newTotals.totals.total_repairs).toFormat("0.00"),
owner_owing: Dinero(newTotals.totals.custPayable.total).toFormat(
"0.00"
),
},
},
});
if (!!!result.errors) {
notification["success"]({ message: t("jobs.successes.updated") });
} else {
notification["error"]({
message: t("jobs.errors.updating", {
error: JSON.stringify(error),
error: JSON.stringify(result.errors),
}),
});
} finally {
setLoading(false);
}
setLoading(false);
};
return (

View File

@@ -32,9 +32,9 @@ const mapDispatchToProps = (dispatch) => ({
});
const span = {
lg: { span: 24 },
xl: { span: 12 },
xxl: { span: 8 },
sm: { span: 24 },
md: { span: 12 },
lg: { span: 8 },
};
export function JobDetailCards({ bodyshop, setPrintCenterContext }) {
@@ -137,6 +137,12 @@ export function JobDetailCards({ bodyshop, setPrintCenterContext }) {
data={data ? data.jobs_by_pk : null}
/>
</Col>
<Col {...span}>
<JobDetailCardsPartsComponent
loading={loading}
data={data ? data.jobs_by_pk : null}
/>
</Col>
<Col {...span}>
<JobDetailCardsNotesComponent
loading={loading}
@@ -157,12 +163,6 @@ export function JobDetailCards({ bodyshop, setPrintCenterContext }) {
data={data ? data.jobs_by_pk : null}
/>
</Col>
<Col span={24}>
<JobDetailCardsPartsComponent
loading={loading}
data={data ? data.jobs_by_pk : null}
/>
</Col>
</Row>
</Card>
) : null}

View File

@@ -1,119 +1,16 @@
import { Table } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import JobLineNotePopup from "../job-line-note-popup/job-line-note-popup.component";
import PartsStatusPie from "../parts-status-pie/parts-status-pie.component";
import CardTemplate from "./job-detail-cards.template.component";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectJobReadOnly } from "../../redux/application/application.selectors";
import { onlyUnique } from "../../utils/arrayHelper";
import { alphaSort } from "../../utils/sorters";
import JobLineLocationPopup from "../job-line-location-popup/job-line-location-popup.component";
import JobLineStatusPopup from "../job-line-status-popup/job-line-status-popup.component";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
jobRO: selectJobReadOnly,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(JobDetailCardsPartsComponent);
export function JobDetailCardsPartsComponent({ loading, data, jobRO }) {
export default function JobDetailCardsPartsComponent({ loading, data }) {
const { t } = useTranslation();
const { joblines_status } = data;
const columns = [
{
title: t("joblines.fields.line_desc"),
dataIndex: "line_desc",
fixed: "left",
key: "line_desc",
sorter: (a, b) => alphaSort(a.line_desc, b.line_desc),
onCell: (record) => ({
className: record.manual_line && "job-line-manual",
style: {
...(record.critical ? { boxShadow: " -.5em 0 0 #FFC107" } : {}),
},
}),
width: "30%",
ellipsis: true,
},
{
title: t("joblines.fields.part_type"),
dataIndex: "part_type",
key: "part_type",
width: "15%",
sorter: (a, b) =>
alphaSort(
t(`joblines.fields.part_types.${a.part_type}`),
t(`joblines.fields.part_types.${b.part_type}`)
),
render: (text, record) =>
record.part_type
? t(`joblines.fields.part_types.${record.part_type}`)
: null,
},
{
title: t("joblines.fields.part_qty"),
dataIndex: "part_qty",
key: "part_qty",
width: "10%",
},
{
title: t("joblines.fields.notes"),
dataIndex: "notes",
key: "notes",
render: (text, record) => (
<JobLineNotePopup disabled={jobRO} jobline={record} />
),
},
{
title: t("joblines.fields.location"),
dataIndex: "location",
key: "location",
sorter: (a, b) => alphaSort(a.location, b.location),
render: (text, record) => (
<JobLineLocationPopup jobline={record} disabled={jobRO} />
),
},
{
title: t("joblines.fields.status"),
dataIndex: "status",
key: "status",
sorter: (a, b) => alphaSort(a.status, b.status),
filters:
(data &&
data.joblines
?.map((l) => l.status)
.filter(onlyUnique)
.map((s) => {
return {
text: s || "No Status*",
value: [s],
};
})) ||
[],
onFilter: (value, record) => value.includes(record.status),
render: (text, record) => (
<JobLineStatusPopup jobline={record} disabled={jobRO} />
),
},
];
return (
<div>
<CardTemplate loading={loading} title={t("jobs.labels.cards.parts")}>
<PartsStatusPie joblines_status={joblines_status} />
<Table
key="id"
columns={columns}
dataSource={data ? data.joblines : []}
/>
</CardTemplate>
</div>
);

View File

@@ -8,18 +8,7 @@ import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { DateFormatter } from "../../utils/DateFormatter";
import AlertComponent from "../alert/alert.component";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(mapStateToProps, mapDispatchToProps)(JobLinesExpander);
export function JobLinesExpander({ jobline, jobid, bodyshop }) {
export default function JobLinesExpander({ jobline, jobid }) {
const { t } = useTranslation();
const { loading, error, data } = useQuery(GET_JOB_LINE_ORDERS, {
fetchPolicy: "network-only",
@@ -34,7 +23,7 @@ export function JobLinesExpander({ jobline, jobid, bodyshop }) {
return (
<Row>
<Col md={24} lg={8}>
<Col md={24} lg={12}>
<Typography.Title level={4}>
{t("parts_orders.labels.parts_orders")}
</Typography.Title>
@@ -60,7 +49,7 @@ export function JobLinesExpander({ jobline, jobid, bodyshop }) {
)}
</Timeline>
</Col>
<Col md={24} lg={8}>
<Col md={24} lg={12}>
<Typography.Title level={4}>{t("bills.labels.bills")}</Typography.Title>
<Timeline>
{data.billlines.length > 0 ? (
@@ -82,7 +71,7 @@ export function JobLinesExpander({ jobline, jobid, bodyshop }) {
</Col>
<Col span={4}>
<span>
{`${t("billlines.fields.actual_cost")}: `}
{`${t("billlines.fields.actual_cost")}: `}
<CurrencyFormatter>{line.actual_cost}</CurrencyFormatter>
</span>
</Col>
@@ -100,37 +89,6 @@ export function JobLinesExpander({ jobline, jobid, bodyshop }) {
)}
</Timeline>
</Col>
<Col md={24} lg={8}>
<Typography.Title level={4}>
{t("parts_dispatch.labels.parts_dispatch")}
</Typography.Title>
<Timeline>
{data.parts_dispatch_lines.length > 0 ? (
data.parts_dispatch_lines.map((line) => (
<Timeline.Item key={line.id}>
<Space split={<Divider type="vertical" />} wrap>
<Link to={`/manage/jobs/${jobid}?partsorderid=${line.id}`}>
{line.parts_dispatch.number}
</Link>
{
bodyshop.employees.find(
(e) => e.id === line.parts_dispatch.employeeid
)?.first_name
}
<Space>
{t("parts_dispatch_lines.fields.accepted_at")}
<DateFormatter>{line.accepted_at}</DateFormatter>
</Space>
</Space>
</Timeline.Item>
))
) : (
<Timeline.Item>
{t("parts_orders.labels.notyetordered")}
</Timeline.Item>
)}
</Timeline>
</Col>
</Row>
);
}

View File

@@ -1,97 +0,0 @@
import { useMutation } from "@apollo/client";
import { Button, Form, notification, Popover, Tooltip } from "antd";
import { t } from "i18next";
import React, { useState } from "react";
import { UPDATE_LINE_PPC } from "../../graphql/jobs-lines.queries";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import CurrencyFormItemComponent from "../form-items-formatted/currency-form-item.component";
import JobLineConvertToLabor from "../job-line-convert-to-labor/job-line-convert-to-labor.component";
import axios from "axios";
export default function JobLinesPartPriceChange({ job, line, refetch }) {
const [loading, setLoading] = useState(false);
const [updatePartPrice] = useMutation(UPDATE_LINE_PPC);
const handleFinish = async (values) => {
try {
setLoading(true);
const result = await updatePartPrice({
variables: {
id: line.id,
jobline: {
act_price_before_ppc: line.act_price_before_ppc
? line.act_price_before_ppc
: line.act_price,
act_price: values.act_price,
},
},
});
await axios.post("/job/totalsssu", {
id: job.id,
});
if (result.errors) {
notification.open({
type: "error",
message: t("joblines.errors.saving", {
error: JSON.stringify(result.errors),
}),
});
if (refetch) refetch();
} else {
notification.open({
type: "success",
message: t("joblines.successes.saved"),
});
}
} catch (error) {
notification.open({
type: "error",
message: t("joblines.errors.saving", { error: JSON.stringify(error) }),
});
} finally {
setLoading(false);
}
};
const popcontent = (
<Form layout="vertical" onFinish={handleFinish} initialValues={{ act_price: line.act_price }}>
<Form.Item
name="act_price"
label={t("jobs.labels.act_price_ppc")}
rules={[{ required: true }]}
>
<CurrencyFormItemComponent />
</Form.Item>
<Button loading={loading} htmlType="primary">
{t("general.actions.save")}
</Button>
</Form>
);
return (
<JobLineConvertToLabor jobline={line} job={job}>
<Popover trigger="click" disabled={line.manual_line} content={popcontent}>
<CurrencyFormatter>
{line.db_ref === "900510" || line.db_ref === "900511"
? line.prt_dsmk_m
: line.act_price}
</CurrencyFormatter>
{line.prt_dsmk_p && line.prt_dsmk_p !== 0 ? (
<span style={{ marginLeft: ".2rem" }}>{`(${line.prt_dsmk_p}%)`}</span>
) : (
<></>
)}
{line.act_price_before_ppc && line.act_price_before_ppc !== 0 ? (
<Tooltip title={t("jobs.labels.ppc")}>
<span style={{ marginLeft: ".2rem", color: "tomato" }}>
(
<CurrencyFormatter>{line.act_price_before_ppc}</CurrencyFormatter>
)
</span>
</Tooltip>
) : (
<></>
)}
</Popover>
</JobLineConvertToLabor>
);
}

View File

@@ -1,12 +1,12 @@
import {
DeleteFilled,
EditFilled,
FilterFilled,
HomeOutlined,
MinusCircleTwoTone,
PlusCircleTwoTone,
SyncOutlined,
WarningFilled,
EditFilled,
PlusCircleTwoTone,
MinusCircleTwoTone,
HomeOutlined,
} from "@ant-design/icons";
import { useMutation } from "@apollo/client";
import {
@@ -29,6 +29,7 @@ import { selectJobReadOnly } from "../../redux/application/application.selectors
import { setModalContext } from "../../redux/modals/modals.actions";
import { selectTechnician } from "../../redux/tech/tech.selectors";
import { onlyUnique } from "../../utils/arrayHelper";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { alphaSort } from "../../utils/sorters";
import JobLineLocationPopup from "../job-line-location-popup/job-line-location-popup.component";
import JobLineNotePopup from "../job-line-note-popup/job-line-note-popup.component";
@@ -37,18 +38,13 @@ import JobLinesBillRefernece from "../job-lines-bill-reference/job-lines-bill-re
// import AllocationsAssignmentContainer from "../allocations-assignment/allocations-assignment.container";
// import AllocationsBulkAssignmentContainer from "../allocations-bulk-assignment/allocations-bulk-assignment.container";
// import AllocationsEmployeeLabelContainer from "../allocations-employee-label/allocations-employee-label.container";
import _ from "lodash";
import moment from "moment";
import { selectBodyshop } from "../../redux/user/user.selectors";
import JobCreateIOU from "../job-create-iou/job-create-iou.component";
import JobSendPartPriceChangeComponent from "../job-send-parts-price-change/job-send-parts-price-change.component";
import PartsOrderModalContainer from "../parts-order-modal/parts-order-modal.container";
import _ from "lodash";
import JobCreateIOU from "../job-create-iou/job-create-iou.component";
import JobLinesExpander from "./job-lines-expander.component";
import JobLinesPartPriceChange from "./job-lines-part-price-change.component";
import JoblineTeamAssignment from "../job-line-team-assignment/job-line-team-assignmnent.component";
import JobLineDispatchButton from "../job-line-dispatch-button/job-line-dispatch-button.component";
import JobLineBulkAssignComponent from "../job-line-bulk-assign/job-line-bulk-assign.component";
import { useTreatments } from "@splitsoftware/splitio-react";
import { selectBodyshop } from "../../redux/user/user.selectors";
import moment from "moment";
import JobLineConvertToLabor from "../job-line-convert-to-labor/job-line-convert-to-labor.component";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -80,16 +76,8 @@ export function JobLinesComponent({
setBillEnterContext,
}) {
const [deleteJobLine] = useMutation(DELETE_JOB_LINE_BY_PK);
const { Enhanced_Payroll } = useTreatments(
["Enhanced_Payroll"],
{},
bodyshop.imexshopid
);
const [selectedLines, setSelectedLines] = useState([]);
console.log(
"🚀 ~ file: job-lines.component.jsx:89 ~ selectedLines:",
selectedLines
);
const [state, setState] = useState({
sortedInfo: {},
filteredInfo: {},
@@ -133,21 +121,10 @@ export function JobLinesComponent({
sortOrder:
state.sortedInfo.columnKey === "oem_partno" && state.sortedInfo.order,
ellipsis: true,
onCell: (record) => ({
className: record.manual_line && "job-line-manual",
style: {
...(record.parts_dispatch_lines[0]?.accepted_at
? { boxShadow: " -.5em 0 0 #FFC107" }
: {}),
},
}),
render: (text, record) => (
<span class="ant-table-cell-content">
{`${record.oem_partno || ""} ${
record.alt_partno ? `(${record.alt_partno})` : ""
}`.trim()}
</span>
),
render: (text, record) =>
`${record.oem_partno || ""} ${
record.alt_partno ? `(${record.alt_partno})` : ""
}`.trim(),
},
{
title: t("joblines.fields.op_code_desc"),
@@ -243,7 +220,20 @@ export function JobLinesComponent({
state.sortedInfo.columnKey === "act_price" && state.sortedInfo.order,
ellipsis: true,
render: (text, record) => (
<JobLinesPartPriceChange line={record} job={job} refetch={refetch} />
<JobLineConvertToLabor jobline={record} job={job}>
<CurrencyFormatter>
{record.db_ref === "900510" || record.db_ref === "900511"
? record.prt_dsmk_m
: record.act_price}
</CurrencyFormatter>
{record.prt_dsmk_p && record.prt_dsmk_p !== 0 ? (
<span
style={{ marginLeft: ".2rem" }}
>{`(${record.prt_dsmk_p}%)`}</span>
) : (
<></>
)}
</JobLineConvertToLabor>
),
},
{
@@ -296,23 +286,6 @@ export function JobLinesComponent({
state.sortedInfo.columnKey === "line_ind" && state.sortedInfo.order,
responsive: ["md"],
},
...(Enhanced_Payroll.treatment === "on"
? [
{
title: t("joblines.fields.assigned_team"),
dataIndex: "assigned_team",
key: "assigned_team",
render: (text, record) => (
<JoblineTeamAssignment
disabled={jobRO}
jobline={record}
jobId={job.id}
/>
),
},
]
: []),
{
title: t("joblines.fields.notes"),
dataIndex: "notes",
@@ -431,11 +404,7 @@ export function JobLinesComponent({
setSelectedLines((selectedLines) =>
_.uniq([
...selectedLines,
...jobLines.filter(
(item) =>
markedTypes.includes(item.part_type) ||
markedTypes.includes(item.mod_lbr_ty)
),
...jobLines.filter((item) => markedTypes.includes(item.part_type)),
])
);
}
@@ -448,21 +417,6 @@ export function JobLinesComponent({
<Menu.Item key="PAL">{t("joblines.fields.part_types.PAL")}</Menu.Item>
<Menu.Item key="PAS">{t("joblines.fields.part_types.PAS")}</Menu.Item>
<Menu.Divider />
<Menu.Item key="LAA">{t("joblines.fields.lbr_types.LAA")}</Menu.Item>
<Menu.Item key="LAB">{t("joblines.fields.lbr_types.LAB")}</Menu.Item>
<Menu.Item key="LAD">{t("joblines.fields.lbr_types.LAD")}</Menu.Item>
<Menu.Item key="LAE">{t("joblines.fields.lbr_types.LAE")}</Menu.Item>
<Menu.Item key="LAF">{t("joblines.fields.lbr_types.LAF")}</Menu.Item>
<Menu.Item key="LAG">{t("joblines.fields.lbr_types.LAG")}</Menu.Item>
<Menu.Item key="LAM">{t("joblines.fields.lbr_types.LAM")}</Menu.Item>
<Menu.Item key="LAR">{t("joblines.fields.lbr_types.LAR")}</Menu.Item>
<Menu.Item key="LAS">{t("joblines.fields.lbr_types.LAS")}</Menu.Item>
<Menu.Item key="LAU">{t("joblines.fields.lbr_types.LAU")}</Menu.Item>
<Menu.Item key="LA1">{t("joblines.fields.lbr_types.LA1")}</Menu.Item>
<Menu.Item key="LA2">{t("joblines.fields.lbr_types.LA2")}</Menu.Item>
<Menu.Item key="LA3">{t("joblines.fields.lbr_types.LA3")}</Menu.Item>
<Menu.Item key="LA4">{t("joblines.fields.lbr_types.LA2")}</Menu.Item>
<Menu.Divider />
<Menu.Item key="clear">{t("general.labels.clear")}</Menu.Item>
</Menu>
);
@@ -486,18 +440,6 @@ export function JobLinesComponent({
</Space>
</Tag>
)}
<JobLineDispatchButton
selectedLines={selectedLines}
setSelectedLines={setSelectedLines}
job={job}
/>
{Enhanced_Payroll.treatment === "on" && (
<JobLineBulkAssignComponent
selectedLines={selectedLines}
setSelectedLines={setSelectedLines}
job={job}
/>
)}
<Button
disabled={
(job && !job.converted) ||
@@ -506,6 +448,15 @@ export function JobLinesComponent({
technician
}
onClick={() => {
// setPartsOrderContext({
// actions: { refetch: refetch },
// context: {
// jobId: job.id,
// job: job,
// linesToOrder: selectedLines,
// },
// });
setBillEnterContext({
actions: { refetch: refetch },
context: {
@@ -612,9 +563,6 @@ export function JobLinesComponent({
>
{t("joblines.actions.new")}
</Button>
{bodyshop.region_config.toLowerCase().startsWith("us") && (
<JobSendPartPriceChangeComponent job={job} />
)}
<JobCreateIOU job={job} selectedJobLines={selectedLines} />
<Input.Search
placeholder={t("general.labels.search")}

View File

@@ -1,149 +0,0 @@
import React, { useState } from "react";
import { useMutation } from "@apollo/client";
import { Button, Form, Popover, Select, Space, notification } from "antd";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { UPDATE_LINE_BULK_ASSIGN } from "../../graphql/jobs-lines.queries";
import { selectJobReadOnly } from "../../redux/application/application.selectors";
import {
selectBodyshop,
selectCurrentUser,
} from "../../redux/user/user.selectors";
import { insertAuditTrail } from "../../redux/application/application.actions";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
jobRO: selectJobReadOnly,
currentUser: selectCurrentUser,
});
const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({ jobid, operation }) =>
dispatch(insertAuditTrail({ jobid, operation })),
});
export default connect(mapStateToProps, mapDispatchToProps)(JoblineBulkAssign);
export function JoblineBulkAssign({
setSelectedLines,
selectedLines,
insertAuditTrail,
bodyshop,
jobRO,
job,
currentUser,
}) {
const [visible, setVisible] = useState(false);
const [loading, setLoading] = useState(false);
const [form] = Form.useForm();
const { t } = useTranslation();
const [assignLines] = useMutation(UPDATE_LINE_BULK_ASSIGN);
const handleConvert = async (values) => {
try {
setLoading(true);
const result = await assignLines({
variables: {
jobline: {
assigned_team: values.assigned_team,
},
ids: selectedLines.map((l) => l.id),
},
});
if (result.errors) {
notification.open({
type: "error",
message: t("parts_dispatch.errors.creating", {
error: JSON.stringify(result.errors),
}),
});
} else {
//Insert the audit trail here.
const teamName = bodyshop.employee_teams.find(
(et) => et.id === values.assigned_team
)?.name;
const hours = selectedLines.reduce(
(acc, val) => (acc += val.mod_lb_hrs),
0
);
insertAuditTrail({
jobid: job.id,
operation: AuditTrailMapping.assignedlinehours(
teamName,
hours.toFixed(1)
),
});
setSelectedLines([]);
setVisible(false);
}
} catch (error) {
notification.open({
type: "error",
message: t("parts_dispatch.errors.creating", {
error: error,
}),
});
} finally {
setLoading(false);
}
};
const popMenu = (
<div>
<Form layout="vertical" form={form} onFinish={handleConvert}>
<Form.Item
name={"assigned_team"}
label={t("joblines.fields.assigned_team")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<Select
showSearch
style={{ width: 200 }}
optionFilterProp="children"
filterOption={(input, option) =>
option.props.children
.toLowerCase()
.indexOf(input.toLowerCase()) >= 0
}
>
{bodyshop.employee_teams.map((team) => (
<Select.Option value={team.id} key={team.id} name={team.name}>
{team.name}
</Select.Option>
))}
</Select>
</Form.Item>
<Space wrap>
<Button type="danger" onClick={() => form.submit()} loading={loading}>
{t("general.actions.save")}
</Button>
<Button onClick={() => setVisible(false)}>
{t("general.actions.cancel")}
</Button>
</Space>
</Form>
</div>
);
return (
<Popover open={visible} content={popMenu}>
<Button
disabled={selectedLines.length === 0 || jobRO}
loading={loading}
onClick={() => setVisible(true)}
>
{t("joblines.actions.assign_team", { count: selectedLines.length })}
</Button>
</Popover>
);
}

View File

@@ -1,167 +0,0 @@
import React, { useState } from "react";
import { useMutation } from "@apollo/client";
import { Button, Form, Popover, Select, Space, notification } from "antd";
import moment from "moment";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { INSERT_PARTS_DISPATCH } from "../../graphql/parts-dispatch.queries";
import { selectJobReadOnly } from "../../redux/application/application.selectors";
import {
selectBodyshop,
selectCurrentUser,
} from "../../redux/user/user.selectors";
import { GenerateDocument } from "../../utils/RenderTemplate";
import { TemplateList } from "../../utils/TemplateConstants";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
jobRO: selectJobReadOnly,
currentUser: selectCurrentUser,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(JobLineDispatchButton);
export function JobLineDispatchButton({
setSelectedLines,
selectedLines,
bodyshop,
jobRO,
job,
currentUser,
}) {
const [visible, setVisible] = useState(false);
const [loading, setLoading] = useState(false);
const [form] = Form.useForm();
const Templates = TemplateList("job_special", {
ro_number: job.ro_number,
});
const { t } = useTranslation();
const [dispatchLines] = useMutation(INSERT_PARTS_DISPATCH);
const handleConvert = async (values) => {
try {
setLoading(true);
//THIS HAS NOT YET BEEN TESTED. START BY FINISHING THIS FUNCTION.
const result = await dispatchLines({
variables: {
partsDispatch: {
dispatched_at: moment(),
employeeid: values.employeeid,
jobid: job.id,
dispatched_by: currentUser.email,
parts_dispatch_lines: {
data: selectedLines.map((l) => ({
joblineid: l.id,
quantity: l.part_qty,
})),
},
},
//joblineids: selectedLines.map((l) => l.id),
},
});
if (result.errors) {
notification.open({
type: "error",
message: t("parts_dispatch.errors.creating", {
error: result.errors,
}),
});
} else {
setSelectedLines([]);
await GenerateDocument(
{
name: Templates.parts_dispatch.key,
variables: {
id: result.data.insert_parts_dispatch_one.id,
},
},
{},
"p"
);
}
setVisible(false);
} catch (error) {
notification.open({
type: "error",
message: t("parts_dispatch.errors.creating", {
error: error,
}),
});
} finally {
setLoading(false);
}
};
const popMenu = (
<div>
<Form layout="vertical" form={form} onFinish={handleConvert}>
<Form.Item
name={"employeeid"}
label={t("timetickets.fields.employee")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<Select
showSearch
style={{ width: 200 }}
optionFilterProp="children"
filterOption={(input, option) =>
option.props.children
.toLowerCase()
.indexOf(input.toLowerCase()) >= 0
}
>
{bodyshop.employees
.filter((emp) => emp.active)
.map((emp) => (
<Select.Option
value={emp.id}
key={emp.id}
name={`${emp.first_name} ${emp.last_name}`}
>
{`${emp.first_name} ${emp.last_name}`}
</Select.Option>
))}
</Select>
</Form.Item>
<Space wrap>
<Button
type="danger"
onClick={() => form.submit()}
loading={loading}
disabled={selectedLines.length === 0}
>
{t("general.actions.save")}
</Button>
<Button onClick={() => setVisible(false)}>
{t("general.actions.cancel")}
</Button>
</Space>
</Form>
</div>
);
return (
<Popover open={visible} content={popMenu}>
<Button
disabled={selectedLines.length === 0 || jobRO}
loading={loading}
onClick={() => setVisible(true)}
>
{t("joblines.actions.dispatchparts", { count: selectedLines.length })}
</Button>
</Popover>
);
}

View File

@@ -1,5 +1,5 @@
import { useMutation } from "@apollo/client";
import { notification, Select, Space } from "antd";
import { notification, Select } from "antd";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
@@ -77,10 +77,7 @@ export function JobLineLocationPopup({ bodyshop, jobline, disabled }) {
style={{ width: "100%", minHeight: "2rem", cursor: "pointer" }}
onClick={() => !disabled && setEditing(true)}
>
<Space wrap>
{jobline.location}
{jobline.parts_dispatch_lines?.length > 0 && "-Disp"}
</Space>
{jobline.location}
</div>
);
}

View File

@@ -1,115 +0,0 @@
import { notification, Select } from "antd";
import React, { useEffect, useState } from "react";
import { useMutation } from "@apollo/client";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { UPDATE_JOB_LINE } from "../../graphql/jobs-lines.queries";
import { selectBodyshop } from "../../redux/user/user.selectors";
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
import { insertAuditTrail } from "../../redux/application/application.actions";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({ jobid, operation }) =>
dispatch(insertAuditTrail({ jobid, operation })),
});
export function JoblineTeamAssignment({
bodyshop,
jobline,
disabled,
jobId,
insertAuditTrail,
}) {
const [editing, setEditing] = useState(false);
const [loading, setLoading] = useState(false);
const [assignedTeam, setAssignedTeam] = useState(jobline.assigned_team);
const [updateJob] = useMutation(UPDATE_JOB_LINE);
const { t } = useTranslation();
useEffect(() => {
if (editing) setAssignedTeam(jobline.assigned_team);
}, [editing, jobline.assigned_team]);
const handleChange = (e) => {
setAssignedTeam(e);
};
const handleSave = async (e) => {
setLoading(true);
const result = await updateJob({
variables: {
lineId: jobline.id,
line: { assigned_team: assignedTeam },
},
});
if (!!!result.errors) {
notification["success"]({ message: t("joblines.successes.saved") });
//insert the audit trail here.
const teamName = bodyshop.employee_teams.find(
(et) => et.id === assignedTeam
)?.name;
insertAuditTrail({
jobid: jobId,
operation: AuditTrailMapping.assignedlinehours(
teamName,
jobline.mod_lb_hrs
),
});
} else {
notification["error"]({
message: t("joblines.errors.saving", {
error: JSON.stringify(result.errors),
}),
});
}
setLoading(false);
setEditing(false);
};
if (editing)
return (
<div>
<LoadingSpinner loading={loading}>
<Select
autoFocus
allowClear
dropdownMatchSelectWidth={100}
value={assignedTeam}
onSelect={handleChange}
onBlur={handleSave}
onClear={() => handleChange(null)}
>
{Object.values(bodyshop.employee_teams).map((s, idx) => (
<Select.Option key={idx} value={s.id}>
{s.name}
</Select.Option>
))}
</Select>
</LoadingSpinner>
</div>
);
const team = bodyshop.employee_teams.find(
(tm) => tm.id === jobline.assigned_team
);
return (
<div
style={{ width: "100%", minHeight: "1rem", cursor: "pointer" }}
onClick={() => !disabled && setEditing(true)}
>
{team?.name}
</div>
);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(JoblineTeamAssignment);

View File

@@ -1,18 +0,0 @@
import { Alert } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
export default function JobProfileDataWarning({ job }) {
const { t } = useTranslation();
let missingProfileInfo =
Object.keys(job.cieca_pft).length === 0 ||
Object.keys(job.cieca_pfl).length === 0 ||
Object.keys(job.materials).length === 0;
if (missingProfileInfo)
return (
<Alert type="error" message={t("jobs.labels.missingprofileinfo")}></Alert>
);
return null;
}

View File

@@ -19,8 +19,7 @@ export default function JobReconciliationModalComponent({ job, bills }) {
const jobLineData = job.joblines.filter(
(j) =>
(j.part_type !== "PAE" && j.act_price !== 0 && j.part_qty !== 0) ||
j.misc_amt !== 0 ||
(j.part_type !== null && j.part_type !== "PAE") ||
(j.line_desc &&
j.line_desc.toLowerCase().includes("towing") &&
j.lbr_op === "OP13") ||

View File

@@ -1,16 +1,16 @@
import { useMutation, useLazyQuery } from "@apollo/client";
import { CheckCircleOutlined } from "@ant-design/icons";
import { useLazyQuery, useMutation } from "@apollo/client";
import {
Button,
Card,
Form,
InputNumber,
notification,
Popover,
Space,
notification,
} from "antd";
import moment from "moment";
import React, { useState, useEffect } from "react";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { logImEXEvent } from "../../firebase/firebase.utils";
import {
@@ -50,6 +50,7 @@ export default function ScoreboardAddButton({
const handleFinish = async (values) => {
logImEXEvent("job_close_add_to_scoreboard");
values.date = moment(values.date).format("YYYY-MM-DD");
setLoading(true);
let result;
@@ -177,7 +178,7 @@ export default function ScoreboardAddButton({
return acc + job.lbr_adjustments[val];
}, 0);
form.setFieldsValue({
date: new moment(),
date: moment(),
bodyhrs: Math.round(v.bodyhrs * 10) / 10,
painthrs: Math.round(v.painthrs * 10) / 10,
});

View File

@@ -1,31 +0,0 @@
import { Button, notification } from "antd";
import axios from "axios";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
export default function JobSendPartPriceChangeComponent({ job }) {
const { t } = useTranslation();
const [loading, setLoading] = useState(false);
const handleClick = async () => {
setLoading(true);
try {
const ppcData = await axios.post("/job/ppc", { jobid: job.id });
await axios.post("http://localhost:1337/ppc/", ppcData.data);
} catch (error) {
notification.open({
type: "error",
message: t("jobs.errors.partspricechange", {
error: JSON.stringify(error),
}),
});
} finally {
setLoading(false);
}
};
return (
<Button onClick={handleClick} loading={loading}>
{t("jobs.actions.sendpartspricechange")}
</Button>
);
}

View File

@@ -67,8 +67,7 @@ export function JobsTotalsTableComponent({ jobRO, currentUser, job }) {
<JobTotalsTableTotals job={job} />
</Card>
</Col>
{(currentUser.email.includes("@imex.") ||
currentUser.email.includes("@rome.")) && (
{currentUser.email.includes("@imex.") && (
<Col span={24}>
<Card title="DEVELOPMENT USE ONLY">
<JobCalculateTotals job={job} disabled={jobRO} />

View File

@@ -123,10 +123,11 @@ export default function JobTotalsTableLabor({ job }) {
<Space>
{t("jobs.labels.mapa")}
{job.materials &&
job.materials.MAPA &&
job.materials.MAPA.cal_maxdlr !== undefined &&
job.materials.mapa &&
job.materials.mapa.cal_maxdlr &&
job.materials.mapa.cal_maxdlr > 0 &&
t("jobs.labels.threshhold", {
amount: job.materials.MAPA.cal_maxdlr,
amount: job.materials.mapa.cal_maxdlr,
})}
</Space>
</Table.Summary.Cell>
@@ -147,10 +148,11 @@ export default function JobTotalsTableLabor({ job }) {
<Space wrap>
{t("jobs.labels.mash")}
{job.materials &&
job.materials.MASH &&
job.materials.MASH.cal_maxdlr !== undefined &&
job.materials.mash &&
job.materials.mash.cal_maxdlr &&
job.materials.mash.cal_maxdlr > 0 &&
t("jobs.labels.threshhold", {
amount: job.materials.MASH.cal_maxdlr,
amount: job.materials.mash.cal_maxdlr,
})}
</Space>
</Table.Summary.Cell>

View File

@@ -11,22 +11,6 @@ export default function JobTotalsTableParts({ job }) {
filteredInfo: {},
});
const insuranceAdjustments = useMemo(() => {
if (!job.job_totals) return [];
if (!job.job_totals?.parts?.adjustments) return [];
const adjs = [];
Object.keys(job.job_totals?.parts?.adjustments).forEach((key) => {
if (Dinero(job.job_totals?.parts?.adjustments[key]).getAmount() !== 0) {
adjs.push({
id: key,
amount: Dinero(job.job_totals.parts.adjustments[key]),
});
}
});
return adjs;
}, [job.job_totals]);
const data = useMemo(() => {
return Object.keys(job.job_totals.parts.parts.list)
.filter(
@@ -90,11 +74,11 @@ export default function JobTotalsTableParts({ job }) {
<Table.Summary.Cell>
{t("jobs.labels.prt_dsmk_total")}
</Table.Summary.Cell>
<Table.Summary.Cell align="right">
{Dinero(job.job_totals.parts.parts.prt_dsmk_total).toFormat()}
</Table.Summary.Cell>
</Table.Summary.Row>
<Table.Summary.Row>
<Table.Summary.Cell>
<strong>{t("jobs.labels.partstotal")}</strong>
@@ -106,24 +90,6 @@ export default function JobTotalsTableParts({ job }) {
</strong>
</Table.Summary.Cell>
</Table.Summary.Row>
{insuranceAdjustments.length > 0 && (
<Table.Summary.Row>
<Table.Summary.Cell colSpan={24}>
{t("jobs.labels.profileadjustments")}
</Table.Summary.Cell>
</Table.Summary.Row>
)}
{insuranceAdjustments.map((adj, idx) => (
<Table.Summary.Row key={idx}>
<Table.Summary.Cell>
{t(`jobs.fields.${adj.id.toLowerCase()}`)}
</Table.Summary.Cell>
<Table.Summary.Cell align="right">
{adj.amount.toFormat()}
</Table.Summary.Cell>
</Table.Summary.Row>
))}
</>
)}
/>

View File

@@ -28,109 +28,26 @@ export function JobTotalsTableTotals({ bodyshop, job }) {
total: job.job_totals.totals.subtotal,
bold: true,
},
...(job.job_totals.totals.us_sales_tax_breakdown
{
key: t("jobs.labels.local_tax_amt"),
total: job.job_totals.totals.local_tax,
},
{
key: t("jobs.labels.state_tax_amt"),
total: job.job_totals.totals.state_tax,
},
...(bodyshop.region_config === "CA_BC"
? [
{
key: `${
bodyshop.md_responsibility_centers.taxes.tax_ty1?.tax_type1 ||
"T1"
} - ${[
job.cieca_pft.ty1_rate1,
job.cieca_pft.ty1_rate2,
job.cieca_pft.ty1_rate3,
job.cieca_pft.ty1_rate4,
job.cieca_pft.ty1_rate5,
]
.filter((i) => i > 0)
.join(", ")}%`,
total: job.job_totals.totals.us_sales_tax_breakdown.ty1Tax,
key: t("jobs.fields.ca_bc_pvrt"),
total: job.job_totals.additional.pvrt,
},
{
key: `${
bodyshop.md_responsibility_centers.taxes.tax_ty2?.tax_type2 ||
"T2"
} - ${[
job.cieca_pft.ty2_rate1,
job.cieca_pft.ty2_rate2,
job.cieca_pft.ty2_rate3,
job.cieca_pft.ty2_rate4,
job.cieca_pft.ty2_rate5,
]
.filter((i) => i > 0)
.join(", ")}%`,
total: job.job_totals.totals.us_sales_tax_breakdown.ty2Tax,
},
{
key: `${
bodyshop.md_responsibility_centers.taxes.tax_ty3?.tax_type3 ||
"T3"
} - ${[
job.cieca_pft.ty3_rate1,
job.cieca_pft.ty3_rate2,
job.cieca_pft.ty3_rate3,
job.cieca_pft.ty3_rate4,
job.cieca_pft.ty3_rate5,
]
.filter((i) => i > 0)
.join(", ")}%`,
total: job.job_totals.totals.us_sales_tax_breakdown.ty3Tax,
},
{
key: `${
bodyshop.md_responsibility_centers.taxes.tax_ty4?.tax_type4 ||
"T4"
} - ${[
job.cieca_pft.ty4_rate1,
job.cieca_pft.ty4_rate2,
job.cieca_pft.ty4_rate3,
job.cieca_pft.ty4_rate4,
job.cieca_pft.ty4_rate5,
]
.filter((i) => i > 0)
.join(", ")}%`,
total: job.job_totals.totals.us_sales_tax_breakdown.ty4Tax,
},
{
key: `${
bodyshop.md_responsibility_centers.taxes.tax_ty5?.tax_type5 ||
"TT"
} - ${[
job.cieca_pft.ty5_rate1,
job.cieca_pft.ty5_rate2,
job.cieca_pft.ty5_rate3,
job.cieca_pft.ty5_rate4,
job.cieca_pft.ty5_rate5,
]
.filter((i) => i > 0)
.join(", ")}%`,
total: job.job_totals.totals.us_sales_tax_breakdown.ty5Tax,
},
{
key: t("jobs.labels.total_sales_tax"),
bold: true,
total: Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty1Tax)
.add(
Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty2Tax)
)
.add(
Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty3Tax)
)
.add(
Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty4Tax)
)
.add(
Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty5Tax)
).toJSON(),
},
].filter((item) => item.total.amount !== 0)
: [
{
key: t("jobs.labels.state_tax_amt"),
total: job.job_totals.totals.state_tax,
},
]),
]
: []),
{
key: t("jobs.labels.federal_tax_amt"),
total: job.job_totals.totals.federal_tax,
},
{
key: t("jobs.labels.total_repairs"),
total: job.job_totals.totals.total_repairs,
@@ -140,10 +57,10 @@ export function JobTotalsTableTotals({ bodyshop, job }) {
key: t("jobs.fields.ded_amt"),
total: job.job_totals.totals.custPayable.deductible,
},
// {
// key: t("jobs.fields.federal_tax_payable"),
// total: job.job_totals.totals.custPayable.federal_tax,
// },
{
key: t("jobs.fields.federal_tax_payable"),
total: job.job_totals.totals.custPayable.federal_tax,
},
{
key: t("jobs.fields.other_amount_payable"),
total: job.job_totals.totals.custPayable.other_customer_amount,
@@ -164,7 +81,7 @@ export function JobTotalsTableTotals({ bodyshop, job }) {
bold: true,
},
];
}, [job.job_totals, job.cieca_pft, t, bodyshop.md_responsibility_centers]);
}, [job.job_totals, t, bodyshop.region_config]);
const columns = [
{

View File

@@ -25,7 +25,7 @@ export const GetSupplementDelta = async (client, jobId, newLines) => {
//Found a relevant matching line. Add it to lines to update.
linesToUpdate.push({
id: existingLines[matchingIndex].id,
newData: { ...newLine, removed: false, act_price_before_ppc: null },
newData: { ...newLine, removed: false },
});
//Splice out item we found for performance.

View File

@@ -6,10 +6,10 @@ import {
useQuery,
} from "@apollo/client";
import { useTreatments } from "@splitsoftware/splitio-react";
import { Button, Col, Row, notification } from "antd";
import { Col, Row, notification } from "antd";
import Axios from "axios";
import _ from "lodash";
import moment from "moment";
import Dinero from "dinero.js";
import moment from "moment-business-days";
import queryString from "query-string";
import React, { useCallback, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
@@ -31,6 +31,7 @@ import {
selectCurrentUser,
} from "../../redux/user/user.selectors";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
import confirmDialog from "../../utils/asyncConfirm";
import CriticalPartsScan from "../../utils/criticalPartsScan";
import AlertComponent from "../alert/alert.component";
import JobsAvailableScan from "../jobs-available-scan/jobs-available-scan.component";
@@ -72,7 +73,15 @@ export function JobsAvailableContainer({
const [selectedJob, setSelectedJob] = useState(null);
const [selectedOwner, setSelectedOwner] = useState(null);
const [partsQueueToggle, setPartsQueueToggle] = useState(bodyshop.md_functionality_toggles.parts_queue_toggle);
const [partsQueueToggle, setPartsQueueToggle] = useState(
bodyshop.md_functionality_toggles.parts_queue_toggle
);
const [updateSchComp, setSchComp] = useState({
actual_in: moment(),
checked: false,
scheduled_completion: moment(),
automatic: false,
});
const [insertLoading, setInsertLoading] = useState(false);
@@ -91,15 +100,14 @@ export function JobsAvailableContainer({
const modalSearchState = useState("");
//Import Scenario
const onOwnerFindModalOk = async (lazyData) => {
const onOwnerFindModalOk = async () => {
logImEXEvent("job_import_new");
setOwnerModalVisible(false);
setInsertLoading(true);
const estData = replaceEmpty(
lazyData?.available_jobs_by_pk || estDataRaw.data.available_jobs_by_pk
);
const estData = replaceEmpty(estDataRaw.data.available_jobs_by_pk);
if (!(estData && estData.est_data)) {
//We don't have the right data. Error!
@@ -109,21 +117,17 @@ export function JobsAvailableContainer({
});
return;
}
// if (process.env.REACT_APP_COUNTRY === "USA") {
//Massage the CCC file set to remove duplicate UNQ_SEQ.
await ResolveCCCLineIssues(estData.est_data, bodyshop);
// } else {
//IO-539 Check for Parts Rate on PAL for SGI use case.
await CheckTaxRates(estData.est_data, bodyshop);
// }
// const newTotals = (
// await Axios.post("/job/totals", {
// job: {
// ...estData.est_data,
// joblines: estData.est_data.joblines.data,
// },
// })
// ).data;
const newTotals = (
await Axios.post("/job/totals", {
job: {
...estData.est_data,
joblines: estData.est_data.joblines.data,
},
})
).data;
let existingVehicles;
if (estData.est_data.v_vin) {
@@ -138,9 +142,9 @@ export function JobsAvailableContainer({
const newJob = {
...estData.est_data,
// clm_total: Dinero(newTotals.totals.total_repairs).toFormat("0.00"),
// owner_owing: Dinero(newTotals.totals.custPayable.total).toFormat("0.00"),
// job_totals: newTotals,
clm_total: Dinero(newTotals.totals.total_repairs).toFormat("0.00"),
owner_owing: Dinero(newTotals.totals.custPayable.total).toFormat("0.00"),
job_totals: newTotals,
date_open: moment(),
status: bodyshop.md_ro_statuses.default_imported,
notes: {
@@ -164,23 +168,17 @@ export function JobsAvailableContainer({
delete newJob.vehicle;
}
if (typeof newJob.kmin === "string") {
newJob.kmin = null;
}
try {
const r = await insertNewJob({
variables: {
job: newJob,
},
});
await Axios.post("/job/totalsssu", {
id: r.data.insert_jobs.returning[0].id,
});
if (CriticalPartsScanning.treatment === "on") {
CriticalPartsScan(r.data.insert_jobs.returning[0].id);
}
notification["success"]({
message: t("jobs.successes.created"),
onClick: () => {
@@ -194,7 +192,7 @@ export function JobsAvailableContainer({
operation: AuditTrailMapping.jobimported(),
});
await deleteJob({
deleteJob({
variables: { id: estData.id },
}).then((r) => {
refetch();
@@ -202,15 +200,20 @@ export function JobsAvailableContainer({
});
setPartsQueueToggle(bodyshop.md_functionality_toggles.parts_queue_toggle);
} catch (r) {
} catch (err) {
//error while inserting
notification["error"]({
message: t("jobs.errors.creating", { error: r.message }),
message: t("jobs.errors.creating", { error: err.message }),
});
refetch().catch((e) => {
console.error(
`Something went wrong in jobs available table container - ${
err.message || ""
}`
);
});
refetch();
setInsertLoading(false);
setPartsQueueToggle(bodyshop.md_functionality_toggles.parts_queue_toggle);
}
};
@@ -234,7 +237,22 @@ export function JobsAvailableContainer({
let supp = replaceEmpty({ ...estData.est_data });
//IO-539 Check for Parts Rate on PAL for SGI use case.
await CheckTaxRates(supp, bodyshop);
await ResolveCCCLineIssues(supp, bodyshop);
if (updateSchComp.checked === true) {
if (updateSchComp.automatic === true) {
const job_hrs = supp.joblines.data.reduce(
(acc, val) => acc + val.mod_lb_hrs,
0
);
const num_days = job_hrs / bodyshop.target_touchtime;
supp.actual_in = updateSchComp.actual_in;
supp.scheduled_completion = moment(
updateSchComp.actual_in
).businessAdd(num_days, "days");
} else {
supp.scheduled_completion = updateSchComp.scheduled_completion;
}
}
delete supp.owner;
delete supp.vehicle;
@@ -272,9 +290,9 @@ export function JobsAvailableContainer({
},
});
setPartsQueueToggle(bodyshop.md_functionality_toggles.parts_queue_toggle);
setPartsQueueToggle(bodyshop.md_functionality_toggles.parts_queue_toggle);
if (CriticalPartsScanning.treatment === "on") {
if (CriticalPartsScanning.treatment === "on") {
CriticalPartsScan(updateResult.data.update_jobs.returning[0].id);
}
if (updateResult.errors) {
@@ -378,7 +396,6 @@ export function JobsAvailableContainer({
if (error) return <AlertComponent type="error" message={error.message} />;
return (
<LoadingSpinner
loading={insertLoading}
@@ -395,7 +412,6 @@ export function JobsAvailableContainer({
visible={ownerModalVisible}
onOk={onOwnerFindModalOk}
onCancel={onOwnerModalCancel}
/>
<JobsFindModalContainer
loading={estDataRaw.loading}
@@ -409,26 +425,9 @@ export function JobsAvailableContainer({
modalSearchState={modalSearchState}
partsQueueToggle={partsQueueToggle}
setPartsQueueToggle={setPartsQueueToggle}
updateSchComp={updateSchComp}
setSchComp={setSchComp}
/>
{currentUser.email.includes("@rome.") ||
currentUser.email.includes("@imex.") ? (
<Button
onClick={async () => {
for (const record of data.available_jobs) {
//Query the data
console.log("Start Job", record.id);
const { data } = await loadEstData({
variables: { id: record.id },
});
console.log("Query has been awaited and is complete");
await onOwnerFindModalOk(data);
}
}}
>
Add all jobs as new.
</Button>
) : null}
<Row gutter={[16, 16]}>
<Col span={24}>
<JobsAvailableTableComponent
@@ -460,158 +459,115 @@ function replaceEmpty(someObj, replaceValue = null) {
}
async function CheckTaxRates(estData, bodyshop) {
// //LKQ Check
// if (
// !estData.parts_tax_rates?.PAL ||
// estData.parts_tax_rates?.PAL?.prt_tax_rt === null ||
// estData.parts_tax_rates?.PAL?.prt_tax_rt === 0
// ) {
// const res = await confirmDialog(
// `Rome Online has detected that there is a missing tax rate for LKQ parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.`
// );
// if (res) {
// if (!estData.parts_tax_rates.PAL) {
// estData.parts_tax_rates.PAL = {
// prt_discp: 0,
// prt_mktyp: true,
// prt_mkupp: 0,
// prt_type: "PAL",
// };
// }
// estData.parts_tax_rates.PAL.prt_tax_rt =
// bodyshop.bill_tax_rates.state_tax_rate / 100;
// estData.parts_tax_rates.PAL.prt_tax_in = true;
// }
// }
// //PAC Check
// if (
// !estData.parts_tax_rates?.PAC ||
// estData.parts_tax_rates?.PAC?.prt_tax_rt === null ||
// estData.parts_tax_rates?.PAC?.prt_tax_rt === 0
// ) {
// const res = await confirmDialog(
// `Rome Online has detected that there is a missing tax rate for rechromed parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.`
// );
// if (res) {
// if (!estData.parts_tax_rates.PAC) {
// estData.parts_tax_rates.PAC = {
// prt_discp: 0,
// prt_mktyp: true,
// prt_mkupp: 0,
// prt_type: "PAC",
// };
// }
// estData.parts_tax_rates.PAC.prt_tax_rt =
// bodyshop.bill_tax_rates.state_tax_rate / 100;
// estData.parts_tax_rates.PAC.prt_tax_in = true;
// }
// }
//LKQ Check
if (
!estData.parts_tax_rates?.PAL ||
estData.parts_tax_rates?.PAL?.prt_tax_rt === null ||
estData.parts_tax_rates?.PAL?.prt_tax_rt === 0
) {
const res = await confirmDialog(
`ImEX Online has detected that there is a missing tax rate for LKQ parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.`
);
if (res) {
if (!estData.parts_tax_rates.PAL) {
estData.parts_tax_rates.PAL = {
prt_discp: 0,
prt_mktyp: true,
prt_mkupp: 0,
prt_type: "PAL",
};
}
estData.parts_tax_rates.PAL.prt_tax_rt =
bodyshop.bill_tax_rates.state_tax_rate / 100;
estData.parts_tax_rates.PAL.prt_tax_in = true;
}
}
//PAC Check
if (
!estData.parts_tax_rates?.PAC ||
estData.parts_tax_rates?.PAC?.prt_tax_rt === null ||
estData.parts_tax_rates?.PAC?.prt_tax_rt === 0
) {
const res = await confirmDialog(
`ImEX Online has detected that there is a missing tax rate for rechromed parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.`
);
if (res) {
if (!estData.parts_tax_rates.PAC) {
estData.parts_tax_rates.PAC = {
prt_discp: 0,
prt_mktyp: true,
prt_mkupp: 0,
prt_type: "PAC",
};
}
estData.parts_tax_rates.PAC.prt_tax_rt =
bodyshop.bill_tax_rates.state_tax_rate / 100;
estData.parts_tax_rates.PAC.prt_tax_in = true;
}
}
//PAM Check
if (!estData.parts_tax_rates?.PAM) {
estData.parts_tax_rates.PAM = estData.parts_tax_rates.PAC;
if (
!estData.parts_tax_rates?.PAM ||
estData.parts_tax_rates?.PAM?.prt_tax_rt === null ||
estData.parts_tax_rates?.PAM?.prt_tax_rt === 0
) {
const res = await confirmDialog(
`ImEX Online has detected that there is a missing tax rate for remanufactured parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.`
);
if (res) {
if (!estData.parts_tax_rates.PAM) {
estData.parts_tax_rates.PAM = {
prt_discp: 0,
prt_mktyp: true,
prt_mkupp: 0,
prt_type: "PAM",
};
}
estData.parts_tax_rates.PAM.prt_tax_rt =
bodyshop.bill_tax_rates.state_tax_rate / 100;
estData.parts_tax_rates.PAM.prt_tax_in = true;
}
}
// //PAM Check
// if (
// !estData.parts_tax_rates?.PAM ||
// estData.parts_tax_rates?.PAM?.prt_tax_rt === null ||
// estData.parts_tax_rates?.PAM?.prt_tax_rt === 0
// ) {
// const res = await confirmDialog(
// `Rome Online has detected that there is a missing tax rate for remanufactured parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.`
// );
// if (res) {
// if (!estData.parts_tax_rates.PAM) {
// estData.parts_tax_rates.PAM = {
// prt_discp: 0,
// prt_mktyp: true,
// prt_mkupp: 0,
// prt_type: "PAM",
// };
// }
// estData.parts_tax_rates.PAM.prt_tax_rt =
// bodyshop.bill_tax_rates.state_tax_rate / 100;
// estData.parts_tax_rates.PAM.prt_tax_in = true;
// }
// }
// if (
// !estData.parts_tax_rates?.PAR ||
// estData.parts_tax_rates?.PAR?.prt_tax_rt === null ||
// estData.parts_tax_rates?.PAR?.prt_tax_rt === 0
// ) {
// const res = await confirmDialog(
// `Rome Online has detected that there is a missing tax rate for recored parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.`
// );
// if (res) {
// if (!estData.parts_tax_rates.PAR) {
// estData.parts_tax_rates.PAR = {
// prt_discp: 0,
// prt_mktyp: true,
// prt_mkupp: 0,
// prt_type: "PAR",
// };
// }
// estData.parts_tax_rates.PAR.prt_tax_rt =
// bodyshop.bill_tax_rates.state_tax_rate / 100;
// estData.parts_tax_rates.PAR.prt_tax_in = true;
// }
// }
if (
!estData.parts_tax_rates?.PAR ||
estData.parts_tax_rates?.PAR?.prt_tax_rt === null ||
estData.parts_tax_rates?.PAR?.prt_tax_rt === 0
) {
const res = await confirmDialog(
`ImEX Online has detected that there is a missing tax rate for recored parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.`
);
if (res) {
if (!estData.parts_tax_rates.PAR) {
estData.parts_tax_rates.PAR = {
prt_discp: 0,
prt_mktyp: true,
prt_mkupp: 0,
prt_type: "PAR",
};
}
estData.parts_tax_rates.PAR.prt_tax_rt =
bodyshop.bill_tax_rates.state_tax_rate / 100;
estData.parts_tax_rates.PAR.prt_tax_in = true;
}
}
//IO-1387 If a sublet line is NOT R&R, use the labor tax. If it is, use the sublet tax rate.
//Currently limited to SK shops only.
if (bodyshop.region_config === "CA_SK") {
estData.joblines.data.forEach((jl, index) => {
if (
(jl.part_type === "PASL" || jl.part_type === "PAS") &&
jl.lbr_op !== "OP11"
) {
estData.joblines.data[index].tax_part = jl.lbr_tax;
}
//if (bodyshop.region_config === "CA_SK") {
estData.joblines.data.forEach((jl, index) => {
if (
(jl.part_type === "PASL" || jl.part_type === "PAS") &&
jl.lbr_op !== "OP11"
) {
estData.joblines.data[index].tax_part = jl.lbr_tax;
}
//Set markup lines and tax lines as taxable.
//900510 is a mark up. 900510 is a discount.
if (jl.db_ref === "900510") {
estData.joblines.data[index].tax_part = true;
}
});
}
}
async function ResolveCCCLineIssues(estData, bodyshop) {
//Find all misc amounts, populate them to the act price.
//TODO Ensure that this doesnt get violated
//This needs to be done before cleansing unq_seq since some misc prices could move over.
estData.joblines.data.forEach((line) => {
if (line.misc_amt && line.misc_amt !== 0) {
line.act_price = line.act_price + line.misc_amt;
line.tax_part = !!line.misc_tax;
//Set markup lines and tax lines as taxable.
//900510 is a mark up. 900510 is a discount.
if (jl.db_ref === "900510") {
estData.joblines.data[index].tax_part = true;
}
});
//Generate the list of duplicated UNQ_SEQ that will feed into the next section to scrub the lines.
const unqSeqHash = _.groupBy(estData.joblines.data, "unq_seq");
const duplicatedUnqSeq = Object.keys(unqSeqHash).filter(
(key) => unqSeqHash[key].length > 1
);
duplicatedUnqSeq.forEach((unq_seq) => {
//Keys are strings, convert to int.
const int_unq_seq = parseInt(unq_seq);
//When line splitting, the first line is always the non-refinish line. We will keep it as is.
//We will cleanse the second line, which is always the next line.
const nonRefLineIndex = estData.joblines.data.findIndex(
(line) => line.unq_seq === int_unq_seq
);
estData.joblines.data[nonRefLineIndex + 1] = {
...estData.joblines.data[nonRefLineIndex + 1],
part_type: null,
act_price: 0,
db_price: 0,
prt_dsmk_p: 0,
prt_dsmk_m: 0,
};
});
//}
}

View File

@@ -36,8 +36,6 @@ export function JobsCloseAutoAllocate({ bodyshop, joblines, form, disabled }) {
ret.profitcenter_part = defaults.profits["MAPA"];
} else if (lineDesc.includes("ats amount")) {
ret.profitcenter_part = defaults.profits["ATS"];
} else if (jl.act_price > 0) {
ret.profitcenter_part = defaults.profits["PAO"];
} else {
ret.profitcenter_part = null;
}

View File

@@ -1,4 +1,4 @@
import { Collapse, Form, Input, Select, Switch } from "antd";
import { Collapse, Form, Input, InputNumber, Select, Switch } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
@@ -12,12 +12,6 @@ import FormItemPhone, {
} from "../form-items-formatted/phone-form-item.component";
import JobsDetailRatesChangeButton from "../jobs-detail-rates-change-button/jobs-detail-rates-change-button.component";
import JobsDetailRatesParts from "../jobs-detail-rates/jobs-detail-rates.parts.component";
import JobsDetailRatesLabor from "../jobs-detail-rates/jobs-detail-rates.labor.component";
import JobsDetailRatesMaterials from "../jobs-detail-rates/jobs-detail-rates.materials.component";
import JobsDetailRatesOther from "../jobs-detail-rates/jobs-detail-rates.other.component";
import JobsDetailRatesTaxes from "../jobs-detail-rates/jobs-detail-rates.taxes.component";
import JobsMarkPstExempt from "../jobs-mark-pst-exempt/jobs-mark-pst-exempt.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
const mapStateToProps = createStructuredSelector({
@@ -264,28 +258,26 @@ export function JobsCreateJobsInfo({ bodyshop, form, selected }) {
<CurrencyInput />
</Form.Item>
</LayoutFormRow>
{
// <LayoutFormRow>
// <Form.Item
// label={t("jobs.fields.federal_tax_rate")}
// name="federal_tax_rate"
// >
// <InputNumber min={0} max={1} precision={2} />
// </Form.Item>
// <Form.Item
// label={t("jobs.fields.state_tax_rate")}
// name="state_tax_rate"
// >
// <InputNumber min={0} max={1} precision={2} />
// </Form.Item>
// <Form.Item
// label={t("jobs.fields.local_tax_rate")}
// name="local_tax_rate"
// >
// <InputNumber min={0} max={1} precision={2} />
// </Form.Item>
// </LayoutFormRow>
}
<LayoutFormRow>
<Form.Item
label={t("jobs.fields.federal_tax_rate")}
name="federal_tax_rate"
>
<InputNumber min={0} max={1} precision={2} />
</Form.Item>
<Form.Item
label={t("jobs.fields.state_tax_rate")}
name="state_tax_rate"
>
<InputNumber min={0} max={1} precision={2} />
</Form.Item>
<Form.Item
label={t("jobs.fields.local_tax_rate")}
name="local_tax_rate"
>
<InputNumber min={0} max={1} precision={2} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow>
<Form.Item label={t("jobs.fields.rate_lab")} name="rate_lab">
<CurrencyInput />
@@ -364,10 +356,6 @@ export function JobsCreateJobsInfo({ bodyshop, form, selected }) {
required={selected && true}
form={form}
/>
<JobsDetailRatesLabor form={form} />
<JobsDetailRatesMaterials form={form} />
<JobsDetailRatesOther form={form} />
<JobsDetailRatesTaxes form={form} />
</div>
);
}

View File

@@ -50,8 +50,6 @@ const mapDispatchToProps = (dispatch) => ({
dispatch(setModalContext({ context: context, modal: "jobCosting" })),
setTimeTicketContext: (context) =>
dispatch(setModalContext({ context: context, modal: "timeTicket" })),
setTimeTicketTaskContext: (context) =>
dispatch(setModalContext({ context: context, modal: "timeTicketTask" })),
setCardPaymentContext: (context) =>
dispatch(setModalContext({ context: context, modal: "cardPayment" })),
insertAuditTrail: ({ jobid, operation }) =>
@@ -69,7 +67,6 @@ export function JobsDetailHeaderActions({
setJobCostingContext,
jobRO,
setTimeTicketContext,
setTimeTicketTaskContext,
setCardPaymentContext,
insertAuditTrail,
}) {
@@ -279,24 +276,6 @@ export function JobsDetailHeaderActions({
>
{t("timetickets.actions.enter")}
</Menu.Item>
{bodyshop.md_tasks_presets.enable_tasks && (
<Menu.Item
key="claimtimetickettasks"
disabled={
!job.converted ||
(!bodyshop.tt_allow_post_to_invoiced && job.date_invoiced)
}
onClick={() => {
setTimeTicketTaskContext({
actions: {},
context: { jobid: job.id },
});
}}
>
{t("timetickets.actions.claimtasks")}
</Menu.Item>
)}
<Menu.Item
key="enterpayments"
disabled={!job.converted}

View File

@@ -131,12 +131,10 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) {
))}
</DataLabel>
)}
<DataLabel label={t("jobs.fields.production_vars.note")}>
<ProductionListColumnProductionNote record={job} />
</DataLabel>
<Space>
<Space wrap>
{job.special_coverage_policy && (
<Tag color="tomato">
<Space>

View File

@@ -5,13 +5,9 @@ import { createStructuredSelector } from "reselect";
import { selectJobReadOnly } from "../../redux/application/application.selectors";
import LaborAllocationsTableComponent from "../labor-allocations-table/labor-allocations-table.component";
import TimeTicketList from "../time-ticket-list/time-ticket-list.component";
import PayrollLaborAllocationsTable from "../labor-allocations-table/labor-allocations-table.payroll.component";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { useTreatments } from "@splitsoftware/splitio-react";
const mapStateToProps = createStructuredSelector({
jobRO: selectJobReadOnly,
bodyshop: selectBodyshop,
});
export default connect(mapStateToProps, null)(JobsDetailLaborContainer);
@@ -52,7 +48,6 @@ const adjSpan = {
};
export function JobsDetailLaborContainer({
bodyshop,
jobRO,
job,
jobId,
@@ -63,12 +58,6 @@ export function JobsDetailLaborContainer({
techConsole,
adjustments,
}) {
const { Enhanced_Payroll } = useTreatments(
["Enhanced_Payroll"],
{},
bodyshop.imexshopid
);
return (
<Row gutter={[16, 16]}>
<Col {...ticketSpan}>
@@ -81,28 +70,14 @@ export function JobsDetailLaborContainer({
jobId={jobId}
/>
</Col>
{Enhanced_Payroll.treatment === "on" ? (
<Col {...adjSpan}>
<PayrollLaborAllocationsTable
jobId={jobId}
joblines={joblines}
timetickets={timetickets}
refetch={refetch}
adjustments={adjustments}
/>
</Col>
) : (
<Col {...adjSpan}>
<LaborAllocationsTableComponent
jobId={jobId}
joblines={joblines}
timetickets={timetickets}
refetch={refetch}
adjustments={adjustments}
/>
</Col>
)}
<Col {...adjSpan}>
<LaborAllocationsTableComponent
jobId={jobId}
joblines={joblines}
timetickets={timetickets}
adjustments={adjustments}
/>
</Col>
</Row>
);
}

View File

@@ -6,14 +6,12 @@ import BillsListTable from "../bills-list-table/bills-list-table.component";
import JobBillsTotal from "../job-bills-total/job-bills-total.component";
import PartsOrderListTableComponent from "../parts-order-list-table/parts-order-list-table.component";
import PartsOrderModal from "../parts-order-modal/parts-order-modal.container";
import PartsDispatchTable from "../parts-dispatch-table/parts-dispatch-table.component";
export default function JobsDetailPliComponent({
job,
billsQuery,
handleBillOnRowClick,
handlePartsOrderOnRowClick,
handlePartsDispatchOnRowClick,
}) {
return (
<div>
@@ -45,13 +43,6 @@ export default function JobsDetailPliComponent({
billsQuery={billsQuery}
/>
</Col>
<Col span={24}>
<PartsDispatchTable
job={job}
handleOnRowClick={handlePartsDispatchOnRowClick}
billsQuery={billsQuery}
/>
</Col>
</Row>
</div>
);

View File

@@ -39,24 +39,12 @@ export default function JobsDetailPliContainer({ job }) {
}
};
const handlePartsDispatchOnRowClick = (record) => {
if (record) {
if (record.id) {
search.partsdispatchid = record.id;
history.push({ search: queryString.stringify(search) });
}
} else {
delete search.partsdispatchid;
history.push({ search: queryString.stringify(search) });
}
};
return (
<JobsDetailPliComponent
job={job}
billsQuery={billsQuery}
handleBillOnRowClick={handleBillOnRowClick}
handlePartsOrderOnRowClick={handlePartsOrderOnRowClick}
handlePartsDispatchOnRowClick={handlePartsDispatchOnRowClick}
/>
);
}

View File

@@ -1,21 +1,25 @@
import { Divider, Form, Input, Select, Space, Switch, Tooltip } from "antd";
import {
Divider,
Form,
Input,
InputNumber,
Select,
Space,
Switch,
Tooltip,
} from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectJobReadOnly } from "../../redux/application/application.selectors";
import { selectBodyshop } from "../../redux/user/user.selectors";
import CABCpvrtCalculator from "../ca-bc-pvrt-calculator/ca-bc-pvrt-calculator.component";
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
import JobsDetailRatesChangeButton from "../jobs-detail-rates-change-button/jobs-detail-rates-change-button.component";
import JobsMarkPstExempt from "../jobs-mark-pst-exempt/jobs-mark-pst-exempt.component";
import FormRow from "../layout-form-row/layout-form-row.component";
import JobsDetailRatesLabor from "./jobs-detail-rates.labor.component";
import JobsDetailRatesMaterials from "./jobs-detail-rates.materials.component";
import JobsDetailRatesOther from "./jobs-detail-rates.other.component";
import JobsDetailRatesParts from "./jobs-detail-rates.parts.component";
import JobsDetailRatesTaxes from "./jobs-detail-rates.taxes.component";
import JobsDetailRatesProfileOVerride from "./jobs-detail-rates.profile-override.component";
const mapStateToProps = createStructuredSelector({
jobRO: selectJobReadOnly,
@@ -80,7 +84,14 @@ export function JobsDetailRates({ jobRO, form, job, bodyshop }) {
>
<CurrencyInput disabled={jobRO || bodyshop.cdk_dealerid} />
</Form.Item>
{bodyshop.region_config === "CA_BC" && (
<Space align="center">
<Form.Item label={t("jobs.fields.ca_bc_pvrt")} name="ca_bc_pvrt">
<CurrencyInput disabled={jobRO} min={0} />
</Form.Item>
<CABCpvrtCalculator form={form} disabled={jobRO} />
</Space>
)}
<Form.Item
label={t("jobs.fields.auto_add_ats")}
name="auto_add_ats"
@@ -109,7 +120,41 @@ export function JobsDetailRates({ jobRO, form, job, bodyshop }) {
}}
</Form.Item>
</FormRow>
<FormRow>
<Form.Item
label={t("jobs.fields.federal_tax_rate")}
name="federal_tax_rate"
>
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.state_tax_rate")}
name="state_tax_rate"
>
<InputNumber
min={0}
max={1}
precision={2}
disabled={jobRO}
autoComplete="new-password"
/>
</Form.Item>
<Form.Item
label={t("jobs.fields.local_tax_rate")}
name="local_tax_rate"
>
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
{bodyshop.region_config.toLowerCase().startsWith("ca") && (
<Form.Item
label={t("jobs.fields.ca_gst_registrant")}
name="ca_gst_registrant"
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
)}
</FormRow>
<Divider
orientation="left"
type="horizontal"
@@ -197,15 +242,7 @@ export function JobsDetailRates({ jobRO, form, job, bodyshop }) {
<CurrencyInput min={0} disabled={jobRO} />
</Form.Item>
</FormRow>
<Divider orientation="left">Tax Profile</Divider>
<JobsDetailRatesProfileOVerride form={form} />
<JobsDetailRatesParts form={form} />
<JobsDetailRatesLabor form={form} />
<JobsDetailRatesMaterials form={form} />
<JobsDetailRatesOther form={form} />
<JobsDetailRatesTaxes form={form} />
</div>
);
}

View File

@@ -1,427 +0,0 @@
import { Collapse, Form, Switch } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectJobReadOnly } from "../../redux/application/application.selectors";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
const mapStateToProps = createStructuredSelector({
jobRO: selectJobReadOnly,
});
export function JobsDetailRatesLabor({
jobRO,
expanded,
required = true,
form,
}) {
const { t } = useTranslation();
return (
<Collapse defaultActiveKey={expanded && "rates"}>
<Collapse.Panel
forceRender
header={t("jobs.labels.cieca_pfl")}
key="cieca_pfl"
>
<LayoutFormRow header={t("joblines.fields.lbr_types.LAB")}>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
name={["cieca_pfl", "LAB", "lbr_tax_in"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
name={["cieca_pfl", "LAB", "lbr_tx_in1"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in2")}
name={["cieca_pfl", "LAB", "lbr_tx_in2"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in3")}
name={["cieca_pfl", "LAB", "lbr_tx_in3"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in4")}
name={["cieca_pfl", "LAB", "lbr_tx_in4"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in5")}
name={["cieca_pfl", "LAB", "lbr_tx_in5"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.lbr_types.LAD")}>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
name={["cieca_pfl", "LAD", "lbr_tax_in"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
name={["cieca_pfl", "LAD", "lbr_tx_in1"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in2")}
name={["cieca_pfl", "LAD", "lbr_tx_in2"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in3")}
name={["cieca_pfl", "LAD", "lbr_tx_in3"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in4")}
name={["cieca_pfl", "LAD", "lbr_tx_in4"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in5")}
name={["cieca_pfl", "LAD", "lbr_tx_in5"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.lbr_types.LAE")}>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
name={["cieca_pfl", "LAE", "lbr_tax_in"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
name={["cieca_pfl", "LAE", "lbr_tx_in1"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in2")}
name={["cieca_pfl", "LAE", "lbr_tx_in2"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in3")}
name={["cieca_pfl", "LAE", "lbr_tx_in3"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in4")}
name={["cieca_pfl", "LAE", "lbr_tx_in4"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in5")}
name={["cieca_pfl", "LAE", "lbr_tx_in5"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.lbr_types.LAF")}>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
name={["cieca_pfl", "LAF", "lbr_tax_in"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
name={["cieca_pfl", "LAF", "lbr_tx_in1"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in2")}
name={["cieca_pfl", "LAF", "lbr_tx_in2"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in3")}
name={["cieca_pfl", "LAF", "lbr_tx_in3"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in4")}
name={["cieca_pfl", "LAF", "lbr_tx_in4"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in5")}
name={["cieca_pfl", "LAF", "lbr_tx_in5"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.lbr_types.LAG")}>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
name={["cieca_pfl", "LAG", "lbr_tax_in"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
name={["cieca_pfl", "LAG", "lbr_tx_in1"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in2")}
name={["cieca_pfl", "LAG", "lbr_tx_in2"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in3")}
name={["cieca_pfl", "LAG", "lbr_tx_in3"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in4")}
name={["cieca_pfl", "LAG", "lbr_tx_in4"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in5")}
name={["cieca_pfl", "LAG", "lbr_tx_in5"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.lbr_types.LAM")}>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
name={["cieca_pfl", "LAM", "lbr_tax_in"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
name={["cieca_pfl", "LAM", "lbr_tx_in1"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in2")}
name={["cieca_pfl", "LAM", "lbr_tx_in2"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in3")}
name={["cieca_pfl", "LAM", "lbr_tx_in3"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in4")}
name={["cieca_pfl", "LAM", "lbr_tx_in4"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in5")}
name={["cieca_pfl", "LAM", "lbr_tx_in5"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.lbr_types.LAR")}>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
name={["cieca_pfl", "LAR", "lbr_tax_in"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
name={["cieca_pfl", "LAR", "lbr_tx_in1"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in2")}
name={["cieca_pfl", "LAR", "lbr_tx_in2"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in3")}
name={["cieca_pfl", "LAR", "lbr_tx_in3"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in4")}
name={["cieca_pfl", "LAR", "lbr_tx_in4"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in5")}
name={["cieca_pfl", "LAR", "lbr_tx_in5"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.lbr_types.LAS")}>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
name={["cieca_pfl", "LAS", "lbr_tax_in"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
name={["cieca_pfl", "LAS", "lbr_tx_in1"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in2")}
name={["cieca_pfl", "LAS", "lbr_tx_in2"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in3")}
name={["cieca_pfl", "LAS", "lbr_tx_in3"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in4")}
name={["cieca_pfl", "LAS", "lbr_tx_in4"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in5")}
name={["cieca_pfl", "LAS", "lbr_tx_in5"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.lbr_types.LAU")}>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
name={["cieca_pfl", "LAU", "lbr_tax_in"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
name={["cieca_pfl", "LAU", "lbr_tx_in1"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in2")}
name={["cieca_pfl", "LAU", "lbr_tx_in2"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in3")}
name={["cieca_pfl", "LAU", "lbr_tx_in3"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in4")}
name={["cieca_pfl", "LAU", "lbr_tx_in4"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in5")}
name={["cieca_pfl", "LAU", "lbr_tx_in5"]}
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
</LayoutFormRow>
</Collapse.Panel>
</Collapse>
);
}
export default connect(mapStateToProps, null)(JobsDetailRatesLabor);

View File

@@ -1,145 +0,0 @@
import { Collapse, Form, Input, InputNumber, Switch } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectJobReadOnly } from "../../redux/application/application.selectors";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
const mapStateToProps = createStructuredSelector({
jobRO: selectJobReadOnly,
});
export function JobsDetailRatesMaterials({
jobRO,
expanded,
required = true,
form,
}) {
const { t } = useTranslation();
return (
<Collapse defaultActiveKey={expanded && "rates"}>
<Collapse.Panel
forceRender
header={t("jobs.fields.materials.materials")}
key="materials"
>
<LayoutFormRow header={t("jobs.fields.materials.MAPA")}>
<Form.Item
label={t("jobs.fields.materials.cal_maxdlr")}
name={["materials", "MAPA", "cal_maxdlr"]}
>
<InputNumber min={0} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.materials.cal_opcode")}
name={["materials", "MAPA", "cal_opcode"]}
>
<Input disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.materials.tax_ind")}
name={["materials", "MAPA", "tax_ind"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.materials.mat_tx_in1")}
name={["materials", "MAPA", "mat_tx_in1"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.materials.mat_tx_in2")}
name={["materials", "MAPA", "mat_tx_in2"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.materials.mat_tx_in3")}
name={["materials", "MAPA", "mat_tx_in3"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.materials.mat_tx_in4")}
name={["materials", "MAPA", "mat_tx_in4"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.materials.mat_tx_in5")}
name={["materials", "MAPA", "mat_tx_in5"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("jobs.fields.materials.MASH")}>
<Form.Item
label={t("jobs.fields.materials.cal_maxdlr")}
name={["materials", "MASH", "cal_maxdlr"]}
>
<InputNumber min={0} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.materials.cal_opcode")}
name={["materials", "MASH", "cal_opcode"]}
>
<Input disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.materials.tax_ind")}
name={["materials", "MASH", "tax_ind"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.materials.mat_tx_in1")}
name={["materials", "MASH", "mat_tx_in1"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.materials.mat_tx_in2")}
name={["materials", "MASH", "mat_tx_in2"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.materials.mat_tx_in3")}
name={["materials", "MASH", "mat_tx_in3"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.materials.mat_tx_in4")}
name={["materials", "MASH", "mat_tx_in4"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.materials.mat_tx_in5")}
name={["materials", "MASH", "mat_tx_in5"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
</LayoutFormRow>
</Collapse.Panel>
</Collapse>
);
}
export default connect(mapStateToProps, null)(JobsDetailRatesMaterials);

View File

@@ -1,104 +0,0 @@
import { Collapse, Form, Switch } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectJobReadOnly } from "../../redux/application/application.selectors";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
const mapStateToProps = createStructuredSelector({
jobRO: selectJobReadOnly,
});
export function JobsDetailRatesOther({
jobRO,
expanded,
required = true,
form,
}) {
const { t } = useTranslation();
return (
<Collapse defaultActiveKey={expanded && "rates"}>
<Collapse.Panel
forceRender
header={t("jobs.labels.cieca_pfo")}
key="cieca_pfo"
>
<LayoutFormRow noDivider>
<Form.Item
label={t("jobs.fields.cieca_pfo.tow_t_in1")}
name={["cieca_pfo", "tow_t_in1"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfo.tow_t_in2")}
name={["cieca_pfo", "tow_t_in2"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfo.tow_t_in3")}
name={["cieca_pfo", "tow_t_in3"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfo.tow_t_in4")}
name={["cieca_pfo", "tow_t_in4"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfo.tow_t_in5")}
name={["cieca_pfo", "tow_t_in5"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfo.stor_t_in1")}
name={["cieca_pfo", "stor_t_in1"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfo.stor_t_in2")}
name={["cieca_pfo", "stor_t_in2"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfo.stor_t_in3")}
name={["cieca_pfo", "stor_t_in3"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfo.stor_t_in4")}
name={["cieca_pfo", "stor_t_in4"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.cieca_pfo.stor_t_in5")}
name={["cieca_pfo", "stor_t_in5"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
</LayoutFormRow>
</Collapse.Panel>
</Collapse>
);
}
export default connect(mapStateToProps, null)(JobsDetailRatesOther);

View File

@@ -29,7 +29,7 @@ export function JobsDetailRatesParts({
label={t("jobs.fields.parts_tax_rates.prt_discp")}
name={["parts_tax_rates", "PAA", "prt_discp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
@@ -42,7 +42,7 @@ export function JobsDetailRatesParts({
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
name={["parts_tax_rates", "PAA", "prt_mkupp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
@@ -68,58 +68,18 @@ export function JobsDetailRatesParts({
},
]}
>
<InputNumber
min={0}
max={100}
precision={4}
disabled={jobRO}
/>
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in1")}
name={["parts_tax_rates", "PAA", "prt_tx_in1"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in2")}
name={["parts_tax_rates", "PAA", "prt_tx_in2"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in3")}
name={["parts_tax_rates", "PAA", "prt_tx_in3"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in4")}
name={["parts_tax_rates", "PAA", "prt_tx_in4"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in5")}
name={["parts_tax_rates", "PAA", "prt_tx_in5"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.part_types.PAC")}>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_discp")}
name={["parts_tax_rates", "PAC", "prt_discp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
@@ -132,7 +92,7 @@ export function JobsDetailRatesParts({
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
name={["parts_tax_rates", "PAC", "prt_mkupp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
@@ -158,58 +118,18 @@ export function JobsDetailRatesParts({
},
]}
>
<InputNumber
min={0}
max={100}
precision={4}
disabled={jobRO}
/>
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in1")}
name={["parts_tax_rates", "PAC", "prt_tx_in1"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in2")}
name={["parts_tax_rates", "PAC", "prt_tx_in2"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in3")}
name={["parts_tax_rates", "PAC", "prt_tx_in3"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in4")}
name={["parts_tax_rates", "PAC", "prt_tx_in4"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in5")}
name={["parts_tax_rates", "PAC", "prt_tx_in5"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.part_types.PAL")}>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_discp")}
name={["parts_tax_rates", "PAL", "prt_discp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
@@ -222,7 +142,7 @@ export function JobsDetailRatesParts({
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
name={["parts_tax_rates", "PAL", "prt_mkupp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
@@ -248,58 +168,18 @@ export function JobsDetailRatesParts({
},
]}
>
<InputNumber
min={0}
max={100}
precision={4}
disabled={jobRO}
/>
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in1")}
name={["parts_tax_rates", "PAL", "prt_tx_in1"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in2")}
name={["parts_tax_rates", "PAL", "prt_tx_in2"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in3")}
name={["parts_tax_rates", "PAL", "prt_tx_in3"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in4")}
name={["parts_tax_rates", "PAL", "prt_tx_in4"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in5")}
name={["parts_tax_rates", "PAL", "prt_tx_in5"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.part_types.PAG")}>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_discp")}
name={["parts_tax_rates", "PAG", "prt_discp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
@@ -312,7 +192,7 @@ export function JobsDetailRatesParts({
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
name={["parts_tax_rates", "PAG", "prt_mkupp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
@@ -338,58 +218,18 @@ export function JobsDetailRatesParts({
},
]}
>
<InputNumber
min={0}
max={100}
precision={4}
disabled={jobRO}
/>
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in1")}
name={["parts_tax_rates", "PAG", "prt_tx_in1"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in2")}
name={["parts_tax_rates", "PAG", "prt_tx_in2"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in3")}
name={["parts_tax_rates", "PAG", "prt_tx_in3"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in4")}
name={["parts_tax_rates", "PAG", "prt_tx_in4"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in5")}
name={["parts_tax_rates", "PAG", "prt_tx_in5"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.part_types.PAM")}>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_discp")}
name={["parts_tax_rates", "PAM", "prt_discp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
@@ -402,7 +242,7 @@ export function JobsDetailRatesParts({
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
name={["parts_tax_rates", "PAM", "prt_mkupp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
@@ -428,58 +268,18 @@ export function JobsDetailRatesParts({
},
]}
>
<InputNumber
min={0}
max={100}
precision={4}
disabled={jobRO}
/>
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in1")}
name={["parts_tax_rates", "PAM", "prt_tx_in1"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in2")}
name={["parts_tax_rates", "PAM", "prt_tx_in2"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in3")}
name={["parts_tax_rates", "PAM", "prt_tx_in3"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in4")}
name={["parts_tax_rates", "PAM", "prt_tx_in4"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in5")}
name={["parts_tax_rates", "PAM", "prt_tx_in5"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.part_types.PAN")}>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_discp")}
name={["parts_tax_rates", "PAN", "prt_discp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
@@ -492,7 +292,7 @@ export function JobsDetailRatesParts({
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
name={["parts_tax_rates", "PAN", "prt_mkupp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
@@ -518,58 +318,18 @@ export function JobsDetailRatesParts({
},
]}
>
<InputNumber
min={0}
max={100}
precision={4}
disabled={jobRO}
/>
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in1")}
name={["parts_tax_rates", "PAN", "prt_tx_in1"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in2")}
name={["parts_tax_rates", "PAN", "prt_tx_in2"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in3")}
name={["parts_tax_rates", "PAN", "prt_tx_in3"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in4")}
name={["parts_tax_rates", "PAN", "prt_tx_in4"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in5")}
name={["parts_tax_rates", "PAN", "prt_tx_in5"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.part_types.PAO")}>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_discp")}
name={["parts_tax_rates", "PAO", "prt_discp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
@@ -582,7 +342,7 @@ export function JobsDetailRatesParts({
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
name={["parts_tax_rates", "PAO", "prt_mkupp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
@@ -608,58 +368,18 @@ export function JobsDetailRatesParts({
},
]}
>
<InputNumber
min={0}
max={100}
precision={4}
disabled={jobRO}
/>
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in1")}
name={["parts_tax_rates", "PAO", "prt_tx_in1"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in2")}
name={["parts_tax_rates", "PAO", "prt_tx_in2"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in3")}
name={["parts_tax_rates", "PAO", "prt_tx_in3"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in4")}
name={["parts_tax_rates", "PAO", "prt_tx_in4"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in5")}
name={["parts_tax_rates", "PAO", "prt_tx_in5"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.part_types.PAP")}>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_discp")}
name={["parts_tax_rates", "PAP", "prt_discp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
@@ -672,7 +392,7 @@ export function JobsDetailRatesParts({
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
name={["parts_tax_rates", "PAP", "prt_mkupp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
@@ -698,58 +418,18 @@ export function JobsDetailRatesParts({
},
]}
>
<InputNumber
min={0}
max={100}
precision={4}
disabled={jobRO}
/>
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in1")}
name={["parts_tax_rates", "PAP", "prt_tx_in1"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in2")}
name={["parts_tax_rates", "PAP", "prt_tx_in2"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in3")}
name={["parts_tax_rates", "PAP", "prt_tx_in3"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in4")}
name={["parts_tax_rates", "PAP", "prt_tx_in4"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in5")}
name={["parts_tax_rates", "PAP", "prt_tx_in5"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.part_types.PAR")}>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_discp")}
name={["parts_tax_rates", "PAR", "prt_discp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
@@ -762,7 +442,7 @@ export function JobsDetailRatesParts({
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
name={["parts_tax_rates", "PAR", "prt_mkupp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
@@ -788,58 +468,18 @@ export function JobsDetailRatesParts({
},
]}
>
<InputNumber
min={0}
max={100}
precision={4}
disabled={jobRO}
/>
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in1")}
name={["parts_tax_rates", "PAR", "prt_tx_in1"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in2")}
name={["parts_tax_rates", "PAR", "prt_tx_in2"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in3")}
name={["parts_tax_rates", "PAR", "prt_tx_in3"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in4")}
name={["parts_tax_rates", "PAR", "prt_tx_in4"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in5")}
name={["parts_tax_rates", "PAR", "prt_tx_in5"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.part_types.PAS")}>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_discp")}
name={["parts_tax_rates", "PAS", "prt_discp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
@@ -852,7 +492,7 @@ export function JobsDetailRatesParts({
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
name={["parts_tax_rates", "PAS", "prt_mkupp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
@@ -878,58 +518,18 @@ export function JobsDetailRatesParts({
},
]}
>
<InputNumber
min={0}
max={100}
precision={4}
disabled={jobRO}
/>
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in1")}
name={["parts_tax_rates", "PAS", "prt_tx_in1"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in2")}
name={["parts_tax_rates", "PAS", "prt_tx_in2"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in3")}
name={["parts_tax_rates", "PAS", "prt_tx_in3"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in4")}
name={["parts_tax_rates", "PAS", "prt_tx_in4"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in5")}
name={["parts_tax_rates", "PAS", "prt_tx_in5"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.part_types.PASL")}>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_discp")}
name={["parts_tax_rates", "PASL", "prt_discp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
@@ -942,7 +542,7 @@ export function JobsDetailRatesParts({
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
name={["parts_tax_rates", "PASL", "prt_mkupp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
@@ -968,58 +568,18 @@ export function JobsDetailRatesParts({
},
]}
>
<InputNumber
min={0}
max={100}
precision={4}
disabled={jobRO}
/>
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in1")}
name={["parts_tax_rates", "PASL", "prt_tx_in1"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in2")}
name={["parts_tax_rates", "PASL", "prt_tx_in2"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in3")}
name={["parts_tax_rates", "PASL", "prt_tx_in3"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in4")}
name={["parts_tax_rates", "PASL", "prt_tx_in4"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tx_in5")}
name={["parts_tax_rates", "PASL", "prt_tx_in5"]}
valuePropName="checked"
>
<Switch />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.part_types.CCDR")}>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_discp")}
name={["parts_tax_rates", "CCDR", "prt_discp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
@@ -1032,7 +592,7 @@ export function JobsDetailRatesParts({
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
name={["parts_tax_rates", "CCDR", "prt_mkupp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
@@ -1045,7 +605,7 @@ export function JobsDetailRatesParts({
label={t("jobs.fields.parts_tax_rates.prt_tax_rt")}
name={["parts_tax_rates", "CCDR", "prt_tax_rt"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.part_types.CCF")}>
@@ -1053,7 +613,7 @@ export function JobsDetailRatesParts({
label={t("jobs.fields.parts_tax_rates.prt_discp")}
name={["parts_tax_rates", "CCF", "prt_discp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
@@ -1066,7 +626,7 @@ export function JobsDetailRatesParts({
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
name={["parts_tax_rates", "CCF", "prt_mkupp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
@@ -1079,7 +639,7 @@ export function JobsDetailRatesParts({
label={t("jobs.fields.parts_tax_rates.prt_tax_rt")}
name={["parts_tax_rates", "CCF", "prt_tax_rt"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.part_types.CCM")}>
@@ -1087,7 +647,7 @@ export function JobsDetailRatesParts({
label={t("jobs.fields.parts_tax_rates.prt_discp")}
name={["parts_tax_rates", "CCM", "prt_discp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
@@ -1100,7 +660,7 @@ export function JobsDetailRatesParts({
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
name={["parts_tax_rates", "CCM", "prt_mkupp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
@@ -1113,7 +673,7 @@ export function JobsDetailRatesParts({
label={t("jobs.fields.parts_tax_rates.prt_tax_rt")}
name={["parts_tax_rates", "CCM", "prt_tax_rt"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.part_types.CCC")}>
@@ -1121,7 +681,7 @@ export function JobsDetailRatesParts({
label={t("jobs.fields.parts_tax_rates.prt_discp")}
name={["parts_tax_rates", "CCC", "prt_discp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
@@ -1134,7 +694,7 @@ export function JobsDetailRatesParts({
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
name={["parts_tax_rates", "CCC", "prt_mkupp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
@@ -1147,7 +707,7 @@ export function JobsDetailRatesParts({
label={t("jobs.fields.parts_tax_rates.prt_tax_rt")}
name={["parts_tax_rates", "CCC", "prt_tax_rt"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.part_types.CCD")}>
@@ -1155,7 +715,7 @@ export function JobsDetailRatesParts({
label={t("jobs.fields.parts_tax_rates.prt_discp")}
name={["parts_tax_rates", "CCD", "prt_discp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
@@ -1168,7 +728,7 @@ export function JobsDetailRatesParts({
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
name={["parts_tax_rates", "CCD", "prt_mkupp"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
@@ -1181,39 +741,39 @@ export function JobsDetailRatesParts({
label={t("jobs.fields.parts_tax_rates.prt_tax_rt")}
name={["parts_tax_rates", "CCD", "prt_tax_rt"]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow>
<Form.Item label={t("jobs.fields.tax_tow_rt")} name="tax_tow_rt">
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item label={t("jobs.fields.tax_str_rt")} name="tax_str_rt">
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.tax_paint_mat_rt")}
name="tax_paint_mat_rt"
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.tax_shop_mat_rt")}
name="tax_shop_mat_rt"
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item label={t("jobs.fields.tax_sub_rt")} name="tax_sub_rt">
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item label={t("jobs.fields.tax_lbr_rt")} name="tax_lbr_rt">
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.tax_levies_rt")}
name="tax_levies_rt"
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
</LayoutFormRow>
</Collapse.Panel>

View File

@@ -1,42 +0,0 @@
import { Button, Popconfirm } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(JobsDetailRatesProfileOVerride);
export function JobsDetailRatesProfileOVerride({ bodyshop, form }) {
const { t } = useTranslation();
return (
<Popconfirm
onConfirm={() => {
form.setFieldsValue({
cieca_pft: {
...bodyshop.md_responsibility_centers.taxes.tax_ty1,
...bodyshop.md_responsibility_centers.taxes.tax_ty2,
...bodyshop.md_responsibility_centers.taxes.tax_ty3,
...bodyshop.md_responsibility_centers.taxes.tax_ty4,
...bodyshop.md_responsibility_centers.taxes.tax_ty5,
},
materials: bodyshop.md_responsibility_centers.cieca_pfm,
cieca_pfl: bodyshop.md_responsibility_centers.cieca_pfl,
parts_tax_rates: bodyshop.md_responsibility_centers.parts_tax_rates,
});
}}
title={t("jobs.actions.taxprofileoverride_confirm")}
>
<Button type="link">{t("jobs.actions.taxprofileoverride")}</Button>
</Popconfirm>
);
}

View File

@@ -1,155 +0,0 @@
import { Collapse, Divider, Form, Input, InputNumber, Space } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectJobReadOnly } from "../../redux/application/application.selectors";
import { selectBodyshop } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
jobRO: selectJobReadOnly,
bodyshop: selectBodyshop,
});
export function JobsDetailRatesTaxes({
jobRO,
expanded,
bodyshop,
required = true,
form,
}) {
const { t } = useTranslation();
const formItems = [];
for (let tyCounter = 1; tyCounter <= 5; tyCounter++) {
const section = [];
section.push(
TaxFormItems({
typeNum: tyCounter,
rootElements: true,
bodyshop,
jobRO,
})
);
for (let iterator = 1; iterator <= 5; iterator++) {
section.push(
TaxFormItems({
typeNum: tyCounter,
typeNumIterator: iterator,
rootElements: false,
jobRO,
})
);
}
formItems.push(Space({ children: section, wrap: true }));
formItems.push(<Divider />);
}
return (
<Collapse defaultActiveKey={expanded && "rates"}>
<Collapse.Panel
forceRender
header={t("jobs.labels.cieca_pft")}
key="cieca_pft"
>
{formItems}
</Collapse.Panel>
</Collapse>
);
}
export default connect(mapStateToProps, null)(JobsDetailRatesTaxes);
function TaxFormItems({
typeNum,
typeNumIterator,
rootElements,
bodyshopjobRO,
jobRO,
}) {
const { t } = useTranslation();
if (rootElements)
return (
<>
<Form.Item
label={t("bodyshop.fields.responsibilitycenter_tax_type", {
typeNum,
typeNumIterator,
})}
// rules={[
// {
// required: true,
// //message: t("general.validation.required"),
// },
// ]}
name={["cieca_pft", `tax_type${typeNum}`]}
>
<Input disabled={jobRO} />
</Form.Item>
</>
);
return (
<>
<Form.Item
label={t("bodyshop.fields.responsibilitycenter_tax_tier", {
typeNum,
typeNumIterator,
})}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["cieca_pft", `ty${typeNum}_tier${typeNumIterator}`]}
>
<InputNumber precision={0} min={0} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenter_tax_thres", {
typeNum,
typeNumIterator,
})}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["cieca_pft", `ty${typeNum}_thres${typeNumIterator}`]}
>
<InputNumber min={0} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenter_tax_rate", {
typeNum,
typeNumIterator,
})}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["cieca_pft", `ty${typeNum}_rate${typeNumIterator}`]}
>
<InputNumber min={0} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenter_tax_sur", {
typeNum,
typeNumIterator,
})}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["cieca_pft", `ty${typeNum}_sur${typeNumIterator}`]}
>
<InputNumber min={0} precision={2} disabled={jobRO} />
</Form.Item>
</>
);
}

View File

@@ -1,9 +1,11 @@
import { SyncOutlined } from "@ant-design/icons";
import { Checkbox, Divider, Input, Table, Button } from "antd";
import React from "react";
import { Button, Checkbox, Divider, Input, Space, Table } from "antd";
import moment from "moment";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom";
import PhoneFormatter from "../../utils/PhoneFormatter";
import FormDateTimePickerComponent from "../form-date-time-picker/form-date-time-picker.component";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
export default function JobsFindModalComponent({
@@ -16,11 +18,13 @@ export default function JobsFindModalComponent({
jobsListRefetch,
partsQueueToggle,
setPartsQueueToggle,
updateSchComp,
setSchComp,
}) {
const { t } = useTranslation();
const [modalSearch, setModalSearch] = modalSearchState;
const [importOptions, setImportOptions] = importOptionsState;
const [checkUTT, setCheckUTT] = useState(false);
const columns = [
{
title: t("jobs.fields.ro_number"),
@@ -142,6 +146,35 @@ export default function JobsFindModalComponent({
if (record) {
if (record.id) {
setSelectedJob(record.id);
if (record.actual_in && record.scheduled_completion) {
setSchComp({
...updateSchComp,
actual_in: record.actual_in,
scheduled_completion: record.scheduled_completion,
});
} else {
if (record.actual_in && !record.scheduled_completion) {
setSchComp({
...updateSchComp,
actual_in: record.actual_in,
scheduled_completion: moment(),
});
}
if (!record.actual_in && record.scheduled_completion) {
setSchComp({
...updateSchComp,
actual_in: moment(),
scheduled_completion: moment(record.scheduled_completion),
});
}
if (!record.actual_in && !record.scheduled_completion) {
setSchComp({
...updateSchComp,
actual_in: moment(),
scheduled_completion: moment(),
});
}
}
return;
}
}
@@ -177,6 +210,35 @@ export default function JobsFindModalComponent({
rowSelection={{
onSelect: (props) => {
setSelectedJob(props.id);
if (props.actual_in && props.scheduled_completion) {
setSchComp({
...updateSchComp,
actual_in: props.actual_in,
scheduled_completion: props.scheduled_completion,
});
} else {
if (props.actual_in && !props.scheduled_completion) {
setSchComp({
...updateSchComp,
actual_in: props.actual_in,
scheduled_completion: moment(),
});
}
if (!props.actual_in && props.scheduled_completion) {
setSchComp({
...updateSchComp,
actual_in: moment(),
scheduled_completion: moment(props.scheduled_completion),
});
}
if (!props.actual_in && !props.scheduled_completion) {
setSchComp({
...updateSchComp,
actual_in: moment(),
scheduled_completion: moment(),
});
}
}
},
type: "radio",
selectedRowKeys: [selectedJob],
@@ -190,23 +252,58 @@ export default function JobsFindModalComponent({
}}
/>
<Divider />
<Checkbox
defaultChecked={importOptions.overrideHeader}
onChange={(e) =>
setImportOptions({
...importOptions,
overrideHeaders: e.target.checked,
})
}
>
{t("jobs.labels.override_header")}
</Checkbox>
<Checkbox
<Space>
<Checkbox
defaultChecked={importOptions.overrideHeader}
onChange={(e) =>
setImportOptions({
...importOptions,
overrideHeaders: e.target.checked,
})
}
>
{t("jobs.labels.override_header")}
</Checkbox>
<Checkbox
checked={partsQueueToggle}
onChange={(e) => setPartsQueueToggle(e.target.checked)}
>
{t("bodyshop.fields.md_functionality_toggles.parts_queue_toggle")}
</Checkbox>
>
{t("bodyshop.fields.md_functionality_toggles.parts_queue_toggle")}
</Checkbox>
<Checkbox
checked={updateSchComp.checked}
onChange={(e) =>
setSchComp({ ...updateSchComp, checked: e.target.checked })
}
>
{t("jobs.labels.update_scheduled_completion")}
</Checkbox>
{updateSchComp.checked === true ? (
<>
{checkUTT === false ? (
<FormDateTimePickerComponent
value={updateSchComp.scheduled_completion}
onChange={(e) => {
setSchComp({ ...updateSchComp, scheduled_completion: e });
}}
/>
) : null}
<Checkbox
checked={checkUTT}
onChange={(e) => {
setCheckUTT(e.target.checked);
setSchComp({
...updateSchComp,
scheduled_completion: null,
automatic: true,
});
}}
>
{t("jobs.labels.calc_scheuled_completion")}
</Checkbox>
</>
) : null}
</Space>
</div>
);
}

View File

@@ -26,6 +26,8 @@ export default connect(
modalSearchState,
partsQueueToggle,
setPartsQueueToggle,
updateSchComp,
setSchComp,
...modalProps
}) {
const { t } = useTranslation();
@@ -95,6 +97,8 @@ export default connect(
modalSearchState={modalSearchState}
partsQueueToggle={partsQueueToggle}
setPartsQueueToggle={setPartsQueueToggle}
updateSchComp={updateSchComp}
setSchComp={setSchComp}
/>
) : null}
</Modal>

View File

@@ -1,8 +1,8 @@
import {
BranchesOutlined,
ExclamationCircleFilled,
PauseCircleOutlined,
SyncOutlined,
BranchesOutlined,
ExclamationCircleFilled,
PauseCircleOutlined,
SyncOutlined,
} from "@ant-design/icons";
import { useQuery } from "@apollo/client";
import { Button, Card, Grid, Input, Space, Table, Tooltip } from "antd";

View File

@@ -1,333 +0,0 @@
import {
Button,
Card,
Col,
Row,
Space,
Table,
Typography,
notification,
} from "antd";
import { SyncOutlined } from "@ant-design/icons";
import axios from "axios";
import _ from "lodash";
import React, { useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectTechnician } from "../../redux/tech/tech.selectors";
import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import "./labor-allocations-table.styles.scss";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
technician: selectTechnician,
});
export function PayrollLaborAllocationsTable({
jobId,
joblines,
timetickets,
bodyshop,
adjustments,
technician,
refetch,
}) {
const { t } = useTranslation();
const [totals, setTotals] = useState([]);
const [state, setState] = useState({
sortedInfo: {
columnKey: "cost_center",
field: "cost_center",
order: "ascend",
},
filteredInfo: {},
});
useEffect(() => {
async function CalculateTotals() {
const { data } = await axios.post("/payroll/calculatelabor", {
jobid: jobId,
});
setTotals(data);
}
if (!!joblines && !!timetickets && !!bodyshop) {
CalculateTotals();
}
if (!jobId) setTotals([]);
}, [joblines, timetickets, bodyshop, adjustments, jobId]);
const convertedLines = useMemo(
() => joblines && joblines.filter((j) => j.convertedtolbr),
[joblines]
);
const columns = [
{
title: t("timetickets.fields.employee"),
dataIndex: "employeeid",
key: "employeeid",
render: (text, record) => {
if (record.employeeid === undefined) {
return (
<span style={{ color: "tomato", fontWeight: "bolder" }}>
{t("timetickets.labels.unassigned")}
</span>
);
}
const emp = bodyshop.employees.find((e) => e.id === record.employeeid);
return `${emp?.first_name} ${emp?.last_name}`;
},
},
{
title: t("joblines.fields.mod_lbr_ty"),
dataIndex: "mod_lbr_ty",
key: "mod_lbr_ty",
render: (text, record) =>
record.employeeid === undefined ? (
<span style={{ color: "tomato", fontWeight: "bolder" }}>
{t("timetickets.labels.unassigned")}
</span>
) : (
t(`joblines.fields.lbr_types.${record.mod_lbr_ty?.toUpperCase()}`)
),
},
// {
// title: t("timetickets.fields.rate"),
// dataIndex: "rate",
// key: "rate",
// },
{
title: t("jobs.labels.hrs_total"),
dataIndex: "expectedHours",
key: "expectedHours",
sorter: (a, b) => a.expectedHours - b.expectedHours,
sortOrder:
state.sortedInfo.columnKey === "expectedHours" &&
state.sortedInfo.order,
render: (text, record) => record.expectedHours.toFixed(5),
},
{
title: t("jobs.labels.hrs_claimed"),
dataIndex: "claimedHours",
key: "claimedHours",
sorter: (a, b) => a.claimedHours - b.claimedHours,
sortOrder:
state.sortedInfo.columnKey === "claimedHours" && state.sortedInfo.order,
render: (text, record) =>
record.claimedHours && record.claimedHours.toFixed(5),
},
{
title: t("jobs.labels.difference"),
dataIndex: "difference",
key: "difference",
sorter: (a, b) => a.difference - b.difference,
sortOrder:
state.sortedInfo.columnKey === "difference" && state.sortedInfo.order,
render: (text, record) => {
const difference = _.round(
record.expectedHours - record.claimedHours,
5
);
return (
<strong
style={{
color: difference >= 0 ? "green" : "red",
}}
>
{difference}
</strong>
);
},
},
];
const convertedTableCols = [
{
title: t("joblines.fields.line_desc"),
dataIndex: "line_desc",
key: "line_desc",
ellipsis: true,
},
{
title: t("joblines.fields.op_code_desc"),
dataIndex: "op_code_desc",
key: "op_code_desc",
ellipsis: true,
render: (text, record) =>
`${record.op_code_desc || ""}${
record.alt_partm ? ` ${record.alt_partm}` : ""
}`,
},
{
title: t("joblines.fields.act_price"),
dataIndex: "act_price",
key: "act_price",
ellipsis: true,
render: (text, record) => (
<>
<CurrencyFormatter>
{record.db_ref === "900510" || record.db_ref === "900511"
? record.prt_dsmk_m
: record.act_price}
</CurrencyFormatter>
{record.prt_dsmk_p && record.prt_dsmk_p !== 0 ? (
<span
style={{ marginLeft: ".2rem" }}
>{`(${record.prt_dsmk_p}%)`}</span>
) : (
<></>
)}
</>
),
},
{
title: t("joblines.fields.part_qty"),
dataIndex: "part_qty",
key: "part_qty",
},
{
title: t("joblines.fields.mod_lbr_ty"),
dataIndex: "conv_mod_lbr_ty",
key: "conv_mod_lbr_ty",
render: (text, record) =>
record.convertedtolbr_data && record.convertedtolbr_data.mod_lbr_ty,
},
{
title: t("joblines.fields.mod_lb_hrs"),
dataIndex: "conv_mod_lb_hrs",
key: "conv_mod_lb_hrs",
render: (text, record) =>
record.convertedtolbr_data &&
record.convertedtolbr_data.mod_lb_hrs &&
record.convertedtolbr_data.mod_lb_hrs.toFixed(5),
},
];
const handleTableChange = (pagination, filters, sorter) => {
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
};
const summary =
totals &&
totals.reduce(
(acc, val) => {
acc.hrs_total += val.expectedHours;
acc.hrs_claimed += val.claimedHours;
// acc.adjustments += val.adjustments;
acc.difference += val.expectedHours - val.claimedHours;
return acc;
},
{ hrs_total: 0, hrs_claimed: 0, adjustments: 0, difference: 0 }
);
return (
<Row gutter={[16, 16]}>
<Col span={24}>
<Card
title={t("jobs.labels.laborallocations")}
extra={
<Space>
<Button
onClick={async () => {
const response = await axios.post("/payroll/payall", {
jobid: jobId,
});
if (response.status === 200) {
if (response.data.success !== false) {
notification.open({
type: "success",
message: t("timetickets.successes.payall"),
});
} else {
notification.open({
type: "error",
message: t("timetickets.errors.payall", {
error: response.data.error,
}),
});
}
if (refetch) refetch();
} else {
notification.open({
type: "error",
message: t("timetickets.errors.payall", {
error: JSON.stringify(""),
}),
});
}
}}
>
{t("timetickets.actions.payall")}
</Button>
<Button
onClick={async () => {
const { data } = await axios.post("/payroll/calculatelabor", {
jobid: jobId,
});
setTotals(data);
refetch();
}}
>
<SyncOutlined />
</Button>
</Space>
}
>
<Table
columns={columns}
rowKey={(record) => `${record.employeeid} ${record.mod_lbr_ty}`}
pagination={false}
onChange={handleTableChange}
dataSource={totals}
scroll={{
x: true,
}}
summary={() => (
<Table.Summary.Row>
<Table.Summary.Cell>
<Typography.Title level={4}>
{t("general.labels.totals")}
</Typography.Title>
</Table.Summary.Cell>
<Table.Summary.Cell></Table.Summary.Cell>
<Table.Summary.Cell>
{summary.hrs_total.toFixed(5)}
</Table.Summary.Cell>
<Table.Summary.Cell>
{summary.hrs_claimed.toFixed(5)}
</Table.Summary.Cell>
<Table.Summary.Cell>
{summary.difference.toFixed(5)}
</Table.Summary.Cell>
</Table.Summary.Row>
)}
/>
</Card>
</Col>
{convertedLines && convertedLines.length > 0 && (
<Col span={24}>
<Card title={t("jobs.labels.convertedtolabor")}>
<Table
columns={convertedTableCols}
rowKey="id"
pagination={false}
dataSource={convertedLines}
scroll={{
x: true,
}}
/>
</Card>
</Col>
)}
</Row>
);
}
export default connect(mapStateToProps, null)(PayrollLaborAllocationsTable);

View File

@@ -1,81 +0,0 @@
import { useMutation } from "@apollo/client";
import { Button, Card, Col, Row, Table, notification } from "antd";
import moment from "moment-business-days";
import React from "react";
import { useTranslation } from "react-i18next";
import { UPDATE_PARTS_DISPATCH_LINE } from "../../graphql/parts-dispatch.queries";
import { DateTimeFormatter } from "../../utils/DateFormatter";
export default function PartsDispatchExpander({ dispatch, job }) {
const { t } = useTranslation();
const [updateDispatchLine] = useMutation(UPDATE_PARTS_DISPATCH_LINE);
const handleAccept = async ({ partsDispatchLineId }) => {
const accepted_at = moment();
const result = await updateDispatchLine({
variables: { id: partsDispatchLineId, line: { accepted_at } },
optimisticResponse: {
update_parts_dispatch_lines_by_pk: {
accepted_at,
id: partsDispatchLineId,
},
},
});
if (result.errors) {
notification.open({
type: "error",
message: t("parts_dispatch.errors.accepting", {
error: JSON.stringify(result.errors),
}),
});
}
};
const columns = [
{
title: t("joblines.fields.part_qty"),
dataIndex: "quantity",
key: "quantity",
width: "10%",
//sorter: (a, b) => alphaSort(a.number, b.number),
},
{
title: t("joblines.fields.line_desc"),
dataIndex: "joblineid",
key: "joblineid",
//sorter: (a, b) => alphaSort(a.number, b.number),
render: (text, record) => record.jobline.line_desc,
},
{
title: t("parts_dispatch_lines.fields.accepted_at"),
dataIndex: "accepted_at",
key: "accepted_at",
width: "20%",
//sorter: (a, b) => alphaSort(a.number, b.number),
render: (text, record) =>
record.accepted_at ? (
<DateTimeFormatter>{record.accepted_at}</DateTimeFormatter>
) : (
<Button
onClick={() => handleAccept({ partsDispatchLineId: record.id })}
>
{t("parts_dispatch.actions.accept")}
</Button>
),
},
];
return (
<Card>
<Row gutter={[16, 16]}>
<Col span={24}>
<Table
rowKey={"id"}
dataSource={dispatch.parts_dispatch_lines}
columns={columns}
/>
</Col>
</Row>
</Card>
);
}

View File

@@ -1,155 +0,0 @@
import {
MinusCircleTwoTone,
PlusCircleTwoTone,
SyncOutlined,
} from "@ant-design/icons";
import { Button, Card, Input, Space, Table } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectJobReadOnly } from "../../redux/application/application.selectors";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { TemplateList } from "../../utils/TemplateConstants";
import { alphaSort } from "../../utils/sorters";
import PartsDispatchExpander from "../parts-dispatch-expander/parts-dispatch-expander.component";
import PrintWrapperComponent from "../print-wrapper/print-wrapper.component";
const mapStateToProps = createStructuredSelector({
jobRO: selectJobReadOnly,
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({});
export function PartDispatchTableComponent({
bodyshop,
jobRO,
job,
billsQuery,
handleOnRowClick,
}) {
const { t } = useTranslation();
const [state, setState] = useState({
sortedInfo: {},
});
// const search = queryString.parse(useLocation().search);
// const selectedBill = search.billid;
const [searchText, setSearchText] = useState("");
const Templates = TemplateList("job_special");
const { refetch } = billsQuery;
const recordActions = (record) => (
<Space wrap>
<PrintWrapperComponent
templateObject={{
name: Templates.parts_dispatch.key,
variables: { id: record.id },
}}
/>
</Space>
);
const columns = [
{
title: t("parts_dispatch.fields.number"),
dataIndex: "number",
key: "number",
sorter: (a, b) => alphaSort(a.number, b.number),
width: "10%",
sortOrder:
state.sortedInfo.columnKey === "number" && state.sortedInfo.order,
},
{
title: t("timetickets.fields.employee"),
dataIndex: "employeeid",
key: "employeeid",
sorter: (a, b) => alphaSort(a.employeeid, b.employeeid),
sortOrder:
state.sortedInfo.columnKey === "employeeid" && state.sortedInfo.order,
render: (text, record) => {
const e = bodyshop.employees.find((e) => e.id === record.employeeid);
return `${e?.first_name || ""} ${e?.last_name || ""}`.trim();
},
},
{
title: t("parts_dispatch.fields.percent_accepted"),
dataIndex: "percent_accepted",
key: "percent_accepted",
render: (text, record) =>
record.parts_dispatch_lines.length > 0
? `
${(
(record.parts_dispatch_lines.filter((l) => l.accepted_at)
.length /
record.parts_dispatch_lines.length) *
100
).toFixed(0)}%`
: "0%",
},
{
title: t("general.labels.actions"),
dataIndex: "actions",
key: "actions",
width: "10%",
render: (text, record) => recordActions(record, true),
},
];
const handleTableChange = (pagination, filters, sorter) => {
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
};
return (
<Card
title={t("parts_dispatch.labels.parts_dispatch")}
extra={
<Space wrap>
<Button onClick={() => refetch()}>
<SyncOutlined />
</Button>
<Input.Search
placeholder={t("general.labels.search")}
value={searchText}
onChange={(e) => {
e.preventDefault();
setSearchText(e.target.value);
}}
/>
</Space>
}
>
<Table
loading={billsQuery.loading}
scroll={{
x: true, // y: "50rem"
}}
expandable={{
expandedRowRender: (record) => (
<PartsDispatchExpander dispatch={record} job={job} />
),
rowExpandable: (record) => true,
expandIcon: ({ expanded, onExpand, record }) =>
expanded ? (
<MinusCircleTwoTone onClick={(e) => onExpand(record, e)} />
) : (
<PlusCircleTwoTone onClick={(e) => onExpand(record, e)} />
),
}}
columns={columns}
rowKey="id"
dataSource={billsQuery.data ? billsQuery.data.parts_dispatch : []}
onChange={handleTableChange}
/>
</Card>
);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(PartDispatchTableComponent);

View File

@@ -0,0 +1,77 @@
import { useQuery } from "@apollo/client";
import { Card, Divider, Drawer, Grid } from "antd";
import queryString from "query-string";
import React from "react";
import { useTranslation } from "react-i18next";
import { Link, useHistory, useLocation } from "react-router-dom";
import { QUERY_PARTS_QUEUE_CARD_DETAILS } from "../../graphql/jobs.queries";
import AlertComponent from "../alert/alert.component";
import JobsDetailHeader from "../jobs-detail-header/jobs-detail-header.component";
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
import PartsQueueJobLinesComponent from "./parts-queue-job-lines.component";
export default function PartsQueueDetailCard() {
const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
.filter((screen) => !!screen[1])
.slice(-1)[0];
const bpoints = {
xs: "100%",
sm: "100%",
md: "100%",
lg: "75%",
xl: "75%",
xxl: "60%",
};
const drawerPercentage = selectedBreakpoint
? bpoints[selectedBreakpoint[0]]
: "100%";
const searchParams = queryString.parse(useLocation().search);
const { selected } = searchParams;
const history = useHistory();
const { loading, error, data } = useQuery(QUERY_PARTS_QUEUE_CARD_DETAILS, {
variables: { id: selected },
skip: !selected,
fetchPolicy: "network-only",
nextFetchPolicy: "network-only",
});
const { t } = useTranslation();
const handleDrawerClose = () => {
delete searchParams.selected;
history.push({
search: queryString.stringify({
...searchParams,
}),
});
};
return (
<Drawer
visible={!!selected}
destroyOnClose
width={drawerPercentage}
placement="right"
onClose={handleDrawerClose}
>
{loading ? <LoadingSpinner /> : null}
{error ? <AlertComponent message={error.message} type="error" /> : null}
{data ? (
<Card
title={
<Link to={`/manage/jobs/${data.jobs_by_pk.id}`}>
{data.jobs_by_pk.ro_number || t("general.labels.na")}
</Link>
}
>
<JobsDetailHeader job={data ? data.jobs_by_pk : null} />
<Divider type="horizontal" />
<PartsQueueJobLinesComponent
jobLines={data.jobs_by_pk ? data.jobs_by_pk.joblines : null}
/>
</Card>
) : null}
</Drawer>
);
}

View File

@@ -0,0 +1,208 @@
import { Card, Table } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectJobReadOnly } from "../../redux/application/application.selectors";
import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { onlyUnique } from "../../utils/arrayHelper";
import { alphaSort } from "../../utils/sorters";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
jobRO: selectJobReadOnly,
});
const mapDispatchToProps = (dispatch) => ({});
export function PartsQueueJobLinesComponent({ jobRO, loading, jobLines }) {
const [state, setState] = useState({
sortedInfo: {},
filteredInfo: {},
});
const { t } = useTranslation();
const columns = [
{
title: "#",
dataIndex: "line_no",
key: "line_no",
sorter: (a, b) => a.line_no - b.line_no,
sortOrder:
state.sortedInfo.columnKey === "line_no" && state.sortedInfo.order,
},
{
title: t("joblines.fields.line_desc"),
dataIndex: "line_desc",
key: "line_desc",
sorter: (a, b) => alphaSort(a.line_desc, b.line_desc),
onCell: (record) => ({
className: record.manual_line && "job-line-manual",
style: {
...(record.critical ? { boxShadow: " -.5em 0 0 #FFC107" } : {}),
},
}),
sortOrder:
state.sortedInfo.columnKey === "line_desc" && state.sortedInfo.order,
ellipsis: true,
},
{
title: t("joblines.fields.oem_partno"),
dataIndex: "oem_partno",
key: "oem_partno",
sorter: (a, b) => alphaSort(a.oem_partno, b.oem_partno),
sortOrder:
state.sortedInfo.columnKey === "oem_partno" && state.sortedInfo.order,
ellipsis: true,
render: (text, record) =>
`${record.oem_partno || ""} ${
record.alt_partno ? `(${record.alt_partno})` : ""
}`.trim(),
},
{
title: t("joblines.fields.part_type"),
dataIndex: "part_type",
key: "part_type",
filteredValue: state.filteredInfo.part_type || null,
sorter: (a, b) => alphaSort(a.part_type, b.part_type),
sortOrder:
state.sortedInfo.columnKey === "part_type" && state.sortedInfo.order,
filters: [
{
text: t("jobs.labels.partsfilter"),
value: [
"PAN",
"PAC",
"PAR",
"PAL",
"PAA",
"PAM",
"PAP",
"PAS",
"PASL",
"PAG",
],
},
{
text: t("joblines.fields.part_types.PAN"),
value: ["PAN"],
},
{
text: t("joblines.fields.part_types.PAP"),
value: ["PAP"],
},
{
text: t("joblines.fields.part_types.PAL"),
value: ["PAL"],
},
{
text: t("joblines.fields.part_types.PAA"),
value: ["PAA"],
},
{
text: t("joblines.fields.part_types.PAG"),
value: ["PAG"],
},
{
text: t("joblines.fields.part_types.PAS"),
value: ["PAS"],
},
{
text: t("joblines.fields.part_types.PASL"),
value: ["PASL"],
},
{
text: t("joblines.fields.part_types.PAC"),
value: ["PAC"],
},
{
text: t("joblines.fields.part_types.PAR"),
value: ["PAR"],
},
{
text: t("joblines.fields.part_types.PAM"),
value: ["PAM"],
},
],
onFilter: (value, record) => value.includes(record.part_type),
render: (text, record) =>
record.part_type
? t(`joblines.fields.part_types.${record.part_type}`)
: null,
},
{
title: t("joblines.fields.part_qty"),
dataIndex: "part_qty",
key: "part_qty",
},
{
title: t("joblines.fields.act_price"),
dataIndex: "act_price",
key: "act_price",
sorter: (a, b) => a.act_price - b.act_price,
sortOrder:
state.sortedInfo.columnKey === "act_price" && state.sortedInfo.order,
ellipsis: true,
render: (text, record) => (
<CurrencyFormatter>
{record.db_ref === "900510" || record.db_ref === "900511"
? record.prt_dsmk_m
: record.act_price}
</CurrencyFormatter>
),
},
{
title: t("joblines.fields.location"),
dataIndex: "location",
key: "location",
},
{
title: t("joblines.fields.status"),
dataIndex: "status",
key: "status",
sorter: (a, b) => alphaSort(a.status, b.status),
sortOrder:
state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
filteredValue: state.filteredInfo.status || null,
filters:
(jobLines &&
jobLines
.map((l) => l.status)
.filter(onlyUnique)
.map((s) => {
return {
text: s || "No Status*",
value: [s],
};
})) ||
[],
onFilter: (value, record) => value.includes(record.status),
},
];
const handleTableChange = (pagination, filters, sorter) => {
setState((state) => ({
...state,
filteredInfo: filters,
sortedInfo: sorter,
}));
};
return (
<Card title={t("jobs.labels.parts_lines")}>
<Table
columns={columns}
rowKey="id"
loading={loading}
pagination={false}
dataSource={jobLines}
onChange={handleTableChange}
/>
</Card>
);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(PartsQueueJobLinesComponent);

View File

@@ -8,30 +8,28 @@ import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { Link, useHistory, useLocation } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import AlertComponent from "../../components/alert/alert.component";
import JobPartsQueueCount from "../../components/job-parts-queue-count/job-parts-queue-count.component";
import JobRemoveFromPartsQueue from "../../components/job-remove-from-parst-queue/job-remove-from-parts-queue.component";
import OwnerNameDisplay from "../../components/owner-name-display/owner-name-display.component";
import ProductionListColumnComment from "../../components/production-list-columns/production-list-columns.comment.component";
import { QUERY_PARTS_QUEUE } from "../../graphql/jobs.queries";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { DateTimeFormatter, TimeAgoFormatter } from "../../utils/DateFormatter";
import { onlyUnique } from "../../utils/arrayHelper";
import { pageLimit } from "../../utils/config";
import { alphaSort, dateSort } from "../../utils/sorters";
import useLocalStorage from "../../utils/useLocalStorage";
import {pageLimit} from "../../utils/config";
import AlertComponent from "../alert/alert.component";
import JobPartsQueueCount from "../job-parts-queue-count/job-parts-queue-count.component";
import JobRemoveFromPartsQueue from "../job-remove-from-parst-queue/job-remove-from-parts-queue.component";
import OwnerNameDisplay, {
OwnerNameDisplayFunction,
} from "../owner-name-display/owner-name-display.component";
import ProductionListColumnComment from "../production-list-columns/production-list-columns.comment.component";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
export function PartsQueuePageComponent({ bodyshop }) {
export function PartsQueueListComponent({ bodyshop }) {
const searchParams = queryString.parse(useLocation().search);
const {
//page,
sortcolumn,
sortorder,
statusFilters,
} = searchParams;
const { selected, sortcolumn, sortorder, statusFilters } = searchParams;
const history = useHistory();
const [filter, setFilter] = useLocalStorage("filter_parts_queue", null);
@@ -39,19 +37,8 @@ export function PartsQueuePageComponent({ bodyshop }) {
fetchPolicy: "network-only",
nextFetchPolicy: "network-only",
variables: {
// offset: page ? (page - 1) * 25 : 0,
// limit: 25,
statuses: (statusFilters && JSON.parse(statusFilters)) ||
bodyshop.md_ro_statuses.active_statuses || ["Open", "Open*"],
order: [
{
[sortcolumn || "ro_number"]: sortorder
? sortorder === "descend"
? "desc"
: "asc"
: "desc",
},
],
},
});
@@ -107,6 +94,19 @@ export function PartsQueuePageComponent({ bodyshop }) {
history.push({ search: queryString.stringify(searchParams) });
};
const handleOnRowClick = (record) => {
if (record) {
if (record.id) {
history.push({
search: queryString.stringify({
...searchParams,
selected: record.id,
}),
});
}
}
};
const columns = [
{
title: t("jobs.fields.ro_number"),
@@ -125,7 +125,8 @@ export function PartsQueuePageComponent({ bodyshop }) {
title: t("jobs.fields.owner"),
dataIndex: "ownr_ln",
key: "ownr_ln",
sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
sorter: (a, b) =>
alphaSort(OwnerNameDisplayFunction(a), OwnerNameDisplayFunction(b)),
sortOrder: sortcolumn === "ownr_ln" && sortorder,
render: (text, record) => {
return record.ownerid ? (
@@ -139,6 +140,56 @@ export function PartsQueuePageComponent({ bodyshop }) {
);
},
},
{
title: t("jobs.fields.vehicle"),
dataIndex: "vehicle",
key: "vehicle",
ellipsis: true,
sorter: (a, b) =>
alphaSort(
`${a.v_model_yr || ""} ${a.v_make_desc || ""} ${
a.v_model_desc || ""
}`,
`${b.v_model_yr || ""} ${b.v_make_desc || ""} ${b.v_model_desc || ""}`
),
sortOrder: sortcolumn === "vehicle" && sortorder,
render: (text, record) => {
return record.vehicleid ? (
<Link to={"/manage/vehicles/" + record.vehicleid}>
{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
record.v_model_desc || ""
}`}
</Link>
) : (
<span>{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
record.v_model_desc || ""
}`}</span>
);
},
},
{
title: t("jobs.fields.ins_co_nm_short"),
dataIndex: "ins_co_nm",
key: "ins_co_nm",
ellipsis: true,
sorter: (a, b) => alphaSort(a.ins_co_nm, b.ins_co_nm),
sortOrder: sortcolumn === "ins_co_nm" && sortorder,
filteredValue: filter?.ins_co_nm || null,
filters:
(jobs &&
jobs
.map((j) => j.ins_co_nm)
.filter(onlyUnique)
.map((s) => {
return {
text: s || "No Ins. Co.*",
value: [s],
};
})
.sort((a, b) => alphaSort(a.text, b.text))) ||
[],
onFilter: (value, record) => value.includes(record.ins_co_nm),
},
{
title: t("jobs.fields.status"),
dataIndex: "status",
@@ -170,23 +221,16 @@ export function PartsQueuePageComponent({ bodyshop }) {
),
},
{
title: t("jobs.fields.vehicle"),
dataIndex: "vehicle",
key: "vehicle",
title: t("jobs.fields.scheduled_completion"),
dataIndex: "scheduled_completion",
key: "scheduled_completion",
ellipsis: true,
render: (text, record) => {
return record.vehicleid ? (
<Link to={"/manage/vehicles/" + record.vehicleid}>
{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
record.v_model_desc || ""
}`}
</Link>
) : (
<span>{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
record.v_model_desc || ""
}`}</span>
);
},
sorter: (a, b) =>
dateSort(a.scheduled_completion, b.scheduled_completion),
sortOrder: sortcolumn === "scheduled_completion" && sortorder,
render: (text, record) => (
<DateTimeFormatter>{record.scheduled_completion}</DateTimeFormatter>
),
},
// {
// title: t("vehicles.fields.plate_no"),
@@ -198,14 +242,6 @@ export function PartsQueuePageComponent({ bodyshop }) {
// return record.plate_no ? record.plate_no : "";
// },
// },
{
title: t("jobs.fields.clm_no"),
dataIndex: "clm_no",
key: "clm_no",
ellipsis: true,
sorter: (a, b) => alphaSort(a.clm_no, b.clm_no),
sortOrder: sortcolumn === "clm_no" && sortorder,
},
// {
// title: t("jobs.fields.clm_total"),
// dataIndex: "clm_total",
@@ -307,9 +343,16 @@ export function PartsQueuePageComponent({ bodyshop }) {
style={{ height: "100%" }}
scroll={{ x: true }}
onChange={handleTableChange}
rowSelection={{
onSelect: (record) => {
handleOnRowClick(record);
},
selectedRowKeys: [selected],
type: "radio",
}}
/>
</Card>
);
}
export default connect(mapStateToProps, null)(PartsQueuePageComponent);
export default connect(mapStateToProps, null)(PartsQueueListComponent);

View File

@@ -1,4 +1,3 @@
import { useTreatments } from "@splitsoftware/splitio-react";
import { Card, Col, Input, Row, Space, Typography } from "antd";
import _ from "lodash";
import React, { useState } from "react";
@@ -24,13 +23,8 @@ export function PrintCenterJobsComponent({ printCenterModal, bodyshop }) {
const { id: jobId, job } = printCenterModal.context;
const tempList = TemplateList("job", {});
const { t } = useTranslation();
const { Enhanced_Payroll } = useTreatments(
["Enhanced_Payroll"],
{},
bodyshop.imexshopid
);
const Templates =
const JobsReportsList =
bodyshop.cdk_dealerid === null && bodyshop.pbs_serialnumber === null
? Object.keys(tempList)
.map((key) => {
@@ -57,26 +51,7 @@ export function PrintCenterJobsComponent({ printCenterModal, bodyshop }) {
bodyshop.region_config.includes(Object.keys(temp.regions)) ===
true)
);
const JobsReportsList =
Enhanced_Payroll.treatment === "on"
? Object.keys(Templates)
.map((key) => {
return Templates[key];
})
.filter(
(temp) =>
temp.enhanced_payroll === undefined ||
temp.enhanced_payroll === true
)
: Object.keys(Templates)
.map((key) => {
return Templates[key];
})
.filter(
(temp) =>
temp.enhanced_payroll === undefined ||
temp.enhanced_payroll === false
);
const filteredJobsReportsList =
search !== ""
? JobsReportsList.filter((r) =>

View File

@@ -9,11 +9,9 @@ export default function PrintWrapperComponent({
children,
id,
emailOnly = false,
disabled,
}) {
const [loading, setLoading] = useState(false);
const handlePrint = async (type) => {
if (disabled) return;
setLoading(true);
await GenerateDocument(templateObject, messageObject, type, id);
setLoading(false);
@@ -22,18 +20,8 @@ export default function PrintWrapperComponent({
return (
<Space>
{children || null}
{!emailOnly && (
<PrinterFilled
disabled={disabled}
onClick={() => handlePrint("p")}
style={{ cursor: disabled ? "not-allowed" : null }}
/>
)}
<MailFilled
disabled={disabled}
onClick={() => handlePrint("e")}
style={{ cursor: disabled ? "not-allowed" : null }}
/>
{!emailOnly && <PrinterFilled onClick={() => handlePrint("p")} />}
<MailFilled onClick={() => handlePrint("e")} />
{loading && <Spin />}
</Space>
);

View File

@@ -115,7 +115,7 @@ export function ProductionBoardKanbanComponent({
// console.log("==> New Card is somewhere in the middle");
movedCardNewKanbanParent = newChildCard.kanbanparent;
} else {
throw new Error("==> !!!!!!Couldn't find a parent.!!!! <==");
console.log("==> !!!!!!Couldn't find a parent.!!!! <==");
}
const newChildCardNewParent = newChildCard ? card.id : null;
const update = await client.mutate({
@@ -153,7 +153,7 @@ export function ProductionBoardKanbanComponent({
0
)
.toFixed(1);
const totalLAB = data
const totalLAB = data
.reduce(
(acc, val) => acc + (val.labhrs?.aggregate?.sum?.mod_lb_hrs || 0),
0

View File

@@ -25,8 +25,6 @@ import ProductionListColumnNote from "./production-list-columns.productionnote.c
import ProductionListColumnCategory from "./production-list-columns.status.category";
import ProductionListColumnStatus from "./production-list-columns.status.component";
import ProductionlistColumnTouchTime from "./prodution-list-columns.touchtime.component";
import { store } from "../../redux/store";
import { setModalContext } from "../../redux/modals/modals.actions";
const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
return [
@@ -41,29 +39,6 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
</Link>
),
},
{
title: i18n.t("timetickets.actions.claimtasks"),
dataIndex: "claimtasks",
key: "claimtasks",
ellipsis: true,
render: (text, record) => (
<div
onClick={() => {
store.dispatch(
setModalContext({
context: {
actions: {},
context: { jobid: record.id },
},
modal: "timeTicketTask",
})
);
}}
>
{i18n.t("timetickets.actions.claimtasks")}
</div>
),
},
{
title: i18n.t("jobs.fields.ro_number"),
dataIndex: "ro_number",

View File

@@ -97,7 +97,7 @@ export function ProductionListDetail({
/>
}
placement="right"
width={"50%"}
width={"33%"}
onClose={handleClose}
visible={selected}
>

View File

@@ -0,0 +1,273 @@
import {Button, Card, Checkbox, Col, Form, Input, InputNumber, Row, Select} from "antd";
import React, {useEffect, useState} from "react";
import {fetchFilterData} from "../../utils/RenderTemplate";
import {DeleteFilled} from "@ant-design/icons";
import {useTranslation} from "react-i18next";
import {getOperatorsByType} from "../../utils/graphQLmodifier";
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
export default function ReportCenterModalFiltersSortersComponent({form}) {
return (
<Form.Item style={{margin: 0, padding: 0}} dependencies={["key"]}>
{() => {
const key = form.getFieldValue("key");
return <RenderFilters form={form} templateId={key}/>;
}}
</Form.Item>
);
}
function RenderFilters({templateId, form}) {
const [state, setState] = useState(null);
const [visible, setVisible] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const {t} = useTranslation();
useEffect(() => {
const fetch = async () => {
setIsLoading(true);
const data = await fetchFilterData({name: templateId});
if (data?.success) {
setState(data.data);
} else {
setState(null);
}
setIsLoading(false);
};
if (templateId) {
fetch();
}
}, [templateId]);
// Conditional display of filters and sorters
if (!templateId) return null;
if (isLoading) return <LoadingSkeleton/>;
if (!state) return null;
// Filters and Sorters data available
return (
<div style={{marginTop: '10px'}}>
<Checkbox
checked={visible}
onChange={(e) => setVisible(e.target.checked)}
children={t('reportcenter.labels.advanced_filters')}
/>
{visible && (
<div>
{state.filters && state.filters.length > 0 && (
<Card type='inner' title={ t('reportcenter.labels.advanced_filters_filters')} style={{marginTop: '10px'}}>
<Form.List name={["filters"]}>
{(fields, {add, remove, move}) => {
return (
<div>
{fields.map((field, index) => (
<Form.Item key={field.key}>
<Row gutter={[16, 16]}>
<Col span={10}>
<Form.Item
key={`${index}field`}
label="field"
name={[field.name, "field"]}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<Select
options={
state.filters
? state.filters.map((f) => {
return {
value: f.name,
label: f?.translation ? (t(f.translation) === f.translation ? f.label : t(f.translation)) : f.label,
}
})
: []
}
/>
</Form.Item>
</Col>
<Col span={6}>
<Form.Item dependencies={[['filters', field.name, "field"]]}>
{
() => {
const name = form.getFieldValue(['filters', field.name, "field"]);
const type = state.filters.find(f => f.name === name)?.type;
return <Form.Item
key={`${index}operator`}
label="operator"
name={[field.name, "operator"]}
dependencies={[]}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<Select options={getOperatorsByType(type)}/>
</Form.Item>
}
}
</Form.Item>
</Col>
<Col span={6}>
<Form.Item dependencies={[['filters', field.name, "field"]]}>
{
() => {
const name = form.getFieldValue(['filters', field.name, "field"]);
const type = state.filters.find(f => f.name === name)?.type;
return <Form.Item
key={`${index}value`}
label="value"
name={[field.name, "value"]}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
{type === 'number' ?
<InputNumber
onChange={(value) => {
form.setFieldsValue({[field.name]: {value: parseInt(value)}});
}}
/>
:
<Input
onChange={(value) => {
form.setFieldsValue({[field.name]: {value: value.toString()}});
}}
/>
}
</Form.Item>
}
}
</Form.Item>
</Col>
<Col span={2}>
<DeleteFilled
style={{margin: "1rem"}}
onClick={() => {
remove(field.name);
}}
/>
</Col>
</Row>
</Form.Item>
))}
<Form.Item>
<Button
type="dashed"
onClick={() => {
add();
}}
style={{width: "100%"}}
>
{t("general.actions.add")}
</Button>
</Form.Item>
</div>
);
}}
</Form.List>
</Card>
)}
{state.sorters && state.sorters.length > 0 && (
<Card type='inner' title={ t('reportcenter.labels.advanced_filters_sorters')} style={{marginTop: '10px'}}>
<Form.List name={["sorters"]}>
{(fields, {add, remove, move}) => {
return (
<div>
Sorters
{fields.map((field, index) => (
<Form.Item key={field.key}>
<Row gutter={[16, 16]}>
<Col span={11}>
<Form.Item
key={`${index}field`}
label="field"
name={[field.name, "field"]}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<Select
options={
state.sorters
? state.sorters.map((f) => ({
value: f.name,
label: f?.translation ? (t(f.translation) === f.translation ? f.label : t(f.translation)) : f.label,
}))
: []
}
/>
</Form.Item>
</Col>
<Col span={11}>
<Form.Item
key={`${index}direction`}
label="direction"
name={[field.name, "direction"]}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<Select
options={[
{value: "desc", label: "Descending"},
{value: "asc", label: "Ascending"},
]}
/>
</Form.Item>
</Col>
<Col span={2}>
<DeleteFilled
style={{margin: "1rem"}}
onClick={() => {
remove(field.name);
}}
/>
</Col>
</Row>
</Form.Item>
))}
<Form.Item>
<Button
type="dashed"
onClick={() => {
add();
}}
style={{width: "100%"}}
>
{t("general.actions.add")}
</Button>
</Form.Item>
</div>
);
}}
</Form.List>
</Card>
)}
</div>
)}
</div>
);
}

View File

@@ -1,95 +1,62 @@
import { useLazyQuery } from "@apollo/client";
import { useTreatments } from "@splitsoftware/splitio-react";
import {
Button,
Card,
Col,
DatePicker,
Form,
Input,
Radio,
Row,
Typography,
} from "antd";
import {useLazyQuery} from "@apollo/client";
import {Button, Card, Col, DatePicker, Form, Input, Radio, Row, Typography,} from "antd";
import _ from "lodash";
import moment from "moment";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { QUERY_ACTIVE_EMPLOYEES } from "../../graphql/employees.queries";
import { QUERY_ALL_VENDORS } from "../../graphql/vendors.queries";
import { selectReportCenter } from "../../redux/modals/modals.selectors";
import { selectBodyshop } from "../../redux/user/user.selectors";
import DatePIckerRanges from "../../utils/DatePickerRanges";
import { GenerateDocument } from "../../utils/RenderTemplate";
import { TemplateList } from "../../utils/TemplateConstants";
import React, {useState} from "react";
import {useTranslation} from "react-i18next";
import {connect} from "react-redux";
import {createStructuredSelector} from "reselect";
import {QUERY_ACTIVE_EMPLOYEES} from "../../graphql/employees.queries";
import {QUERY_ALL_VENDORS} from "../../graphql/vendors.queries";
import {selectReportCenter} from "../../redux/modals/modals.selectors";
import DatePickerRanges from "../../utils/DatePickerRanges";
import {GenerateDocument} from "../../utils/RenderTemplate";
import {TemplateList} from "../../utils/TemplateConstants";
import EmployeeSearchSelect from "../employee-search-select/employee-search-select.component";
import VendorSearchSelect from "../vendor-search-select/vendor-search-select.component";
import "./report-center-modal.styles.scss";
import ReportCenterModalFiltersSortersComponent from "./report-center-modal-filters-sorters-component";
const mapStateToProps = createStructuredSelector({
reportCenterModal: selectReportCenter,
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(
mapStateToProps,
mapDispatchToProps
mapStateToProps,
mapDispatchToProps
)(ReportCenterModalComponent);
export function ReportCenterModalComponent({ reportCenterModal, bodyshop }) {
export function ReportCenterModalComponent({reportCenterModal}) {
const [form] = Form.useForm();
const [search, setSearch] = useState("");
const { Enhanced_Payroll } = useTreatments(
["Enhanced_Payroll"],
{},
bodyshop.imexshopid
);
const [loading, setLoading] = useState(false);
const { t } = useTranslation();
const {t} = useTranslation();
const Templates = TemplateList("report_center");
const ReportsList =
Enhanced_Payroll.treatment === "on"
? Object.keys(Templates)
.map((key) => {
return Templates[key];
})
.filter(
(temp) =>
temp.enhanced_payroll === undefined ||
temp.enhanced_payroll === true
)
: Object.keys(Templates)
.map((key) => {
return Templates[key];
})
.filter(
(temp) =>
temp.enhanced_payroll === undefined ||
temp.enhanced_payroll === false
);
const { visible } = reportCenterModal;
const ReportsList = Object.keys(Templates).map((key) => {
return Templates[key];
});
const {open} = reportCenterModal;
const [callVendorQuery, { data: vendorData, called: vendorCalled }] =
useLazyQuery(QUERY_ALL_VENDORS, {
skip: !(
visible &&
Templates[form.getFieldValue("key")] &&
Templates[form.getFieldValue("key")].idtype
),
});
const [callVendorQuery, {data: vendorData, called: vendorCalled}] =
useLazyQuery(QUERY_ALL_VENDORS, {
skip: !(
open &&
Templates[form.getFieldValue("key")] &&
Templates[form.getFieldValue("key")].idtype
),
});
const [callEmployeeQuery, { data: employeeData, called: employeeCalled }] =
useLazyQuery(QUERY_ACTIVE_EMPLOYEES, {
skip: !(
visible &&
Templates[form.getFieldValue("key")] &&
Templates[form.getFieldValue("key")].idtype
),
});
const [callEmployeeQuery, {data: employeeData, called: employeeCalled}] =
useLazyQuery(QUERY_ACTIVE_EMPLOYEES, {
skip: !(
open &&
Templates[form.getFieldValue("key")] &&
Templates[form.getFieldValue("key")].idtype
),
});
const handleFinish = async (values) => {
setLoading(true);
@@ -98,243 +65,245 @@ export function ReportCenterModalComponent({ reportCenterModal, bodyshop }) {
const { id } = values;
await GenerateDocument(
{
name: values.key,
variables: {
...(start
? { start: moment(start).startOf("day").format("YYYY-MM-DD") }
: {}),
...(end
? { end: moment(end).endOf("day").format("YYYY-MM-DD") }
: {}),
...(start ? { starttz: moment(start).startOf("day") } : {}),
...(end ? { endtz: moment(end).endOf("day") } : {}),
{
name: values.key,
variables: {
...(start
? { start: moment(start).startOf("day").format("YYYY-MM-DD") }
: {}),
...(end ? { end: moment(end).endOf("day").format("YYYY-MM-DD") } : {}),
...(start ? { starttz: moment(start).startOf("day") } : {}),
...(end ? { endtz: moment(end).endOf("day") } : {}),
...(id ? { id: id } : {}),
...(id ? { id: id } : {}),
},
filters: values.filters,
sorters: values.sorters,
},
},
{
to: values.to,
subject: Templates[values.key]?.subject,
},
values.sendbyexcel === "excel"
? "x"
: values.sendby === "email"
? "e"
: "p",
id
{
to: values.to,
subject: Templates[values.key]?.subject,
},
values.sendbyexcel === "excel"
? "x"
: values.sendby === "email"
? "e"
: "p",
id
);
setLoading(false);
};
const FilteredReportsList =
search !== ""
? ReportsList.filter((r) =>
r.title.toLowerCase().includes(search.toLowerCase())
)
: ReportsList;
search !== ""
? ReportsList.filter((r) =>
r.title.toLowerCase().includes(search.toLowerCase())
)
: ReportsList;
//Group it, create cards, and then filter out.
const grouped = _.groupBy(FilteredReportsList, "group");
return (
<div>
<Form
onFinish={handleFinish}
autoComplete={"off"}
layout="vertical"
form={form}
>
<Input.Search
onChange={(e) => setSearch(e.target.value)}
value={search}
/>
<Form.Item
name="key"
label={t("reportcenter.labels.key")}
// className="radio-group-columns"
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
<div>
<Form
onFinish={handleFinish}
autoComplete={"off"}
layout="vertical"
form={form}
>
<Radio.Group>
{/* {Object.keys(Templates).map((key) => (
<Input.Search
onChange={(e) => setSearch(e.target.value)}
value={search}
/>
<Form.Item
name="key"
label={t("reportcenter.labels.key")}
// className="radio-group-columns"
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<Radio.Group>
{/* {Object.keys(Templates).map((key) => (
<Radio key={key} value={key}>
{Templates[key].title}
</Radio>
))} */}
<Row gutter={[16, 16]}>
{Object.keys(grouped).map((key) => (
<Col md={8} sm={12} key={key}>
<Card.Grid
style={{
width: "100%",
height: "100%",
maxHeight: "33vh",
overflowY: "scroll",
}}
>
<Typography.Title level={4}>
{t(`reportcenter.labels.groups.${key}`)}
</Typography.Title>
<ul style={{ columns: "2 auto" }}>
{grouped[key].map((item) => (
<li key={item.key}>
<Radio key={item.key} value={item.key}>
{item.title}
</Radio>
</li>
))}
</ul>
</Card.Grid>
</Col>
))}
</Row>
</Radio.Group>
</Form.Item>
<Form.Item style={{ margin: 0, padding: 0 }} dependencies={["key"]}>
{() => {
const key = form.getFieldValue("key");
if (!key) return null;
//Kind of Id
const rangeFilter = Templates[key] && Templates[key].rangeFilter;
if (!rangeFilter) return null;
return (
<div>
{t("reportcenter.labels.filterson", {
object: rangeFilter.object,
field: rangeFilter.field,
})}
</div>
);
}}
</Form.Item>
<Form.Item style={{ margin: 0, padding: 0 }} dependencies={["key"]}>
{() => {
const key = form.getFieldValue("key");
const currentId = form.getFieldValue("id");
if (!key) return null;
//Kind of Id
const idtype = Templates[key] && Templates[key].idtype;
if (!idtype && currentId) {
form.setFieldsValue({ id: null });
return null;
}
if (!vendorCalled && idtype === "vendor") callVendorQuery();
if (!employeeCalled && idtype === "employee") callEmployeeQuery();
if (idtype === "vendor")
<Row gutter={[16, 16]}>
{Object.keys(grouped).map((key) => (
<Col md={8} sm={12} key={key}>
<Card.Grid
style={{
width: "100%",
height: "100%",
maxHeight: "33vh",
overflowY: "scroll",
}}
>
<Typography.Title level={4}>
{t(`reportcenter.labels.groups.${key}`)}
</Typography.Title>
<ul style={{ listStyleType: 'none', columns: "2 auto"}}>
{grouped[key].map((item) => (
<li key={item.key}>
<Radio key={item.key} value={item.key}>
{item.title}
</Radio>
</li>
))}
</ul>
</Card.Grid>
</Col>
))}
</Row>
</Radio.Group>
</Form.Item>
<Form.Item style={{margin: 0, padding: 0}} dependencies={["key"]}>
{() => {
const key = form.getFieldValue("key");
if (!key) return null;
//Kind of Id
const rangeFilter = Templates[key] && Templates[key].rangeFilter;
if (!rangeFilter) return null;
return (
<Form.Item
name="id"
label={t("reportcenter.labels.vendor")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<VendorSearchSelect
options={vendorData ? vendorData.vendors : []}
/>
</Form.Item>
<div>
{t("reportcenter.labels.filterson", {
object: rangeFilter.object,
field: rangeFilter.field,
})}
</div>
);
if (idtype === "employee")
return (
<Form.Item
name="id"
label={t("reportcenter.labels.employee")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<EmployeeSearchSelect
options={employeeData ? employeeData.employees : []}
/>
</Form.Item>
);
else return null;
}}
</Form.Item>
<Form.Item style={{ margin: 0, padding: 0 }} dependencies={["key"]}>
{() => {
const key = form.getFieldValue("key");
const datedisable = Templates[key] && Templates[key].datedisable;
if (datedisable !== true) {
return (
<Form.Item
name="dates"
label={t("reportcenter.labels.dates")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<DatePicker.RangePicker
format="MM/DD/YYYY"
ranges={DatePIckerRanges}
/>
</Form.Item>
);
} else return null;
}}
</Form.Item>
<Form.Item style={{ margin: 0, padding: 0 }} dependencies={["key"]}>
{() => {
const key = form.getFieldValue("key");
//Kind of Id
const reporttype = Templates[key] && Templates[key].reporttype;
}}
</Form.Item>
<ReportCenterModalFiltersSortersComponent form={form} />
<Form.Item style={{margin: 0, padding: 0}} dependencies={["key"]}>
{() => {
const key = form.getFieldValue("key");
const currentId = form.getFieldValue("id");
if (!key) return null;
//Kind of Id
const idtype = Templates[key] && Templates[key].idtype;
if (!idtype && currentId) {
form.setFieldsValue({id: null});
return null;
}
if (!vendorCalled && idtype === "vendor") callVendorQuery();
if (!employeeCalled && idtype === "employee") callEmployeeQuery();
if (idtype === "vendor")
return (
<Form.Item
name="id"
label={t("reportcenter.labels.vendor")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<VendorSearchSelect
options={vendorData ? vendorData.vendors : []}
/>
</Form.Item>
);
if (idtype === "employee")
return (
<Form.Item
name="id"
label={t("reportcenter.labels.employee")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<EmployeeSearchSelect
options={employeeData ? employeeData.employees : []}
/>
</Form.Item>
);
else return null;
}}
</Form.Item>
<Form.Item style={{margin: 0, padding: 0}} dependencies={["key"]}>
{() => {
const key = form.getFieldValue("key");
const datedisable = Templates[key] && Templates[key].datedisable;
if (datedisable !== true) {
return (
<Form.Item
name="dates"
label={t("reportcenter.labels.dates")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<DatePicker.RangePicker
format="MM/DD/YYYY"
presets={DatePickerRanges}
/>
</Form.Item>
);
} else return null;
}}
</Form.Item>
<Form.Item style={{margin: 0, padding: 0}} dependencies={["key"]}>
{() => {
const key = form.getFieldValue("key");
//Kind of Id
const reporttype = Templates[key] && Templates[key].reporttype;
if (reporttype === "excel")
return (
<Form.Item
label={t("general.labels.sendby")}
name="sendbyexcel"
initialValue="excel"
>
<Radio.Group>
<Radio value="excel">{t("general.labels.excel")}</Radio>
</Radio.Group>
</Form.Item>
);
if (reporttype !== "excel")
return (
<Form.Item
label={t("general.labels.sendby")}
name="sendby"
initialValue="print"
>
<Radio.Group>
<Radio value="email">{t("general.labels.email")}</Radio>
<Radio value="print">{t("general.labels.print")}</Radio>
</Radio.Group>
</Form.Item>
);
}}
</Form.Item>
if (reporttype === "excel")
return (
<Form.Item
label={t("general.labels.sendby")}
name="sendbyexcel"
initialValue="excel"
>
<Radio.Group>
<Radio value="excel">{t("general.labels.excel")}</Radio>
</Radio.Group>
</Form.Item>
);
if (reporttype !== "excel")
return (
<Form.Item
label={t("general.labels.sendby")}
name="sendby"
initialValue="print"
>
<Radio.Group>
<Radio value="email">{t("general.labels.email")}</Radio>
<Radio value="print">{t("general.labels.print")}</Radio>
</Radio.Group>
</Form.Item>
);
}}
</Form.Item>
<div
style={{
display: "flex",
justifyContent: "center",
marginTop: "1rem",
}}
>
<Button onClick={() => form.submit()} style={{}} loading={loading}>
{t("reportcenter.actions.generate")}
</Button>
</div>
</Form>
</div>
<div
style={{
display: "flex",
justifyContent: "center",
marginTop: "1rem",
}}
>
<Button onClick={() => form.submit()} style={{}} loading={loading}>
{t("reportcenter.actions.generate")}
</Button>
</div>
</Form>
</div>
);
}

View File

@@ -1,5 +1,5 @@
import React from "react";
import { Form } from "antd";
import React from "react";
import ConfigFormComponents from "../config-form-components/config-form-components.component";
export default function ShopCsiConfigForm({ selectedCsi }) {
@@ -9,7 +9,7 @@ export default function ShopCsiConfigForm({ selectedCsi }) {
return (
<div>
The Config Form {readOnly}
{readOnly}
{selectedCsi && (
<Form form={form} onFinish={handleFinish}>
<ConfigFormComponents

View File

@@ -1,7 +1,7 @@
import { CheckCircleFilled } from "@ant-design/icons";
import { useQuery } from "@apollo/client";
import { Button, Col, List, Row } from "antd";
import React, { useState } from "react";
import { useQuery } from "@apollo/client";
import { useTranslation } from "react-i18next";
import { GET_ALL_QUESTION_SETS } from "../../graphql/csi.queries";
import { DateFormatter } from "../../utils/DateFormatter";
@@ -21,7 +21,6 @@ export default function ShopCsiConfig() {
if (error) return <AlertComponent message={error.message} type="error" />;
return (
<div>
The Config Form
<Row>
<Col span={3}>
<List
@@ -42,7 +41,8 @@ export default function ShopCsiConfig() {
)}
/>
</Col>
<Col span={21}>
<Col span={1} />
<Col span={20}>
<ShopCsiConfigForm selectedCsi={selectedCsi} />
</Col>
</Row>

View File

@@ -11,7 +11,7 @@ import {
Switch,
Table,
} from "antd";
import { useForm } from "antd/es/form/Form";
import moment from "moment";
import querystring from "query-string";
import React, { useEffect } from "react";
@@ -36,7 +36,6 @@ import FormDatePicker from "../form-date-picker/form-date-picker.component";
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
import ShopEmployeeAddVacation from "./shop-employees-add-vacation.component";
import { useTreatments } from "@splitsoftware/splitio-react";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -47,7 +46,7 @@ const mapDispatchToProps = (dispatch) => ({
export function ShopEmployeesFormComponent({ bodyshop }) {
const { t } = useTranslation();
const [form] = Form.useForm();
const [form] = useForm();
const history = useHistory();
const search = querystring.parse(useLocation().search);
const [deleteVacation] = useMutation(DELETE_VACATION);
@@ -57,11 +56,7 @@ export function ShopEmployeesFormComponent({ bodyshop }) {
fetchPolicy: "network-only",
nextFetchPolicy: "network-only",
});
const { Enhanced_Payroll } = useTreatments(
["Enhanced_Payroll"],
{},
bodyshop.imexshopid
);
const client = useApolloClient();
useEffect(() => {
if (data && data.employees_by_pk) form.setFieldsValue(data.employees_by_pk);
@@ -367,7 +362,7 @@ export function ShopEmployeesFormComponent({ bodyshop }) {
{t("timetickets.labels.shift")}
</Select.Option>
{bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber || Enhanced_Payroll.treatment === "on"
{bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber
? CiecaSelect(false, true)
: bodyshop.md_responsibility_centers.costs.map(
(c) => (

View File

@@ -15,7 +15,6 @@ import ShopInfoResponsibilityCenterComponent from "./shop-info.responsibilitycen
import ShopInfoROStatusComponent from "./shop-info.rostatus.component";
import ShopInfoSchedulingComponent from "./shop-info.scheduling.component";
import ShopInfoSpeedPrint from "./shop-info.speedprint.component";
import ShopInfoTaskPresets from "./shop-info.task-presets.component";
import { useHistory, useLocation } from "react-router-dom";
import queryString from "query-string";
@@ -97,12 +96,6 @@ export function ShopInfoComponent({ bodyshop, form, saveLoading }) {
<ShopInfoPartsScan form={form} />
</Tabs.TabPane>
)}
<Tabs.TabPane
key="task-presets"
tab={t("bodyshop.labels.task-presets")}
>
<ShopInfoTaskPresets form={form} />
</Tabs.TabPane>
</Tabs>
</Card>
);

View File

@@ -189,22 +189,20 @@ export function ShopInfoGeneral({ form, bodyshop }) {
<Switch />
</Form.Item>
{
// <Form.Item shouldUpdate noStyle>
// {() => (
// <Form.Item
// label={t("bodyshop.labels.qbo_usa")}
// shouldUpdate
// valuePropName="checked"
// name={["accountingconfig", "qbo_usa"]}
// >
// <Switch
// disabled={!form.getFieldValue(["accountingconfig", "qbo"])}
// />
// </Form.Item>
// )}
// </Form.Item>
}
<Form.Item shouldUpdate noStyle>
{() => (
<Form.Item
label={t("bodyshop.labels.qbo_usa")}
shouldUpdate
valuePropName="checked"
name={["accountingconfig", "qbo_usa"]}
>
<Switch
disabled={!form.getFieldValue(["accountingconfig", "qbo"])}
/>
</Form.Item>
)}
</Form.Item>
<Form.Item
label={t("bodyshop.labels.qbo_departmentid")}
name={["accountingconfig", "qbo_departmentid"]}
@@ -293,34 +291,36 @@ export function ShopInfoGeneral({ form, bodyshop }) {
>
<InputNumber min={0} precision={2} />
</Form.Item>
{
// <Form.Item
// label={t("bodyshop.fields.federal_tax_id")}
// name="federal_tax_id"
// >
// <Input />
// </Form.Item>
}
<Form.Item
label={t("bodyshop.fields.federal_tax_id")}
name="federal_tax_id"
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<Input />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.state_tax_id")}
name="state_tax_id"
>
<Input />
</Form.Item>
{
// <Form.Item
// label={t("bodyshop.fields.invoice_federal_tax_rate")}
// name={["bill_tax_rates", "federal_tax_rate"]}
// rules={[
// {
// required: true,
// //message: t("general.validation.required"),
// },
// ]}
// >
// <InputNumber />
// </Form.Item>
}
<Form.Item
label={t("bodyshop.fields.invoice_federal_tax_rate")}
name={["bill_tax_rates", "federal_tax_rate"]}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.invoice_state_tax_rate")}
name={["bill_tax_rates", "state_tax_rate"]}

View File

@@ -408,31 +408,7 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "bills:list"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.employees.page")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "employees:page"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.employee_teams.page")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "employee_teams:page"]}
name={["md_rbac", "owners:detail"]}
>
<InputNumber />
</Form.Item>
@@ -564,67 +540,7 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "timetickets:edit"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.timetickets.shiftedit")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "timetickets:shiftedit"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.timetickets.editcommitted")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "timetickets:editcommitted"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.ttapprovals.view")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "ttapprovals:view"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.ttapprovals.approve")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "ttapprovals:approve"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.shop.vendors")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "shop:vendors"]}
name={["md_rbac", "shop:config"]}
>
<InputNumber />
</Form.Item>

View File

@@ -17,7 +17,6 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { useTreatments } from "@splitsoftware/splitio-react";
import ShopInfoResponsibilitycentersTaxesComponent from "./shop-info.responsibilitycenters.taxes.component";
const SelectorDiv = styled.div`
.ant-form-item .ant-select {
@@ -4117,124 +4116,122 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
</LayoutFormRow>
</SelectorDiv>
{
// <LayoutFormRow
// header={t("bodyshop.labels.responsibilitycenters.tax_accounts")}
// id="tax_accounts"
// >
// <Form.Item
// label={t("bodyshop.fields.responsibilitycenters.federal_tax")}
// rules={[
// {
// required: true,
// //message: t("general.validation.required"),
// },
// ]}
// name={["md_responsibility_centers", "taxes", "federal", "name"]}
// >
// <Input />
// </Form.Item>
// {/* <Form.Item
// label={t("bodyshop.fields.responsibilitycenter_accountnumber")}
// rules={[
// {
// required: true,
// //message: t("general.validation.required"),
// },
// ]}
// name={[
// "md_responsibility_centers",
// "taxes",
// "federal",
// "accountnumber",
// ]}
// >
// <Input />
// </Form.Item> */}
// {/* <Form.Item
// label={t("bodyshop.fields.responsibilitycenter_accountname")}
// rules={[
// {
// required: true,
// //message: t("general.validation.required"),
// },
// ]}
// name={[
// "md_responsibility_centers",
// "taxes",
// "federal",
// "accountname",
// ]}
// >
// <Input />
// </Form.Item> */}
// <Form.Item
// label={t("bodyshop.fields.responsibilitycenter_accountdesc")}
// rules={[
// {
// required: true,
// //message: t("general.validation.required"),
// },
// ]}
// name={[
// "md_responsibility_centers",
// "taxes",
// "federal",
// "accountdesc",
// ]}
// >
// <Input />
// </Form.Item>
// <Form.Item
// label={t("bodyshop.fields.responsibilitycenter_accountitem")}
// rules={[
// {
// required: true,
// //message: t("general.validation.required"),
// },
// ]}
// name={[
// "md_responsibility_centers",
// "taxes",
// "federal",
// "accountitem",
// ]}
// >
// <Input />
// </Form.Item>
// {(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
// <Form.Item
// label={t("bodyshop.fields.dms.dms_acctnumber")}
// rules={[
// {
// required: true,
// //message: t("general.validation.required"),
// },
// ]}
// name={[
// "md_responsibility_centers",
// "taxes",
// "federal",
// "dms_acctnumber",
// ]}
// >
// <Input />
// </Form.Item>
// )}
// <Form.Item
// label={t("bodyshop.fields.responsibilitycenter_rate")}
// rules={[
// {
// required: true,
// //message: t("general.validation.required"),
// },
// ]}
// name={["md_responsibility_centers", "taxes", "federal", "rate"]}
// >
// <InputNumber precision={2} />
// </Form.Item>
// </LayoutFormRow>
}
<LayoutFormRow
header={t("bodyshop.labels.responsibilitycenters.tax_accounts")}
id="tax_accounts"
>
<Form.Item
label={t("bodyshop.fields.responsibilitycenters.federal_tax")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_responsibility_centers", "taxes", "federal", "name"]}
>
<Input />
</Form.Item>
{/* <Form.Item
label={t("bodyshop.fields.responsibilitycenter_accountnumber")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={[
"md_responsibility_centers",
"taxes",
"federal",
"accountnumber",
]}
>
<Input />
</Form.Item> */}
{/* <Form.Item
label={t("bodyshop.fields.responsibilitycenter_accountname")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={[
"md_responsibility_centers",
"taxes",
"federal",
"accountname",
]}
>
<Input />
</Form.Item> */}
<Form.Item
label={t("bodyshop.fields.responsibilitycenter_accountdesc")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={[
"md_responsibility_centers",
"taxes",
"federal",
"accountdesc",
]}
>
<Input />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenter_accountitem")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={[
"md_responsibility_centers",
"taxes",
"federal",
"accountitem",
]}
>
<Input />
</Form.Item>
{(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
<Form.Item
label={t("bodyshop.fields.dms.dms_acctnumber")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={[
"md_responsibility_centers",
"taxes",
"federal",
"dms_acctnumber",
]}
>
<Input />
</Form.Item>
)}
<Form.Item
label={t("bodyshop.fields.responsibilitycenter_rate")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_responsibility_centers", "taxes", "federal", "rate"]}
>
<InputNumber precision={2} />
</Form.Item>
</LayoutFormRow>
{DmsAp.treatment === "on" && (
<LayoutFormRow id="federal_tax_itc">
<Form.Item
@@ -4350,242 +4347,202 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
</Form.Item>
</LayoutFormRow>
)}
{
// <LayoutFormRow id="state_tax">
// <Form.Item
// label={t("bodyshop.fields.responsibilitycenters.state_tax")}
// rules={[
// {
// required: true,
// //message: t("general.validation.required"),
// },
// ]}
// name={["md_responsibility_centers", "taxes", "state", "name"]}
// >
// <Input />
// </Form.Item>
// {/* <Form.Item
// label={t("bodyshop.fields.responsibilitycenter_accountnumber")}
// rules={[
// {
// required: true,
// //message: t("general.validation.required"),
// },
// ]}
// name={[
// "md_responsibility_centers",
// "taxes",
// "state",
// "accountnumber",
// ]}
// >
// <Input />
// </Form.Item>
// <Form.Item
// label={t("bodyshop.fields.responsibilitycenter_accountname")}
// rules={[
// {
// required: true,
// //message: t("general.validation.required"),
// },
// ]}
// name={["md_responsibility_centers", "taxes", "state", "accountname"]}
// >
// <Input />
// </Form.Item> */}
// <Form.Item
// label={t("bodyshop.fields.responsibilitycenter_accountdesc")}
// rules={[
// {
// required: true,
// //message: t("general.validation.required"),
// },
// ]}
// name={["md_responsibility_centers", "taxes", "state", "accountdesc"]}
// >
// <Input />
// </Form.Item>
// <Form.Item
// label={t("bodyshop.fields.responsibilitycenter_accountitem")}
// rules={[
// {
// required: true,
// //message: t("general.validation.required"),
// },
// ]}
// name={["md_responsibility_centers", "taxes", "state", "accountitem"]}
// >
// <Input />
// </Form.Item>
// {(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
// <Form.Item
// label={t("bodyshop.fields.dms.dms_acctnumber")}
// rules={[
// {
// required: true,
// //message: t("general.validation.required"),
// },
// ]}
// name={[
// "md_responsibility_centers",
// "taxes",
// "state",
// "dms_acctnumber",
// ]}
// >
// <Input />
// </Form.Item>
// )}
// <Form.Item
// label={t("bodyshop.fields.responsibilitycenter_rate")}
// rules={[
// {
// required: true,
// //message: t("general.validation.required"),
// },
// ]}
// name={["md_responsibility_centers", "taxes", "state", "rate"]}
// >
// <InputNumber precision={2} />
// </Form.Item>
// </LayoutFormRow>
}
<ShopInfoResponsibilitycentersTaxesComponent form={form} />
<Form.Item
label={t("bodyshop.fields.responsibilitycenters.itemexemptcode")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_responsibility_centers", "taxes", "itemexemptcode"]}
>
<Input />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenters.invoiceexemptcode")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_responsibility_centers", "taxes", "invoiceexemptcode"]}
>
<Input />
</Form.Item>
{
// <LayoutFormRow id="local_tax">
// <Form.Item
// label={t("bodyshop.fields.responsibilitycenters.local_tax")}
// rules={[
// {
// required: true,
// //message: t("general.validation.required"),
// },
// ]}
// name={["md_responsibility_centers", "taxes", "local", "name"]}
// >
// <Input />
// </Form.Item>
// {/* <Form.Item
// label={t("bodyshop.fields.responsibilitycenter_accountnumber")}
// rules={[
// {
// required: true,
// //message: t("general.validation.required"),
// },
// ]}
// name={[
// "md_responsibility_centers",
// "taxes",
// "local",
// "accountnumber",
// ]}
// >
// <Input />
// </Form.Item>
// <Form.Item
// label={t("bodyshop.fields.responsibilitycenter_accountname")}
// rules={[
// {
// required: true,
// //message: t("general.validation.required"),
// },
// ]}
// name={["md_responsibility_centers", "taxes", "local", "accountname"]}
// >
// <Input />
// </Form.Item> */}
// <Form.Item
// label={t("bodyshop.fields.responsibilitycenter_accountdesc")}
// rules={[
// {
// required: true,
// //message: t("general.validation.required"),
// },
// ]}
// name={[
// "md_responsibility_centers",
// "taxes",
// "local",
// "accountdesc",
// ]}
// >
// <Input />
// </Form.Item>
// <Form.Item
// label={t("bodyshop.fields.responsibilitycenter_accountitem")}
// rules={[
// {
// required: true,
// //message: t("general.validation.required"),
// },
// ]}
// name={[
// "md_responsibility_centers",
// "taxes",
// "local",
// "accountitem",
// ]}
// >
// <Input />
// </Form.Item>
// {(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
// <Form.Item
// label={t("bodyshop.fields.dms.dms_acctnumber")}
// rules={[
// {
// required: true,
// //message: t("general.validation.required"),
// },
// ]}
// name={[
// "md_responsibility_centers",
// "taxes",
// "local",
// "dms_acctnumber",
// ]}
// >
// <Input />
// </Form.Item>
// )}
// <Form.Item
// label={t("bodyshop.fields.responsibilitycenter_rate")}
// rules={[
// {
// required: true,
// //message: t("general.validation.required"),
// },
// ]}
// name={["md_responsibility_centers", "taxes", "local", "rate"]}
// >
// <InputNumber precision={2} />
// </Form.Item>
// </LayoutFormRow>
}
<LayoutFormRow id="state_tax">
<Form.Item
label={t("bodyshop.fields.responsibilitycenters.state_tax")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_responsibility_centers", "taxes", "state", "name"]}
>
<Input />
</Form.Item>
{/* <Form.Item
label={t("bodyshop.fields.responsibilitycenter_accountnumber")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={[
"md_responsibility_centers",
"taxes",
"state",
"accountnumber",
]}
>
<Input />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenter_accountname")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_responsibility_centers", "taxes", "state", "accountname"]}
>
<Input />
</Form.Item> */}
<Form.Item
label={t("bodyshop.fields.responsibilitycenter_accountdesc")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_responsibility_centers", "taxes", "state", "accountdesc"]}
>
<Input />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenter_accountitem")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_responsibility_centers", "taxes", "state", "accountitem"]}
>
<Input />
</Form.Item>
{(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
<Form.Item
label={t("bodyshop.fields.dms.dms_acctnumber")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={[
"md_responsibility_centers",
"taxes",
"state",
"dms_acctnumber",
]}
>
<Input />
</Form.Item>
)}
<Form.Item
label={t("bodyshop.fields.responsibilitycenter_rate")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_responsibility_centers", "taxes", "state", "rate"]}
>
<InputNumber precision={2} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow id="local_tax">
<Form.Item
label={t("bodyshop.fields.responsibilitycenters.local_tax")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_responsibility_centers", "taxes", "local", "name"]}
>
<Input />
</Form.Item>
{/* <Form.Item
label={t("bodyshop.fields.responsibilitycenter_accountnumber")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={[
"md_responsibility_centers",
"taxes",
"local",
"accountnumber",
]}
>
<Input />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenter_accountname")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_responsibility_centers", "taxes", "local", "accountname"]}
>
<Input />
</Form.Item> */}
<Form.Item
label={t("bodyshop.fields.responsibilitycenter_accountdesc")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_responsibility_centers", "taxes", "local", "accountdesc"]}
>
<Input />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenter_accountitem")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_responsibility_centers", "taxes", "local", "accountitem"]}
>
<Input />
</Form.Item>
{(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
<Form.Item
label={t("bodyshop.fields.dms.dms_acctnumber")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={[
"md_responsibility_centers",
"taxes",
"local",
"dms_acctnumber",
]}
>
<Input />
</Form.Item>
)}
<Form.Item
label={t("bodyshop.fields.responsibilitycenter_rate")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_responsibility_centers", "taxes", "local", "rate"]}
>
<InputNumber precision={2} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={<div>AR</div>} id="AR">
{/* <Form.Item
label={t("bodyshop.fields.responsibilitycenters.ar")}

View File

@@ -1,269 +0,0 @@
import { DeleteFilled } from "@ant-design/icons";
import {
Button,
Checkbox,
Col,
Form,
Input,
InputNumber,
Row,
Select,
Space,
Switch,
} from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(ShopInfoTaskPresets);
export function ShopInfoTaskPresets({ bodyshop, form }) {
const { t } = useTranslation();
return (
<>
<LayoutFormRow noDivider>
<Form.Item
label={t("bodyshop.fields.md_tasks_presets.enable_tasks")}
valuePropName="checked"
name={["md_tasks_presets", "enable_tasks"]}
>
<Switch />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.md_tasks_presets.use_approvals")}
valuePropName="checked"
name={["md_tasks_presets", "use_approvals"]}
>
<Switch />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("bodyshop.labels.md_tasks_presets")}>
<Form.List name={["md_tasks_presets", "presets"]}>
{(fields, { add, remove, move }) => {
return (
<div>
{fields.map((field, index) => (
<Form.Item key={field.key}>
<LayoutFormRow noDivider>
<Form.Item
label={t("bodyshop.fields.md_tasks_presets.name")}
key={`${index}name`}
name={[field.name, "name"]}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<Input />
</Form.Item>
<Form.Item
span={12}
label={t("bodyshop.fields.md_tasks_presets.hourstype")}
key={`${index}hourstype`}
name={[field.name, "hourstype"]}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<Checkbox.Group>
<Row>
<Col span={4}>
<Checkbox
value="LAA"
style={{ lineHeight: "32px" }}
>
{t("joblines.fields.lbr_types.LAA")}
</Checkbox>
</Col>
<Col span={4}>
<Checkbox
value="LAB"
style={{ lineHeight: "32px" }}
>
{t("joblines.fields.lbr_types.LAB")}
</Checkbox>
</Col>
<Col span={4}>
<Checkbox
value="LAD"
style={{ lineHeight: "32px" }}
>
{t("joblines.fields.lbr_types.LAD")}
</Checkbox>
</Col>
<Col span={4}>
<Checkbox
value="LAE"
style={{ lineHeight: "32px" }}
>
{t("joblines.fields.lbr_types.LAE")}
</Checkbox>
</Col>
<Col span={4}>
<Checkbox
value="LAF"
style={{ lineHeight: "32px" }}
>
{t("joblines.fields.lbr_types.LAF")}
</Checkbox>
</Col>
<Col span={4}>
<Checkbox
value="LAG"
style={{ lineHeight: "32px" }}
>
{t("joblines.fields.lbr_types.LAG")}
</Checkbox>
</Col>
<Col span={4}>
<Checkbox
value="LAM"
style={{ lineHeight: "32px" }}
>
{t("joblines.fields.lbr_types.LAM")}
</Checkbox>
</Col>
<Col span={4}>
<Checkbox
value="LAR"
style={{ lineHeight: "32px" }}
>
{t("joblines.fields.lbr_types.LAR")}
</Checkbox>
</Col>
<Col span={4}>
<Checkbox
value="LAS"
style={{ lineHeight: "32px" }}
>
{t("joblines.fields.lbr_types.LAS")}
</Checkbox>
</Col>
<Col span={4}>
<Checkbox
value="LAU"
style={{ lineHeight: "32px" }}
>
{t("joblines.fields.lbr_types.LAU")}
</Checkbox>
</Col>
<Col span={4}>
<Checkbox
value="LA1"
style={{ lineHeight: "32px" }}
>
{t("joblines.fields.lbr_types.LA1")}
</Checkbox>
</Col>
<Col span={4}>
<Checkbox
value="LA2"
style={{ lineHeight: "32px" }}
>
{t("joblines.fields.lbr_types.LA2")}
</Checkbox>
</Col>
<Col span={4}>
<Checkbox
value="LA3"
style={{ lineHeight: "32px" }}
>
{t("joblines.fields.lbr_types.LA3")}
</Checkbox>
</Col>
<Col span={4}>
<Checkbox
value="LA4"
style={{ lineHeight: "32px" }}
>
{t("joblines.fields.lbr_types.LA4")}
</Checkbox>
</Col>
</Row>
</Checkbox.Group>
</Form.Item>
<Form.Item
label={t("bodyshop.fields.md_tasks_presets.percent")}
key={`${index}percent`}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={[field.name, "percent"]}
>
<InputNumber min={0} max={100} />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.md_tasks_presets.memo")}
key={`${index}memo`}
name={[field.name, "memo"]}
>
<Input />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.md_tasks_presets.nextstatus")}
key={`${index}nextstatus`}
name={[field.name, "nextstatus"]}
>
<Select
options={bodyshop.md_ro_statuses.production_statuses.map(
(o) => ({ value: o, label: o })
)}
/>
</Form.Item>
<Space wrap>
<DeleteFilled
onClick={() => {
remove(field.name);
}}
/>
<FormListMoveArrows
move={move}
index={index}
total={fields.length}
/>
</Space>
</LayoutFormRow>
</Form.Item>
))}
<Form.Item>
<Button
type="dashed"
onClick={() => {
add();
}}
style={{ width: "100%" }}
>
{t("bodyshop.actions.add_task_preset")}
</Button>
</Form.Item>
</div>
);
}}
</Form.List>
</LayoutFormRow>
</>
);
}

View File

@@ -1,7 +0,0 @@
import React from 'react'
export default function ShopEmployeeTeamMember({teamMember}) {
return (
<div>ShopEmployeeTeamMember</div>
)
}

View File

@@ -1,436 +0,0 @@
import { DeleteFilled } from "@ant-design/icons";
import { useMutation, useQuery } from "@apollo/client";
import {
Button,
Card,
Form,
Input,
InputNumber,
Space,
Switch,
notification,
} from "antd";
import querystring from "query-string";
import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { useHistory, useLocation } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import { logImEXEvent } from "../../firebase/firebase.utils";
import { selectBodyshop } from "../../redux/user/user.selectors";
import AlertComponent from "../alert/alert.component";
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
import {
INSERT_EMPLOYEE_TEAM,
QUERY_EMPLOYEE_TEAM_BY_ID,
UPDATE_EMPLOYEE_TEAM,
} from "../../graphql/employee_teams.queries";
import EmployeeSearchSelectComponent from "../employee-search-select/employee-search-select.component";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export function ShopEmployeeTeamsFormComponent({ bodyshop }) {
const { t } = useTranslation();
const [form] = Form.useForm();
const history = useHistory();
const search = querystring.parse(useLocation().search);
const { error, data } = useQuery(QUERY_EMPLOYEE_TEAM_BY_ID, {
variables: { id: search.employeeTeamId },
skip: !search.employeeTeamId || search.employeeTeamId === "new",
fetchPolicy: "network-only",
nextFetchPolicy: "network-only",
});
useEffect(() => {
if (data && data.employee_teams_by_pk)
form.setFieldsValue(data.employee_teams_by_pk);
else {
form.resetFields();
}
}, [form, data, search.employeeTeamId]);
const [updateEmployeeTeam] = useMutation(UPDATE_EMPLOYEE_TEAM);
const [insertEmployeeTeam] = useMutation(INSERT_EMPLOYEE_TEAM);
const handleFinish = async ({ employee_team_members, ...values }) => {
if (search.employeeTeamId && search.employeeTeamId !== "new") {
//Update a record.
logImEXEvent("shop_employee_update");
const result = await updateEmployeeTeam({
variables: {
employeeTeamId: search.employeeTeamId,
employeeTeam: values,
teamMemberUpdates: employee_team_members
.filter((e) => e.id)
.map((e) => {
delete e.__typename;
return { where: { id: { _eq: e.id } }, _set: e };
}),
teamMemberInserts: employee_team_members
.filter((e) => e.id === null || e.id === undefined)
.map((e) => ({ ...e, teamid: search.employeeTeamId })),
teamMemberDeletes:
data.employee_teams_by_pk.employee_team_members.filter(
(e) => !employee_team_members.find((etm) => etm.id === e.id)
),
},
});
if (!result.errors) {
notification["success"]({
message: t("employees.successes.save"),
});
} else {
notification["error"]({
message: t("employees.errors.save", {
message: JSON.stringify(error),
}),
});
}
} else {
//New record, insert it.
logImEXEvent("shop_employee_insert");
insertEmployeeTeam({
variables: {
employeeTeam: {
...values,
employee_team_members: { data: employee_team_members },
bodyshopid: bodyshop.id,
},
},
refetchQueries: ["QUERY_TEAMS"],
}).then((r) => {
search.employeeTeamId = r.data.insert_employee_teams_one.id;
history.push({ search: querystring.stringify(search) });
notification["success"]({
message: t("employees.successes.save"),
});
});
}
};
if (!search.employeeTeamId) return null;
if (error) return <AlertComponent message={error.message} type="error" />;
return (
<Card
extra={
<Button type="primary" onClick={() => form.submit()}>
{t("general.actions.save")}
</Button>
}
>
<Form
onFinish={handleFinish}
autoComplete={"off"}
layout="vertical"
form={form}
>
<LayoutFormRow>
<Form.Item
name="name"
label={t("employee_teams.fields.name")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<Input />
</Form.Item>
<Form.Item
label={t("employee_teams.fields.active")}
name="active"
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("employee_teams.fields.max_load")}
name="max_load"
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<InputNumber min={0} precision={1} />
</Form.Item>
</LayoutFormRow>
<Form.List name={["employee_team_members"]}>
{(fields, { add, remove, move }) => {
return (
<div>
{fields.map((field, index) => (
<Form.Item key={field.key} style={{ padding: 0, margin: 2 }}>
<Form.Item
label={t("employees.fields.id")}
key={`${index}`}
name={[field.name, "id"]}
hidden
>
<Input />
</Form.Item>
<LayoutFormRow grow>
<Form.Item
label={t("employee_teams.fields.employeeid")}
key={`${index}`}
name={[field.name, "employeeid"]}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<EmployeeSearchSelectComponent
options={bodyshop.employees}
/>
</Form.Item>
<Form.Item
label={t("employee_teams.fields.percentage")}
key={`${index}`}
name={[field.name, "percentage"]}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<InputNumber min={0} max={100} precision={2} />
</Form.Item>
<Form.Item
label={t("joblines.fields.lbr_types.LAA")}
key={`${index}`}
name={[field.name, "labor_rates", "LAA"]}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<CurrencyInput />
</Form.Item>
<Form.Item
label={t("joblines.fields.lbr_types.LAB")}
key={`${index}`}
name={[field.name, "labor_rates", "LAB"]}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<CurrencyInput />
</Form.Item>
<Form.Item
label={t("joblines.fields.lbr_types.LAD")}
key={`${index}`}
name={[field.name, "labor_rates", "LAD"]}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<CurrencyInput />
</Form.Item>
<Form.Item
label={t("joblines.fields.lbr_types.LAE")}
key={`${index}`}
name={[field.name, "labor_rates", "LAE"]}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<CurrencyInput />
</Form.Item>
<Form.Item
label={t("joblines.fields.lbr_types.LAF")}
key={`${index}`}
name={[field.name, "labor_rates", "LAF"]}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<CurrencyInput />
</Form.Item>
<Form.Item
label={t("joblines.fields.lbr_types.LAG")}
key={`${index}`}
name={[field.name, "labor_rates", "LAG"]}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<CurrencyInput />
</Form.Item>
<Form.Item
label={t("joblines.fields.lbr_types.LAM")}
key={`${index}`}
name={[field.name, "labor_rates", "LAM"]}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<CurrencyInput />
</Form.Item>
<Form.Item
label={t("joblines.fields.lbr_types.LAR")}
key={`${index}`}
name={[field.name, "labor_rates", "LAR"]}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<CurrencyInput />
</Form.Item>
<Form.Item
label={t("joblines.fields.lbr_types.LAS")}
key={`${index}`}
name={[field.name, "labor_rates", "LAS"]}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<CurrencyInput />
</Form.Item>
<Form.Item
label={t("joblines.fields.lbr_types.LAU")}
key={`${index}`}
name={[field.name, "labor_rates", "LAU"]}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<CurrencyInput />
</Form.Item>
<Form.Item
label={t("joblines.fields.lbr_types.LA1")}
key={`${index}`}
name={[field.name, "labor_rates", "LA1"]}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<CurrencyInput />
</Form.Item>
<Form.Item
label={t("joblines.fields.lbr_types.LA2")}
key={`${index}`}
name={[field.name, "labor_rates", "LA2"]}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<CurrencyInput />
</Form.Item>
<Form.Item
label={t("joblines.fields.lbr_types.LA3")}
key={`${index}`}
name={[field.name, "labor_rates", "LA3"]}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<CurrencyInput />
</Form.Item>
<Form.Item
label={t("joblines.fields.lbr_types.LA4")}
key={`${index}`}
name={[field.name, "labor_rates", "LA4"]}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<CurrencyInput />
</Form.Item>
<Space align="center">
<DeleteFilled
onClick={() => {
remove(field.name);
}}
/>
<FormListMoveArrows
move={move}
index={index}
total={fields.length}
/>
</Space>
</LayoutFormRow>
</Form.Item>
))}
<Form.Item>
<Button
type="dashed"
onClick={() => {
add();
}}
style={{ width: "100%" }}
>
{t("employee_teams.actions.newmember")}
</Button>
</Form.Item>
</div>
);
}}
</Form.List>
</Form>
</Card>
);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(ShopEmployeeTeamsFormComponent);

View File

@@ -1,71 +0,0 @@
import { Button, Table } from "antd";
import queryString from "query-string";
import React from "react";
import { useTranslation } from "react-i18next";
import { useHistory, useLocation } from "react-router-dom";
export default function ShopEmployeeTeamsListComponent({
loading,
employee_teams,
}) {
const { t } = useTranslation();
const history = useHistory();
const search = queryString.parse(useLocation().search);
const handleOnRowClick = (record) => {
if (record) {
search.employeeTeamId = record.id;
history.push({ search: queryString.stringify(search) });
} else {
delete search.employeeTeamId;
history.push({ search: queryString.stringify(search) });
}
};
const columns = [
{
title: t("employee_teams.fields.name"),
dataIndex: "name",
key: "name",
},
];
return (
<div>
<Table
title={() => {
return (
<Button
type="primary"
onClick={() => {
search.employeeTeamId = "new";
history.push({ search: queryString.stringify(search) });
}}
>
{t("employee_teams.actions.new")}
</Button>
);
}}
loading={loading}
pagination={{ position: "top" }}
columns={columns}
rowKey="id"
dataSource={employee_teams}
rowSelection={{
onSelect: (props) => {
search.employeeTeamId = props.id;
history.push({ search: queryString.stringify(search) });
},
type: "radio",
selectedRowKeys: [search.employeeTeamId],
}}
onRow={(record, rowIndex) => {
return {
onClick: (event) => {
handleOnRowClick(record);
},
};
}}
/>
</div>
);
}

View File

@@ -1,43 +0,0 @@
import { useQuery } from "@apollo/client";
import React from "react";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { QUERY_TEAMS } from "../../graphql/employee_teams.queries";
import { selectBodyshop } from "../../redux/user/user.selectors";
import AlertComponent from "../alert/alert.component";
import RbacWrapper from "../rbac-wrapper/rbac-wrapper.component";
import ShopEmployeeTeamsListComponent from "./shop-employee-teams.list";
import ShopEmployeeTeamsFormComponent from "./shop-employee-teams.form.component";
import { Col, Row } from "antd";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
function ShopTeamsContainer({ bodyshop }) {
const { loading, error, data } = useQuery(QUERY_TEAMS, {
fetchPolicy: "network-only",
nextFetchPolicy: "network-only",
});
if (error) return <AlertComponent message={error.message} type="error" />;
return (
<div>
<RbacWrapper action="employee_teams:page">
<Row gutter={[16, 16]}>
<Col span={6}>
<ShopEmployeeTeamsListComponent
employee_teams={data ? data.employee_teams : []}
loading={loading}
/>
</Col>
<Col span={18}>
<ShopEmployeeTeamsFormComponent />
</Col>
</Row>
</RbacWrapper>
</div>
);
}
export default connect(mapStateToProps, null)(ShopTeamsContainer);

View File

@@ -1,12 +1,12 @@
import { LockOutlined, UserOutlined } from "@ant-design/icons";
import { Button, Form, Input } from "antd";
import { Button, Form, Input, Typography } from "antd";
import queryString from "query-string";
import React from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { Link, Redirect, useLocation } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import RomeLogo from "../../assets/RomeOnlineBlue.png";
import ImEXOnlineLogo from "../../assets/logo192.png";
import {
emailSignInStart,
sendPasswordReset,
@@ -53,7 +53,8 @@ export function SignInComponent({
return (
<div className="login-container">
<div className="login-logo-container">
<img src={RomeLogo} width={200} alt="Rome Online" />
<img src={ImEXOnlineLogo} height="100" width="100" alt="ImEX Online" />
<Typography.Title>{t("titles.app")}</Typography.Title>
</div>
<Form onFinish={handleFinish} form={form} size="large">
<Form.Item

View File

@@ -8,7 +8,6 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
import JobSearchSelect from "../job-search-select/job-search-select.component";
import JobsDetailLaborContainer from "../jobs-detail-labor/jobs-detail-labor.container";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
import { useTreatments } from "@splitsoftware/splitio-react";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -17,11 +16,6 @@ const mapStateToProps = createStructuredSelector({
export function TechClockInComponent({ form, bodyshop, technician }) {
const { t } = useTranslation();
const { Enhanced_Payroll } = useTreatments(
["Enhanced_Payroll"],
{},
bodyshop.imexshopid
);
const emps = bodyshop.employees.filter((e) => e.id === technician.id)[0];
return (
<div>
@@ -59,7 +53,7 @@ export function TechClockInComponent({ form, bodyshop, technician }) {
<Select.Option key={item.cost_center} value={item.cost_center}>
{item.cost_center === "timetickets.labels.shift"
? t(item.cost_center)
: bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber || Enhanced_Payroll.treatment === "on"
: bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber
? t(
`joblines.fields.lbr_types.${item.cost_center.toUpperCase()}`
)

View File

@@ -16,7 +16,6 @@ import {
} from "../../redux/user/user.selectors";
import TechJobPrintTickets from "../tech-job-print-tickets/tech-job-print-tickets.component";
import TechClockInComponent from "./tech-job-clock-in-form.component";
import { useTreatments } from "@splitsoftware/splitio-react";
const mapStateToProps = createStructuredSelector({
technician: selectTechnician,
@@ -33,10 +32,9 @@ export function TechClockInContainer({
bodyshop,
currentUser,
}) {
const { Enhanced_Payroll } = useTreatments(
["Enhanced_Payroll"],
{},
bodyshop.imexshopid
console.log(
"🚀 ~ file: tech-job-clock-in-form.container.jsx:30 ~ technician:",
technician
);
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
@@ -70,7 +68,7 @@ export function TechClockInContainer({
jobid: values.jobid,
cost_center: values.cost_center,
ciecacode:
bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber || Enhanced_Payroll.treatment === 'on'
bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber
? values.cost_center
: Object.keys(
bodyshop.md_responsibility_centers.defaults.costs

View File

@@ -24,7 +24,6 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
import { CalculateAllocationsTotals } from "../labor-allocations-table/labor-allocations-table.utility";
import TechJobClockoutDelete from "../tech-job-clock-out-delete/tech-job-clock-out-delete.component";
import { LaborAllocationContainer } from "../time-ticket-modal/time-ticket-modal.component";
import { useTreatments } from "@splitsoftware/splitio-react";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -44,12 +43,6 @@ export function TechClockOffButton({
const [updateTimeticket] = useMutation(UPDATE_TIME_TICKET);
const [updateJobStatus] = useMutation(UPDATE_JOB_STATUS);
const [form] = Form.useForm();
const { Enhanced_Payroll } = useTreatments(
["Enhanced_Payroll"],
{},
bodyshop.imexshopid
);
const { queryLoading, data: lineTicketData } = useQuery(
GET_LINE_TICKET_BY_PK,
{
@@ -83,9 +76,7 @@ export function TechClockOffButton({
?.rate,
flat_rate: emps && emps.flat_rate,
ciecacode:
bodyshop.cdk_dealerid ||
bodyshop.pbs_serialnumber ||
Enhanced_Payroll.treatment === "on"
bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber
? values.cost_center
: Object.keys(
bodyshop.md_responsibility_centers.defaults.costs

View File

@@ -1,9 +1,4 @@
import Icon, {
SearchOutlined,
ScheduleOutlined,
UserAddOutlined,
CarOutlined,
} from "@ant-design/icons";
import Icon, { SearchOutlined, ScheduleOutlined } from "@ant-design/icons";
import { Layout, Menu } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
@@ -16,38 +11,22 @@ import { createStructuredSelector } from "reselect";
import { techLogout } from "../../redux/tech/tech.actions";
import { selectTechnician } from "../../redux/tech/tech.selectors";
import { BsKanban } from "react-icons/bs";
import { useTreatments } from "@splitsoftware/splitio-react";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { setModalContext } from "../../redux/modals/modals.actions";
const { Sider } = Layout;
const mapStateToProps = createStructuredSelector({
technician: selectTechnician,
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
techLogout: () => dispatch(techLogout()),
setTimeTicketTaskContext: (context) =>
dispatch(setModalContext({ context: context, modal: "timeTicketTask" })),
});
export function TechSider({
technician,
techLogout,
bodyshop,
setTimeTicketTaskContext,
}) {
export function TechSider({ technician, techLogout }) {
const [collapsed, setCollapsed] = useState(true);
const { t } = useTranslation();
const onCollapse = (collapsed) => {
setCollapsed(collapsed);
};
const { Enhanced_Payroll } = useTreatments(
["Enhanced_Payroll"],
{},
bodyshop.imexshopid
);
return (
<Sider
@@ -72,38 +51,13 @@ export function TechSider({
<Menu.Item key="2" disabled={!!!technician} icon={<SearchOutlined />}>
<Link to={`/tech/joblookup`}>{t("menus.tech.joblookup")}</Link>
</Menu.Item>
{Enhanced_Payroll.treatment === "on" ? (
<>
<Menu.Item
key="TechAssignedProdJobs"
disabled={!!!technician}
icon={<UserAddOutlined />}
>
<Link to={`/tech/assigned`}> {t("menus.tech.assignedjobs")}</Link>
</Menu.Item>
<Menu.Item
key="3"
disabled={!!!technician}
icon={<Icon component={FaBusinessTime} />}
onClick={() => {
setTimeTicketTaskContext({
actions: {},
context: { jobid: null },
});
}}
>
{t("menus.tech.claimtask")}
</Menu.Item>
</>
) : (
<Menu.Item
key="3"
disabled={!!!technician}
icon={<Icon component={FaBusinessTime} />}
>
<Link to={`/tech/jobclock`}>{t("menus.tech.jobclockin")}</Link>
</Menu.Item>
)}
<Menu.Item
key="3"
disabled={!!!technician}
icon={<Icon component={FaBusinessTime} />}
>
<Link to={`/tech/jobclock`}>{t("menus.tech.jobclockin")}</Link>
</Menu.Item>
<Menu.Item
key="4"
disabled={!!!technician}
@@ -114,15 +68,6 @@ export function TechSider({
<Menu.Item key="5" disabled={!!!technician} icon={<ScheduleOutlined />}>
<Link to={`/tech/list`}>{t("menus.tech.productionlist")}</Link>
</Menu.Item>
<Menu.Item
key="dispatchedparts"
disabled={!!!technician}
icon={<CarOutlined />}
>
<Link to={`/tech/dispatchedparts`}>
{t("menus.tech.dispatchedparts")}
</Link>
</Menu.Item>
<Menu.Item
key="6"
disabled={!!!technician}
@@ -130,7 +75,6 @@ export function TechSider({
>
<Link to={`/tech/board`}> {t("menus.tech.productionboard")}</Link>
</Menu.Item>
<Menu.Item
key="7"
disabled={!!!technician}

Some files were not shown because too many files have changed in this diff Show More