Compare commits
2 Commits
feature/IO
...
pagination
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee8cbe33c4 | ||
|
|
92c8b54f85 |
@@ -68,120 +68,6 @@ jobs:
|
|||||||
from: build
|
from: build
|
||||||
to: "s3://imex-online-production/"
|
to: "s3://imex-online-production/"
|
||||||
- jira/notify
|
- 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
|
|
||||||
|
|
||||||
|
|
||||||
test-hasura-migrate:
|
test-hasura-migrate:
|
||||||
docker:
|
docker:
|
||||||
@@ -279,19 +165,6 @@ workflows:
|
|||||||
filters:
|
filters:
|
||||||
branches:
|
branches:
|
||||||
only: master
|
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:
|
- test-app-build:
|
||||||
filters:
|
filters:
|
||||||
branches:
|
branches:
|
||||||
@@ -301,15 +174,6 @@ workflows:
|
|||||||
filters:
|
filters:
|
||||||
branches:
|
branches:
|
||||||
only: test
|
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:
|
#- admin-app-build:
|
||||||
#filters:
|
#filters:
|
||||||
#branches:
|
#branches:
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,13 @@
|
|||||||
REACT_APP_GRAPHQL_ENDPOINT=https://db.dev.bodyshop.app/v1/graphql
|
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_GRAPHQL_ENDPOINT_WS=wss://db.dev.bodyshop.app/v1/graphql
|
||||||
REACT_APP_GA_CODE=231099835
|
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_API=https://api.cloudinary.com/v1_1/io-test
|
||||||
REACT_APP_CLOUDINARY_ENDPOINT=https://res.cloudinary.com/io-test
|
REACT_APP_CLOUDINARY_ENDPOINT=https://res.cloudinary.com/io-test
|
||||||
REACT_APP_CLOUDINARY_API_KEY=957865933348715
|
REACT_APP_CLOUDINARY_API_KEY=957865933348715
|
||||||
REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS=c_fill,h_250,w_250
|
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_STRIPE_PUBLIC_KEY=pk_test_51GqB4TJl3nQjrZ0wCQWAxAhlNF8jKe0tipIa6ExBaxwJGitwvFsIZUEua4dUzaMIAuXp4qwYHXx7lgjyQSwP0Pe900vzm38C7g
|
||||||
REACT_APP_AXIOS_BASE_API_URL=http://localhost:4000
|
REACT_APP_AXIOS_BASE_API_URL=http://localhost:4000
|
||||||
REACT_APP_REPORTS_SERVER_URL=https://reports3.test.imex.online
|
REACT_APP_REPORTS_SERVER_URL=https://reports3.test.imex.online
|
||||||
REACT_APP_SPLIT_API=ts615lqgnmk84thn72uk18uu5pgce6e0l4rc
|
REACT_APP_SPLIT_API=ts615lqgnmk84thn72uk18uu5pgce6e0l4rc
|
||||||
REACT_APP_COUNTRY=USA
|
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
REACT_APP_GRAPHQL_ENDPOINT=https://db.romeonline.io/v1/graphql
|
GENERATE_SOURCEMAP=false
|
||||||
REACT_APP_GRAPHQL_ENDPOINT_WS=wss://db.romeonline.io/v1/graphql
|
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_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_API=https://api.cloudinary.com/v1_1/bodyshop
|
||||||
REACT_APP_CLOUDINARY_ENDPOINT=https://res.cloudinary.com/bodyshop
|
REACT_APP_CLOUDINARY_ENDPOINT=https://res.cloudinary.com/bodyshop
|
||||||
REACT_APP_CLOUDINARY_API_KEY=473322739956866
|
REACT_APP_CLOUDINARY_API_KEY=473322739956866
|
||||||
REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS=c_fill,h_250,w_250
|
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_STRIPE_PUBLIC_KEY=pk_test_51GqB4TJl3nQjrZ0wCQWAxAhlNF8jKe0tipIa6ExBaxwJGitwvFsIZUEua4dUzaMIAuXp4qwYHXx7lgjyQSwP0Pe900vzm38C7g
|
||||||
REACT_APP_AXIOS_BASE_API_URL=https://api.romeonline.io/
|
REACT_APP_AXIOS_BASE_API_URL=https://api.imex.online/
|
||||||
REACT_APP_REPORTS_SERVER_URL=https://reports.romeonline.io
|
REACT_APP_REPORTS_SERVER_URL=https://reports.imex.online
|
||||||
REACT_APP_SPLIT_API=et9pjkik6bn67he5evpmpr1agoo7gactphgk
|
REACT_APP_SPLIT_API=et9pjkik6bn67he5evpmpr1agoo7gactphgk
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
REACT_APP_GRAPHQL_ENDPOINT=https://db.test.romeonline.io/v1/graphql
|
REACT_APP_GRAPHQL_ENDPOINT=https://db.test.bodyshop.app/v1/graphql
|
||||||
REACT_APP_GRAPHQL_ENDPOINT_WS=wss://db.test.romeonline.io/v1/graphql
|
REACT_APP_GRAPHQL_ENDPOINT_WS=wss://db.test.bodyshop.app/v1/graphql
|
||||||
REACT_APP_GA_CODE=231103507
|
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":"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_API=https://api.cloudinary.com/v1_1/bodyshop
|
||||||
REACT_APP_CLOUDINARY_ENDPOINT=https://res.cloudinary.com/bodyshop
|
REACT_APP_CLOUDINARY_ENDPOINT=https://res.cloudinary.com/bodyshop
|
||||||
REACT_APP_CLOUDINARY_API_KEY=473322739956866
|
REACT_APP_CLOUDINARY_API_KEY=473322739956866
|
||||||
REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS=c_fill,h_250,w_250
|
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_STRIPE_PUBLIC_KEY=pk_test_51GqB4TJl3nQjrZ0wCQWAxAhlNF8jKe0tipIa6ExBaxwJGitwvFsIZUEua4dUzaMIAuXp4qwYHXx7lgjyQSwP0Pe900vzm38C7g
|
||||||
REACT_APP_AXIOS_BASE_API_URL=https://api.test.romeonline.io/
|
REACT_APP_AXIOS_BASE_API_URL=https://api.test.imex.online/
|
||||||
REACT_APP_REPORTS_SERVER_URL=https://reports.test.romeonline.io
|
REACT_APP_REPORTS_SERVER_URL=https://reports3.test.imex.online
|
||||||
REACT_APP_IS_TEST=true
|
REACT_APP_IS_TEST=true
|
||||||
REACT_APP_SPLIT_API=ts615lqgnmk84thn72uk18uu5pgce6e0l4rc
|
REACT_APP_SPLIT_API=ts615lqgnmk84thn72uk18uu5pgce6e0l4rc
|
||||||
@@ -12,7 +12,7 @@ module.exports = {
|
|||||||
authToken:
|
authToken:
|
||||||
"6b45b028a02342db97a9a2f92c0959058665443d379d4a3a876430009e744260",
|
"6b45b028a02342db97a9a2f92c0959058665443d379d4a3a876430009e744260",
|
||||||
org: "snapt-software",
|
org: "snapt-software",
|
||||||
project: "rome-online",
|
project: "imexonline",
|
||||||
release: process.env.REACT_APP_GIT_SHA,
|
release: process.env.REACT_APP_GIT_SHA,
|
||||||
|
|
||||||
// webpack-specific configuration
|
// webpack-specific configuration
|
||||||
@@ -27,7 +27,7 @@ module.exports = {
|
|||||||
lessOptions: {
|
lessOptions: {
|
||||||
modifyVars: {
|
modifyVars: {
|
||||||
...(process.env.NODE_ENV === "development"
|
...(process.env.NODE_ENV === "development"
|
||||||
? { "@primary-color": "#B22234" }
|
? { "@primary-color": "#a51d1d" }
|
||||||
: {
|
: {
|
||||||
//"@primary-color": "#1DA57A"
|
//"@primary-color": "#1DA57A"
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -28,17 +28,6 @@ switch (this.location.hostname) {
|
|||||||
// measurementId: "${config.measurementId}",
|
// measurementId: "${config.measurementId}",
|
||||||
};
|
};
|
||||||
break;
|
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":
|
case "imex.online":
|
||||||
default:
|
default:
|
||||||
firebaseConfig = {
|
firebaseConfig = {
|
||||||
|
|||||||
@@ -2,81 +2,23 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<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="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="theme-color" content="#002366" />
|
<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" /> -->
|
<!-- <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" />
|
<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>
|
<script>
|
||||||
!(function () {
|
!(function () {
|
||||||
"use strict";
|
"use strict";
|
||||||
@@ -135,7 +77,7 @@ enable-ga="false"
|
|||||||
work correctly both with client-side routing and a non-root public URL.
|
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`.
|
Learn how to configure a non-root public URL by running `npm run build`.
|
||||||
-->
|
-->
|
||||||
<title>Rome Online</title>
|
<title>ImEX Online</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"short_name": "Rome Online",
|
"short_name": "ImEX Online",
|
||||||
"name": "Rome Online",
|
"name": "ImEX Online",
|
||||||
"description": "The ultimate bodyshop management system.",
|
"description": "The ultimate bodyshop management system.",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 376 B |
@@ -27,12 +27,6 @@ export default function AppContainer() {
|
|||||||
//componentSize="small"
|
//componentSize="small"
|
||||||
input={{ autoComplete: "new-password" }}
|
input={{ autoComplete: "new-password" }}
|
||||||
locale={enLocale}
|
locale={enLocale}
|
||||||
theme={{
|
|
||||||
token: {
|
|
||||||
colorPrimary: "#326ade",
|
|
||||||
colorInfo: "#326ade"
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
form={{
|
form={{
|
||||||
validateMessages: {
|
validateMessages: {
|
||||||
// eslint-disable-next-line no-template-curly-in-string
|
// eslint-disable-next-line no-template-curly-in-string
|
||||||
|
|||||||
@@ -77,9 +77,9 @@ export function App({
|
|||||||
if (currentUser.authorized && bodyshop) {
|
if (currentUser.authorized && bodyshop) {
|
||||||
client.setAttribute("imexshopid", bodyshop.imexshopid);
|
client.setAttribute("imexshopid", bodyshop.imexshopid);
|
||||||
|
|
||||||
LogRocket.init("rome-online/rome-online");
|
|
||||||
if (client.getTreatment("LogRocket_Tracking") === "on") {
|
if (client.getTreatment("LogRocket_Tracking") === "on") {
|
||||||
LogRocket.init("rome-online/rome-online");
|
console.log("LR Start");
|
||||||
|
LogRocket.init("gvfvfw/bodyshopapp");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [bodyshop, client, currentUser.authorized]);
|
}, [bodyshop, client, currentUser.authorized]);
|
||||||
@@ -109,7 +109,7 @@ export function App({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Switch>
|
<Switch>
|
||||||
<Suspense fallback={<LoadingSpinner />}>
|
<Suspense fallback={<LoadingSpinner message="ImEX Online" />}>
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<Route exact path="/" component={LandingPage} />
|
<Route exact path="/" component={LandingPage} />
|
||||||
</ErrorBoundary>
|
</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 |
@@ -1,5 +1,4 @@
|
|||||||
import { useApolloClient, useMutation } from "@apollo/client";
|
import { useApolloClient, useMutation } from "@apollo/client";
|
||||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
|
||||||
import { Button, Checkbox, Form, Modal, Space, notification } from "antd";
|
import { Button, Checkbox, Form, Modal, Space, notification } from "antd";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import React, { useEffect, useMemo, useState } from "react";
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
@@ -64,19 +63,9 @@ function BillEnterModalContainer({
|
|||||||
"enter_bill_generate_label",
|
"enter_bill_generate_label",
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
const { Enhanced_Payroll } = useTreatments(
|
|
||||||
["Enhanced_Payroll"],
|
|
||||||
{},
|
|
||||||
bodyshop.imexshopid
|
|
||||||
);
|
|
||||||
const formValues = useMemo(() => {
|
const formValues = useMemo(() => {
|
||||||
return {
|
return {
|
||||||
...billEnterModal.context.bill,
|
...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:
|
jobid:
|
||||||
(billEnterModal.context.job && billEnterModal.context.job.id) || null,
|
(billEnterModal.context.job && billEnterModal.context.job.id) || null,
|
||||||
federal_tax_rate:
|
federal_tax_rate:
|
||||||
@@ -109,7 +98,6 @@ function BillEnterModalContainer({
|
|||||||
} = values;
|
} = values;
|
||||||
|
|
||||||
let adjustmentsToInsert = {};
|
let adjustmentsToInsert = {};
|
||||||
let payrollAdjustmentsToInsert = [];
|
|
||||||
|
|
||||||
const r1 = await insertBill({
|
const r1 = await insertBill({
|
||||||
variables: {
|
variables: {
|
||||||
@@ -125,33 +113,14 @@ function BillEnterModalContainer({
|
|||||||
lbr_adjustment,
|
lbr_adjustment,
|
||||||
location: lineLocation,
|
location: lineLocation,
|
||||||
part_type,
|
part_type,
|
||||||
create_ppc,
|
|
||||||
original_actual_price,
|
|
||||||
...restI
|
...restI
|
||||||
} = i;
|
} = i;
|
||||||
|
|
||||||
if (Enhanced_Payroll.treatment === "on") {
|
if (deductedfromlbr) {
|
||||||
if (
|
adjustmentsToInsert[lbr_adjustment.mod_lbr_ty] =
|
||||||
deductedfromlbr &&
|
(adjustmentsToInsert[lbr_adjustment.mod_lbr_ty] || 0) -
|
||||||
true //payroll is on
|
restI.actual_price / lbr_adjustment.rate;
|
||||||
) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...restI,
|
...restI,
|
||||||
deductedfromlbr: deductedfromlbr,
|
deductedfromlbr: deductedfromlbr,
|
||||||
@@ -177,20 +146,6 @@ function BillEnterModalContainer({
|
|||||||
refetchQueries: ["QUERY_PARTS_BILLS_BY_JOBID", "GET_JOB_BY_PK"],
|
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);
|
const adjKeys = Object.keys(adjustmentsToInsert);
|
||||||
if (adjKeys.length > 0) {
|
if (adjKeys.length > 0) {
|
||||||
//Query the adjustments, merge, and update them.
|
//Query the adjustments, merge, and update them.
|
||||||
@@ -299,14 +254,6 @@ function BillEnterModalContainer({
|
|||||||
location: li.location || location,
|
location: li.location || location,
|
||||||
status:
|
status:
|
||||||
bodyshop.md_order_statuses.default_received || "Received*",
|
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 +322,12 @@ function BillEnterModalContainer({
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (enterAgain) {
|
if (enterAgain) {
|
||||||
// form.resetFields();
|
form.resetFields();
|
||||||
|
form.resetFields();
|
||||||
form.setFieldsValue({
|
form.setFieldsValue({
|
||||||
...formValues,
|
...formValues,
|
||||||
billlines: [],
|
billlines: [],
|
||||||
});
|
});
|
||||||
form.resetFields();
|
|
||||||
} else {
|
} else {
|
||||||
toggleModalVisible();
|
toggleModalVisible();
|
||||||
}
|
}
|
||||||
@@ -455,9 +402,6 @@ function BillEnterModalContainer({
|
|||||||
setEnterAgain(false);
|
setEnterAgain(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<button onClick={() => console.log(form.getFieldsValue("billlines"))}>
|
|
||||||
get billlines
|
|
||||||
</button>
|
|
||||||
<BillFormContainer
|
<BillFormContainer
|
||||||
form={form}
|
form={form}
|
||||||
disableInvNumber={billEnterModal.context.disableInvNumber}
|
disableInvNumber={billEnterModal.context.disableInvNumber}
|
||||||
|
|||||||
@@ -366,15 +366,13 @@ export function BillFormComponent({
|
|||||||
)}
|
)}
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<LayoutFormRow>
|
<LayoutFormRow>
|
||||||
{
|
<Form.Item
|
||||||
// <Form.Item
|
span={3}
|
||||||
// span={3}
|
label={t("bills.fields.federal_tax_rate")}
|
||||||
// label={t("bills.fields.federal_tax_rate")}
|
name="federal_tax_rate"
|
||||||
// name="federal_tax_rate"
|
>
|
||||||
// >
|
<CurrencyInput min={0} disabled={disabled} />
|
||||||
// <CurrencyInput min={0} disabled={disabled} />
|
</Form.Item>
|
||||||
// </Form.Item>
|
|
||||||
}
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
span={3}
|
span={3}
|
||||||
label={t("bills.fields.state_tax_rate")}
|
label={t("bills.fields.state_tax_rate")}
|
||||||
@@ -382,15 +380,13 @@ export function BillFormComponent({
|
|||||||
>
|
>
|
||||||
<CurrencyInput min={0} disabled={disabled} />
|
<CurrencyInput min={0} disabled={disabled} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
{
|
<Form.Item
|
||||||
// <Form.Item
|
span={3}
|
||||||
// span={3}
|
label={t("bills.fields.local_tax_rate")}
|
||||||
// label={t("bills.fields.local_tax_rate")}
|
name="local_tax_rate"
|
||||||
// name="local_tax_rate"
|
>
|
||||||
// >
|
<CurrencyInput min={0} />
|
||||||
// <CurrencyInput min={0} />
|
</Form.Item>
|
||||||
// </Form.Item>
|
|
||||||
}
|
|
||||||
<Form.Item shouldUpdate span={15}>
|
<Form.Item shouldUpdate span={15}>
|
||||||
{() => {
|
{() => {
|
||||||
const values = form.getFieldsValue([
|
const values = form.getFieldsValue([
|
||||||
@@ -416,25 +412,21 @@ export function BillFormComponent({
|
|||||||
value={totals.subtotal.toFormat()}
|
value={totals.subtotal.toFormat()}
|
||||||
precision={2}
|
precision={2}
|
||||||
/>
|
/>
|
||||||
{
|
<Statistic
|
||||||
// <Statistic
|
title={t("bills.labels.federal_tax")}
|
||||||
// title={t("bills.labels.federal_tax")}
|
value={totals.federalTax.toFormat()}
|
||||||
// value={totals.federalTax.toFormat()}
|
precision={2}
|
||||||
// precision={2}
|
/>
|
||||||
// />
|
|
||||||
}
|
|
||||||
<Statistic
|
<Statistic
|
||||||
title={t("bills.labels.state_tax")}
|
title={t("bills.labels.state_tax")}
|
||||||
value={totals.stateTax.toFormat()}
|
value={totals.stateTax.toFormat()}
|
||||||
precision={2}
|
precision={2}
|
||||||
/>
|
/>
|
||||||
{
|
<Statistic
|
||||||
// <Statistic
|
title={t("bills.labels.local_tax")}
|
||||||
// title={t("bills.labels.local_tax")}
|
value={totals.localTax.toFormat()}
|
||||||
// value={totals.localTax.toFormat()}
|
precision={2}
|
||||||
// precision={2}
|
/>
|
||||||
// />
|
|
||||||
}
|
|
||||||
<Statistic
|
<Statistic
|
||||||
title={t("bills.labels.entered_total")}
|
title={t("bills.labels.entered_total")}
|
||||||
value={totals.enteredTotal.toFormat()}
|
value={totals.enteredTotal.toFormat()}
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
import { DeleteFilled, DollarCircleFilled } from "@ant-design/icons";
|
import { DeleteFilled, DollarCircleFilled } from "@ant-design/icons";
|
||||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
import { useTreatments } from "@splitsoftware/splitio-react";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button, Form,
|
||||||
Checkbox,
|
|
||||||
Form,
|
|
||||||
Input,
|
Input,
|
||||||
InputNumber,
|
InputNumber,
|
||||||
Select,
|
Select,
|
||||||
Space,
|
Space,
|
||||||
Switch,
|
Switch,
|
||||||
Table,
|
Table,
|
||||||
Tooltip,
|
Tooltip
|
||||||
} from "antd";
|
} from "antd";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@@ -47,13 +45,6 @@ export function BillEnterModalLinesComponent({
|
|||||||
{},
|
{},
|
||||||
bodyshop && bodyshop.imexshopid
|
bodyshop && bodyshop.imexshopid
|
||||||
);
|
);
|
||||||
|
|
||||||
const { Enhanced_Payroll } = useTreatments(
|
|
||||||
["Enhanced_Payroll"],
|
|
||||||
{},
|
|
||||||
bodyshop.imexshopid
|
|
||||||
);
|
|
||||||
|
|
||||||
const columns = (remove) => {
|
const columns = (remove) => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@@ -102,7 +93,6 @@ export function BillEnterModalLinesComponent({
|
|||||||
line_desc: opt.line_desc,
|
line_desc: opt.line_desc,
|
||||||
quantity: opt.part_qty || 1,
|
quantity: opt.part_qty || 1,
|
||||||
actual_price: opt.cost,
|
actual_price: opt.cost,
|
||||||
original_actual_price: opt.cost,
|
|
||||||
cost_center: opt.part_type
|
cost_center: opt.part_type
|
||||||
? bodyshop.pbs_serialnumber || bodyshop.cdk_dealerid
|
? bodyshop.pbs_serialnumber || bodyshop.cdk_dealerid
|
||||||
? opt.part_type !== "PAE"
|
? opt.part_type !== "PAE"
|
||||||
@@ -229,43 +219,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"),
|
title: t("billlines.fields.actual_cost"),
|
||||||
@@ -407,7 +360,7 @@ export function BillEnterModalLinesComponent({
|
|||||||
},
|
},
|
||||||
formInput: (record, index) => <Switch disabled={disabled} />,
|
formInput: (record, index) => <Switch disabled={disabled} />,
|
||||||
additional: (record, index) => (
|
additional: (record, index) => (
|
||||||
<Form.Item shouldUpdate noStyle style={{ display: "inline-block" }}>
|
<Form.Item shouldUpdate style={{ display: "inline-block" }}>
|
||||||
{() => {
|
{() => {
|
||||||
const price = getFieldValue([
|
const price = getFieldValue([
|
||||||
"billlines",
|
"billlines",
|
||||||
@@ -422,31 +375,12 @@ export function BillEnterModalLinesComponent({
|
|||||||
"rate",
|
"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"]))
|
if (getFieldValue(["billlines", record.name, "deductedfromlbr"]))
|
||||||
return (
|
return (
|
||||||
<div>
|
<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
|
<Form.Item
|
||||||
label={t("joblines.fields.mod_lbr_ty")}
|
label={t("joblines.fields.mod_lbr_ty")}
|
||||||
key={`${index}modlbrty`}
|
key={`${index}modlbrty`}
|
||||||
initialValue={jobline ? jobline.mod_lbr_ty : null}
|
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
@@ -500,44 +434,22 @@ export function BillEnterModalLinesComponent({
|
|||||||
</Select.Option>
|
</Select.Option>
|
||||||
</Select>
|
</Select>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
{Enhanced_Payroll.treatment === "on" ? (
|
<Form.Item
|
||||||
<Form.Item
|
label={t("jobs.labels.adjustmentrate")}
|
||||||
label={t("billlines.labels.mod_lbr_adjustment")}
|
name={[record.name, "lbr_adjustment", "rate"]}
|
||||||
name={[record.name, "lbr_adjustment", "mod_lb_hrs"]}
|
initialValue={bodyshop.default_adjustment_rate}
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
//message: t("general.validation.required"),
|
//message: t("general.validation.required"),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber precision={2} min={0.01} />
|
||||||
precision={5}
|
</Form.Item>
|
||||||
min={0.01}
|
{price &&
|
||||||
max={jobline ? jobline.mod_lb_hrs : 0}
|
adjustmentRate &&
|
||||||
/>
|
`${(price / adjustmentRate).toFixed(1)} hrs`}
|
||||||
</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>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
return <></>;
|
return <></>;
|
||||||
@@ -545,21 +457,21 @@ export function BillEnterModalLinesComponent({
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// title: t("billlines.fields.federal_tax_applicable"),
|
title: t("billlines.fields.federal_tax_applicable"),
|
||||||
// dataIndex: "applicable_taxes.federal",
|
dataIndex: "applicable_taxes.federal",
|
||||||
// editable: true,
|
editable: true,
|
||||||
|
|
||||||
// formItemProps: (field) => {
|
formItemProps: (field) => {
|
||||||
// return {
|
return {
|
||||||
// key: `${field.index}fedtax`,
|
key: `${field.index}fedtax`,
|
||||||
// valuePropName: "checked",
|
valuePropName: "checked",
|
||||||
// // initialValue: true,
|
initialValue: true,
|
||||||
// name: [field.name, "applicable_taxes", "federal"],
|
name: [field.name, "applicable_taxes", "federal"],
|
||||||
// };
|
};
|
||||||
// },
|
},
|
||||||
// formInput: (record, index) => <Switch disabled={disabled} />,
|
formInput: (record, index) => <Switch disabled={disabled} />,
|
||||||
// },
|
},
|
||||||
{
|
{
|
||||||
title: t("billlines.fields.state_tax_applicable"),
|
title: t("billlines.fields.state_tax_applicable"),
|
||||||
dataIndex: "applicable_taxes.state",
|
dataIndex: "applicable_taxes.state",
|
||||||
@@ -574,20 +486,20 @@ export function BillEnterModalLinesComponent({
|
|||||||
},
|
},
|
||||||
formInput: (record, index) => <Switch disabled={disabled} />,
|
formInput: (record, index) => <Switch disabled={disabled} />,
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// title: t("billlines.fields.local_tax_applicable"),
|
title: t("billlines.fields.local_tax_applicable"),
|
||||||
// dataIndex: "applicable_taxes.local",
|
dataIndex: "applicable_taxes.local",
|
||||||
// editable: true,
|
editable: true,
|
||||||
|
|
||||||
// formItemProps: (field) => {
|
formItemProps: (field) => {
|
||||||
// return {
|
return {
|
||||||
// key: `${field.index}localtax`,
|
key: `${field.index}localtax`,
|
||||||
// valuePropName: "checked",
|
valuePropName: "checked",
|
||||||
// name: [field.name, "applicable_taxes", "local"],
|
name: [field.name, "applicable_taxes", "local"],
|
||||||
// };
|
};
|
||||||
// },
|
},
|
||||||
// formInput: (record, index) => <Switch disabled={disabled} />,
|
formInput: (record, index) => <Switch disabled={disabled} />,
|
||||||
// },
|
},
|
||||||
{
|
{
|
||||||
title: t("general.labels.actions"),
|
title: t("general.labels.actions"),
|
||||||
|
|
||||||
@@ -712,7 +624,7 @@ const EditableCell = ({
|
|||||||
if (additional)
|
if (additional)
|
||||||
return (
|
return (
|
||||||
<td {...restProps}>
|
<td {...restProps}>
|
||||||
<div size="small">
|
<Space size="small">
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name={dataIndex}
|
name={dataIndex}
|
||||||
labelCol={{ span: 0 }}
|
labelCol={{ span: 0 }}
|
||||||
@@ -721,7 +633,7 @@ const EditableCell = ({
|
|||||||
{(formInput && formInput(record, record.name)) || children}
|
{(formInput && formInput(record, record.name)) || children}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
{additional && additional(record, record.name)}
|
{additional && additional(record, record.name)}
|
||||||
</div>
|
</Space>
|
||||||
</td>
|
</td>
|
||||||
);
|
);
|
||||||
if (wrapper)
|
if (wrapper)
|
||||||
|
|||||||
@@ -19,14 +19,14 @@ export const CalculateBillTotal = (invoice) => {
|
|||||||
}).multiply(i.quantity || 1);
|
}).multiply(i.quantity || 1);
|
||||||
|
|
||||||
subtotal = subtotal.add(itemTotal);
|
subtotal = subtotal.add(itemTotal);
|
||||||
if (i.applicable_taxes?.federal) {
|
if (i.applicable_taxes.federal) {
|
||||||
federalTax = federalTax.add(
|
federalTax = federalTax.add(
|
||||||
itemTotal.percentage(federal_tax_rate || 0)
|
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));
|
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));
|
localTax = localTax.add(itemTotal.percentage(local_tax_rate || 0));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -63,12 +63,6 @@ const BillLineSearchSelect = (
|
|||||||
item.oem_partno ? ` - ${item.oem_partno}` : ""
|
item.oem_partno ? ` - ${item.oem_partno}` : ""
|
||||||
}${item.alt_partno ? ` (${item.alt_partno})` : ""}`.trim()}
|
}${item.alt_partno ? ` (${item.alt_partno})` : ""}`.trim()}
|
||||||
</span>
|
</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" }}>
|
<span style={{ float: "right", paddingleft: "1rem" }}>
|
||||||
{item.act_price
|
{item.act_price
|
||||||
? `$${item.act_price && item.act_price.toFixed(2)}`
|
? `$${item.act_price && item.act_price.toFixed(2)}`
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { Select, Space, Tag } from "antd";
|
import { Select, Space, Tag } from "antd";
|
||||||
import React from "react";
|
import React, { forwardRef } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
const { Option } = Select;
|
const { Option } = Select;
|
||||||
//To be used as a form element only.
|
//To be used as a form element only.
|
||||||
|
|
||||||
const EmployeeSearchSelect = ({ options, ...props }) => {
|
const EmployeeSearchSelect = ({ options, ...props }, ref) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -39,4 +39,4 @@ const EmployeeSearchSelect = ({ options, ...props }) => {
|
|||||||
</Select>
|
</Select>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
export default EmployeeSearchSelect;
|
export default forwardRef(EmployeeSearchSelect);
|
||||||
|
|||||||
@@ -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);
|
|
||||||
@@ -40,22 +40,22 @@ class ErrorBoundary extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleErrorSubmit = () => {
|
handleErrorSubmit = () => {
|
||||||
// window.$crisp.push([
|
window.$crisp.push([
|
||||||
// "do",
|
"do",
|
||||||
// "message:send",
|
"message:send",
|
||||||
// [
|
[
|
||||||
// "text",
|
"text",
|
||||||
// `I hit the following error: \n\n
|
`I hit the following error: \n\n
|
||||||
// ${this.state.error.message}\n\n
|
${this.state.error.message}\n\n
|
||||||
// ${this.state.error.stack}\n\n
|
${this.state.error.stack}\n\n
|
||||||
// URL:${window.location} as ${this.props.currentUser.email} for ${
|
URL:${window.location} as ${this.props.currentUser.email} for ${
|
||||||
// this.props.bodyshop && this.props.bodyshop.name
|
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**
|
// const errorDescription = `**Please add relevant details about what you were doing before you encountered this issue**
|
||||||
|
|
||||||
// ----
|
// ----
|
||||||
|
|||||||
@@ -1,26 +1,9 @@
|
|||||||
import Dinero from "dinero.js";
|
import Dinero from "dinero.js";
|
||||||
import React, { forwardRef } from "react";
|
import React, { forwardRef } from "react";
|
||||||
|
|
||||||
import { connect } from "react-redux";
|
const ReadOnlyFormItem = ({ value, type = "text", onChange }, ref) => {
|
||||||
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
|
|
||||||
) => {
|
|
||||||
if (!value) return null;
|
if (!value) return null;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "employee":
|
|
||||||
const emp = bodyshop.employees.find((e) => e.id === value);
|
|
||||||
return `${emp?.first_name} ${emp?.last_name}`;
|
|
||||||
|
|
||||||
case "text":
|
case "text":
|
||||||
return <div>{value}</div>;
|
return <div>{value}</div>;
|
||||||
case "currency":
|
case "currency":
|
||||||
@@ -31,8 +14,4 @@ const ReadOnlyFormItem = (
|
|||||||
return <div>{value}</div>;
|
return <div>{value}</div>;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
export default forwardRef(ReadOnlyFormItem);
|
||||||
export default connect(
|
|
||||||
mapStateToProps,
|
|
||||||
mapDispatchToProps
|
|
||||||
)(forwardRef(ReadOnlyFormItem));
|
|
||||||
|
|||||||
@@ -268,13 +268,6 @@ function Header({
|
|||||||
{t("menus.header.timetickets")}
|
{t("menus.header.timetickets")}
|
||||||
</Link>
|
</Link>
|
||||||
</Menu.Item>
|
</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
|
<Menu.Item
|
||||||
key="entertimetickets"
|
key="entertimetickets"
|
||||||
icon={<Icon component={GiPlayerTime} />}
|
icon={<Icon component={GiPlayerTime} />}
|
||||||
@@ -389,12 +382,20 @@ function Header({
|
|||||||
<Menu.Item
|
<Menu.Item
|
||||||
key="help"
|
key="help"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
window.open("https://rometech.com/", "_blank");
|
window.open("https://help.imex.online/", "_blank");
|
||||||
}}
|
}}
|
||||||
icon={<Icon component={QuestionCircleFilled} />}
|
icon={<Icon component={QuestionCircleFilled} />}
|
||||||
>
|
>
|
||||||
{t("menus.header.help")}
|
{t("menus.header.help")}
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
|
<Menu.Item
|
||||||
|
key="rescue"
|
||||||
|
onClick={() => {
|
||||||
|
window.open("https://imexrescue.com/", "_blank");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("menus.header.rescueme")}
|
||||||
|
</Menu.Item>
|
||||||
<Menu.Item key="shiftclock">
|
<Menu.Item key="shiftclock">
|
||||||
<Link to="/manage/shiftclock">{t("menus.header.shiftclock")}</Link>
|
<Link to="/manage/shiftclock">{t("menus.header.shiftclock")}</Link>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
|
|||||||
@@ -87,8 +87,7 @@ export default function JobBillsTotalComponent({
|
|||||||
const totalPartsSublet = Dinero(totals.parts.parts.total)
|
const totalPartsSublet = Dinero(totals.parts.parts.total)
|
||||||
.add(Dinero(totals.parts.sublets.total))
|
.add(Dinero(totals.parts.sublets.total))
|
||||||
.add(Dinero(totals.additional.shipping))
|
.add(Dinero(totals.additional.shipping))
|
||||||
.add(Dinero(totals.additional.towing))
|
.add(Dinero(totals.additional.towing));
|
||||||
.add(Dinero(totals.additional.additionalCosts));
|
|
||||||
|
|
||||||
const discrepancy = totalPartsSublet.subtract(billTotals);
|
const discrepancy = totalPartsSublet.subtract(billTotals);
|
||||||
|
|
||||||
|
|||||||
@@ -1,52 +1,47 @@
|
|||||||
import { Button, notification } from "antd";
|
import { Button, notification } from "antd";
|
||||||
import Axios from "axios";
|
import Axios from "axios";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
|
import { useMutation } from "@apollo/client";
|
||||||
import { useTranslation } from "react-i18next";
|
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 { t } = useTranslation();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [updateJob] = useMutation(UPDATE_JOB);
|
||||||
|
|
||||||
const handleCalculate = async () => {
|
const handleCalculate = async () => {
|
||||||
try {
|
setLoading(true);
|
||||||
setLoading(true);
|
const newTotals = (
|
||||||
|
await Axios.post("/job/totals", {
|
||||||
|
job: job,
|
||||||
|
})
|
||||||
|
).data;
|
||||||
|
|
||||||
await Axios.post("/job/totalsssu", {
|
const result = await updateJob({
|
||||||
id: job.id,
|
refetchQueries: ["GET_JOB_BY_PK"],
|
||||||
});
|
awaitRefetchQueries: true,
|
||||||
|
variables: {
|
||||||
if (refetch) refetch();
|
jobId: job.id,
|
||||||
// const result = await updateJob({
|
job: {
|
||||||
// refetchQueries: ["GET_JOB_BY_PK"],
|
job_totals: newTotals,
|
||||||
// awaitRefetchQueries: true,
|
clm_total: Dinero(newTotals.totals.total_repairs).toFormat("0.00"),
|
||||||
// variables: {
|
owner_owing: Dinero(newTotals.totals.custPayable.total).toFormat(
|
||||||
// jobId: job.id,
|
"0.00"
|
||||||
// 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 {
|
||||||
// },
|
|
||||||
// });
|
|
||||||
// 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) {
|
|
||||||
notification["error"]({
|
notification["error"]({
|
||||||
message: t("jobs.errors.updating", {
|
message: t("jobs.errors.updating", {
|
||||||
error: JSON.stringify(error),
|
error: JSON.stringify(result.errors),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
}
|
||||||
|
setLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -32,9 +32,9 @@ const mapDispatchToProps = (dispatch) => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const span = {
|
const span = {
|
||||||
lg: { span: 24 },
|
sm: { span: 24 },
|
||||||
xl: { span: 12 },
|
md: { span: 12 },
|
||||||
xxl: { span: 8 },
|
lg: { span: 8 },
|
||||||
};
|
};
|
||||||
|
|
||||||
export function JobDetailCards({ bodyshop, setPrintCenterContext }) {
|
export function JobDetailCards({ bodyshop, setPrintCenterContext }) {
|
||||||
@@ -137,6 +137,12 @@ export function JobDetailCards({ bodyshop, setPrintCenterContext }) {
|
|||||||
data={data ? data.jobs_by_pk : null}
|
data={data ? data.jobs_by_pk : null}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
|
<Col {...span}>
|
||||||
|
<JobDetailCardsPartsComponent
|
||||||
|
loading={loading}
|
||||||
|
data={data ? data.jobs_by_pk : null}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
<Col {...span}>
|
<Col {...span}>
|
||||||
<JobDetailCardsNotesComponent
|
<JobDetailCardsNotesComponent
|
||||||
loading={loading}
|
loading={loading}
|
||||||
@@ -157,12 +163,6 @@ export function JobDetailCards({ bodyshop, setPrintCenterContext }) {
|
|||||||
data={data ? data.jobs_by_pk : null}
|
data={data ? data.jobs_by_pk : null}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={24}>
|
|
||||||
<JobDetailCardsPartsComponent
|
|
||||||
loading={loading}
|
|
||||||
data={data ? data.jobs_by_pk : null}
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
</Row>
|
||||||
</Card>
|
</Card>
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
@@ -1,119 +1,16 @@
|
|||||||
import { Table } from "antd";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
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 PartsStatusPie from "../parts-status-pie/parts-status-pie.component";
|
||||||
import CardTemplate from "./job-detail-cards.template.component";
|
import CardTemplate from "./job-detail-cards.template.component";
|
||||||
|
|
||||||
import { connect } from "react-redux";
|
export default function JobDetailCardsPartsComponent({ loading, data }) {
|
||||||
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 }) {
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { joblines_status } = data;
|
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 (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<CardTemplate loading={loading} title={t("jobs.labels.cards.parts")}>
|
<CardTemplate loading={loading} title={t("jobs.labels.cards.parts")}>
|
||||||
<PartsStatusPie joblines_status={joblines_status} />
|
<PartsStatusPie joblines_status={joblines_status} />
|
||||||
<Table
|
|
||||||
key="id"
|
|
||||||
columns={columns}
|
|
||||||
dataSource={data ? data.joblines : []}
|
|
||||||
/>
|
|
||||||
</CardTemplate>
|
</CardTemplate>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,18 +8,7 @@ import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
|||||||
import { DateFormatter } from "../../utils/DateFormatter";
|
import { DateFormatter } from "../../utils/DateFormatter";
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
|
|
||||||
import { connect } from "react-redux";
|
export default function JobLinesExpander({ jobline, jobid }) {
|
||||||
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 }) {
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { loading, error, data } = useQuery(GET_JOB_LINE_ORDERS, {
|
const { loading, error, data } = useQuery(GET_JOB_LINE_ORDERS, {
|
||||||
fetchPolicy: "network-only",
|
fetchPolicy: "network-only",
|
||||||
@@ -34,7 +23,7 @@ export function JobLinesExpander({ jobline, jobid, bodyshop }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Row>
|
<Row>
|
||||||
<Col md={24} lg={8}>
|
<Col md={24} lg={12}>
|
||||||
<Typography.Title level={4}>
|
<Typography.Title level={4}>
|
||||||
{t("parts_orders.labels.parts_orders")}
|
{t("parts_orders.labels.parts_orders")}
|
||||||
</Typography.Title>
|
</Typography.Title>
|
||||||
@@ -60,7 +49,7 @@ export function JobLinesExpander({ jobline, jobid, bodyshop }) {
|
|||||||
)}
|
)}
|
||||||
</Timeline>
|
</Timeline>
|
||||||
</Col>
|
</Col>
|
||||||
<Col md={24} lg={8}>
|
<Col md={24} lg={12}>
|
||||||
<Typography.Title level={4}>{t("bills.labels.bills")}</Typography.Title>
|
<Typography.Title level={4}>{t("bills.labels.bills")}</Typography.Title>
|
||||||
<Timeline>
|
<Timeline>
|
||||||
{data.billlines.length > 0 ? (
|
{data.billlines.length > 0 ? (
|
||||||
@@ -82,7 +71,7 @@ export function JobLinesExpander({ jobline, jobid, bodyshop }) {
|
|||||||
</Col>
|
</Col>
|
||||||
<Col span={4}>
|
<Col span={4}>
|
||||||
<span>
|
<span>
|
||||||
{`${t("billlines.fields.actual_cost")}: `}
|
{`${t("billlines.fields.actual_cost")}: `}
|
||||||
<CurrencyFormatter>{line.actual_cost}</CurrencyFormatter>
|
<CurrencyFormatter>{line.actual_cost}</CurrencyFormatter>
|
||||||
</span>
|
</span>
|
||||||
</Col>
|
</Col>
|
||||||
@@ -100,37 +89,6 @@ export function JobLinesExpander({ jobline, jobid, bodyshop }) {
|
|||||||
)}
|
)}
|
||||||
</Timeline>
|
</Timeline>
|
||||||
</Col>
|
</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>
|
</Row>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
import {
|
import {
|
||||||
DeleteFilled,
|
DeleteFilled,
|
||||||
EditFilled,
|
|
||||||
FilterFilled,
|
FilterFilled,
|
||||||
HomeOutlined,
|
|
||||||
MinusCircleTwoTone,
|
|
||||||
PlusCircleTwoTone,
|
|
||||||
SyncOutlined,
|
SyncOutlined,
|
||||||
WarningFilled,
|
WarningFilled,
|
||||||
|
EditFilled,
|
||||||
|
PlusCircleTwoTone,
|
||||||
|
MinusCircleTwoTone,
|
||||||
|
HomeOutlined,
|
||||||
} from "@ant-design/icons";
|
} from "@ant-design/icons";
|
||||||
import { useMutation } from "@apollo/client";
|
import { useMutation } from "@apollo/client";
|
||||||
import {
|
import {
|
||||||
@@ -29,6 +29,7 @@ import { selectJobReadOnly } from "../../redux/application/application.selectors
|
|||||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||||
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||||
import { onlyUnique } from "../../utils/arrayHelper";
|
import { onlyUnique } from "../../utils/arrayHelper";
|
||||||
|
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||||
import { alphaSort } from "../../utils/sorters";
|
import { alphaSort } from "../../utils/sorters";
|
||||||
import JobLineLocationPopup from "../job-line-location-popup/job-line-location-popup.component";
|
import JobLineLocationPopup from "../job-line-location-popup/job-line-location-popup.component";
|
||||||
import JobLineNotePopup from "../job-line-note-popup/job-line-note-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 AllocationsAssignmentContainer from "../allocations-assignment/allocations-assignment.container";
|
||||||
// import AllocationsBulkAssignmentContainer from "../allocations-bulk-assignment/allocations-bulk-assignment.container";
|
// import AllocationsBulkAssignmentContainer from "../allocations-bulk-assignment/allocations-bulk-assignment.container";
|
||||||
// import AllocationsEmployeeLabelContainer from "../allocations-employee-label/allocations-employee-label.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 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 JobLinesExpander from "./job-lines-expander.component";
|
||||||
import JobLinesPartPriceChange from "./job-lines-part-price-change.component";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import JoblineTeamAssignment from "../job-line-team-assignment/job-line-team-assignmnent.component";
|
import moment from "moment";
|
||||||
import JobLineDispatchButton from "../job-line-dispatch-button/job-line-dispatch-button.component";
|
import JobLineConvertToLabor from "../job-line-convert-to-labor/job-line-convert-to-labor.component";
|
||||||
import JobLineBulkAssignComponent from "../job-line-bulk-assign/job-line-bulk-assign.component";
|
|
||||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -80,16 +76,8 @@ export function JobLinesComponent({
|
|||||||
setBillEnterContext,
|
setBillEnterContext,
|
||||||
}) {
|
}) {
|
||||||
const [deleteJobLine] = useMutation(DELETE_JOB_LINE_BY_PK);
|
const [deleteJobLine] = useMutation(DELETE_JOB_LINE_BY_PK);
|
||||||
const { Enhanced_Payroll } = useTreatments(
|
|
||||||
["Enhanced_Payroll"],
|
|
||||||
{},
|
|
||||||
bodyshop.imexshopid
|
|
||||||
);
|
|
||||||
const [selectedLines, setSelectedLines] = useState([]);
|
const [selectedLines, setSelectedLines] = useState([]);
|
||||||
console.log(
|
|
||||||
"🚀 ~ file: job-lines.component.jsx:89 ~ selectedLines:",
|
|
||||||
selectedLines
|
|
||||||
);
|
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
sortedInfo: {},
|
sortedInfo: {},
|
||||||
filteredInfo: {},
|
filteredInfo: {},
|
||||||
@@ -133,21 +121,10 @@ export function JobLinesComponent({
|
|||||||
sortOrder:
|
sortOrder:
|
||||||
state.sortedInfo.columnKey === "oem_partno" && state.sortedInfo.order,
|
state.sortedInfo.columnKey === "oem_partno" && state.sortedInfo.order,
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
onCell: (record) => ({
|
render: (text, record) =>
|
||||||
className: record.manual_line && "job-line-manual",
|
`${record.oem_partno || ""} ${
|
||||||
style: {
|
record.alt_partno ? `(${record.alt_partno})` : ""
|
||||||
...(record.parts_dispatch_lines[0]?.accepted_at
|
}`.trim(),
|
||||||
? { 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>
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("joblines.fields.op_code_desc"),
|
title: t("joblines.fields.op_code_desc"),
|
||||||
@@ -243,7 +220,20 @@ export function JobLinesComponent({
|
|||||||
state.sortedInfo.columnKey === "act_price" && state.sortedInfo.order,
|
state.sortedInfo.columnKey === "act_price" && state.sortedInfo.order,
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
render: (text, record) => (
|
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,
|
state.sortedInfo.columnKey === "line_ind" && state.sortedInfo.order,
|
||||||
responsive: ["md"],
|
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"),
|
title: t("joblines.fields.notes"),
|
||||||
dataIndex: "notes",
|
dataIndex: "notes",
|
||||||
@@ -431,11 +404,7 @@ export function JobLinesComponent({
|
|||||||
setSelectedLines((selectedLines) =>
|
setSelectedLines((selectedLines) =>
|
||||||
_.uniq([
|
_.uniq([
|
||||||
...selectedLines,
|
...selectedLines,
|
||||||
...jobLines.filter(
|
...jobLines.filter((item) => markedTypes.includes(item.part_type)),
|
||||||
(item) =>
|
|
||||||
markedTypes.includes(item.part_type) ||
|
|
||||||
markedTypes.includes(item.mod_lbr_ty)
|
|
||||||
),
|
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -448,21 +417,6 @@ export function JobLinesComponent({
|
|||||||
<Menu.Item key="PAL">{t("joblines.fields.part_types.PAL")}</Menu.Item>
|
<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.Item key="PAS">{t("joblines.fields.part_types.PAS")}</Menu.Item>
|
||||||
<Menu.Divider />
|
<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.Item key="clear">{t("general.labels.clear")}</Menu.Item>
|
||||||
</Menu>
|
</Menu>
|
||||||
);
|
);
|
||||||
@@ -486,18 +440,6 @@ export function JobLinesComponent({
|
|||||||
</Space>
|
</Space>
|
||||||
</Tag>
|
</Tag>
|
||||||
)}
|
)}
|
||||||
<JobLineDispatchButton
|
|
||||||
selectedLines={selectedLines}
|
|
||||||
setSelectedLines={setSelectedLines}
|
|
||||||
job={job}
|
|
||||||
/>
|
|
||||||
{Enhanced_Payroll.treatment === "on" && (
|
|
||||||
<JobLineBulkAssignComponent
|
|
||||||
selectedLines={selectedLines}
|
|
||||||
setSelectedLines={setSelectedLines}
|
|
||||||
job={job}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<Button
|
<Button
|
||||||
disabled={
|
disabled={
|
||||||
(job && !job.converted) ||
|
(job && !job.converted) ||
|
||||||
@@ -506,6 +448,15 @@ export function JobLinesComponent({
|
|||||||
technician
|
technician
|
||||||
}
|
}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
// setPartsOrderContext({
|
||||||
|
// actions: { refetch: refetch },
|
||||||
|
// context: {
|
||||||
|
// jobId: job.id,
|
||||||
|
// job: job,
|
||||||
|
// linesToOrder: selectedLines,
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
|
||||||
setBillEnterContext({
|
setBillEnterContext({
|
||||||
actions: { refetch: refetch },
|
actions: { refetch: refetch },
|
||||||
context: {
|
context: {
|
||||||
@@ -612,9 +563,6 @@ export function JobLinesComponent({
|
|||||||
>
|
>
|
||||||
{t("joblines.actions.new")}
|
{t("joblines.actions.new")}
|
||||||
</Button>
|
</Button>
|
||||||
{bodyshop.region_config.toLowerCase().startsWith("us") && (
|
|
||||||
<JobSendPartPriceChangeComponent job={job} />
|
|
||||||
)}
|
|
||||||
<JobCreateIOU job={job} selectedJobLines={selectedLines} />
|
<JobCreateIOU job={job} selectedJobLines={selectedLines} />
|
||||||
<Input.Search
|
<Input.Search
|
||||||
placeholder={t("general.labels.search")}
|
placeholder={t("general.labels.search")}
|
||||||
|
|||||||
@@ -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>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -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>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useMutation } from "@apollo/client";
|
import { useMutation } from "@apollo/client";
|
||||||
import { notification, Select, Space } from "antd";
|
import { notification, Select } from "antd";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
@@ -77,10 +77,7 @@ export function JobLineLocationPopup({ bodyshop, jobline, disabled }) {
|
|||||||
style={{ width: "100%", minHeight: "2rem", cursor: "pointer" }}
|
style={{ width: "100%", minHeight: "2rem", cursor: "pointer" }}
|
||||||
onClick={() => !disabled && setEditing(true)}
|
onClick={() => !disabled && setEditing(true)}
|
||||||
>
|
>
|
||||||
<Space wrap>
|
{jobline.location}
|
||||||
{jobline.location}
|
|
||||||
{jobline.parts_dispatch_lines?.length > 0 && "-Disp"}
|
|
||||||
</Space>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -19,8 +19,7 @@ export default function JobReconciliationModalComponent({ job, bills }) {
|
|||||||
|
|
||||||
const jobLineData = job.joblines.filter(
|
const jobLineData = job.joblines.filter(
|
||||||
(j) =>
|
(j) =>
|
||||||
(j.part_type !== "PAE" && j.act_price !== 0 && j.part_qty !== 0) ||
|
(j.part_type !== null && j.part_type !== "PAE") ||
|
||||||
j.misc_amt !== 0 ||
|
|
||||||
(j.line_desc &&
|
(j.line_desc &&
|
||||||
j.line_desc.toLowerCase().includes("towing") &&
|
j.line_desc.toLowerCase().includes("towing") &&
|
||||||
j.lbr_op === "OP13") ||
|
j.lbr_op === "OP13") ||
|
||||||
|
|||||||
@@ -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>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -67,8 +67,7 @@ export function JobsTotalsTableComponent({ jobRO, currentUser, job }) {
|
|||||||
<JobTotalsTableTotals job={job} />
|
<JobTotalsTableTotals job={job} />
|
||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
{(currentUser.email.includes("@imex.") ||
|
{currentUser.email.includes("@imex.") && (
|
||||||
currentUser.email.includes("@rome.")) && (
|
|
||||||
<Col span={24}>
|
<Col span={24}>
|
||||||
<Card title="DEVELOPMENT USE ONLY">
|
<Card title="DEVELOPMENT USE ONLY">
|
||||||
<JobCalculateTotals job={job} disabled={jobRO} />
|
<JobCalculateTotals job={job} disabled={jobRO} />
|
||||||
|
|||||||
@@ -123,10 +123,11 @@ export default function JobTotalsTableLabor({ job }) {
|
|||||||
<Space>
|
<Space>
|
||||||
{t("jobs.labels.mapa")}
|
{t("jobs.labels.mapa")}
|
||||||
{job.materials &&
|
{job.materials &&
|
||||||
job.materials.MAPA &&
|
job.materials.mapa &&
|
||||||
job.materials.MAPA.cal_maxdlr !== undefined &&
|
job.materials.mapa.cal_maxdlr &&
|
||||||
|
job.materials.mapa.cal_maxdlr > 0 &&
|
||||||
t("jobs.labels.threshhold", {
|
t("jobs.labels.threshhold", {
|
||||||
amount: job.materials.MAPA.cal_maxdlr,
|
amount: job.materials.mapa.cal_maxdlr,
|
||||||
})}
|
})}
|
||||||
</Space>
|
</Space>
|
||||||
</Table.Summary.Cell>
|
</Table.Summary.Cell>
|
||||||
@@ -147,10 +148,11 @@ export default function JobTotalsTableLabor({ job }) {
|
|||||||
<Space wrap>
|
<Space wrap>
|
||||||
{t("jobs.labels.mash")}
|
{t("jobs.labels.mash")}
|
||||||
{job.materials &&
|
{job.materials &&
|
||||||
job.materials.MASH &&
|
job.materials.mash &&
|
||||||
job.materials.MASH.cal_maxdlr !== undefined &&
|
job.materials.mash.cal_maxdlr &&
|
||||||
|
job.materials.mash.cal_maxdlr > 0 &&
|
||||||
t("jobs.labels.threshhold", {
|
t("jobs.labels.threshhold", {
|
||||||
amount: job.materials.MASH.cal_maxdlr,
|
amount: job.materials.mash.cal_maxdlr,
|
||||||
})}
|
})}
|
||||||
</Space>
|
</Space>
|
||||||
</Table.Summary.Cell>
|
</Table.Summary.Cell>
|
||||||
|
|||||||
@@ -11,22 +11,6 @@ export default function JobTotalsTableParts({ job }) {
|
|||||||
filteredInfo: {},
|
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(() => {
|
const data = useMemo(() => {
|
||||||
return Object.keys(job.job_totals.parts.parts.list)
|
return Object.keys(job.job_totals.parts.parts.list)
|
||||||
.filter(
|
.filter(
|
||||||
@@ -90,11 +74,11 @@ export default function JobTotalsTableParts({ job }) {
|
|||||||
<Table.Summary.Cell>
|
<Table.Summary.Cell>
|
||||||
{t("jobs.labels.prt_dsmk_total")}
|
{t("jobs.labels.prt_dsmk_total")}
|
||||||
</Table.Summary.Cell>
|
</Table.Summary.Cell>
|
||||||
|
|
||||||
<Table.Summary.Cell align="right">
|
<Table.Summary.Cell align="right">
|
||||||
{Dinero(job.job_totals.parts.parts.prt_dsmk_total).toFormat()}
|
{Dinero(job.job_totals.parts.parts.prt_dsmk_total).toFormat()}
|
||||||
</Table.Summary.Cell>
|
</Table.Summary.Cell>
|
||||||
</Table.Summary.Row>
|
</Table.Summary.Row>
|
||||||
|
|
||||||
<Table.Summary.Row>
|
<Table.Summary.Row>
|
||||||
<Table.Summary.Cell>
|
<Table.Summary.Cell>
|
||||||
<strong>{t("jobs.labels.partstotal")}</strong>
|
<strong>{t("jobs.labels.partstotal")}</strong>
|
||||||
@@ -106,24 +90,6 @@ export default function JobTotalsTableParts({ job }) {
|
|||||||
</strong>
|
</strong>
|
||||||
</Table.Summary.Cell>
|
</Table.Summary.Cell>
|
||||||
</Table.Summary.Row>
|
</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>
|
|
||||||
))}
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -28,109 +28,26 @@ export function JobTotalsTableTotals({ bodyshop, job }) {
|
|||||||
total: job.job_totals.totals.subtotal,
|
total: job.job_totals.totals.subtotal,
|
||||||
bold: true,
|
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: `${
|
key: t("jobs.fields.ca_bc_pvrt"),
|
||||||
bodyshop.md_responsibility_centers.taxes.tax_ty1?.tax_type1 ||
|
total: job.job_totals.additional.pvrt,
|
||||||
"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: `${
|
: []),
|
||||||
bodyshop.md_responsibility_centers.taxes.tax_ty2?.tax_type2 ||
|
{
|
||||||
"T2"
|
key: t("jobs.labels.federal_tax_amt"),
|
||||||
} - ${[
|
total: job.job_totals.totals.federal_tax,
|
||||||
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.total_repairs"),
|
key: t("jobs.labels.total_repairs"),
|
||||||
total: job.job_totals.totals.total_repairs,
|
total: job.job_totals.totals.total_repairs,
|
||||||
@@ -140,10 +57,10 @@ export function JobTotalsTableTotals({ bodyshop, job }) {
|
|||||||
key: t("jobs.fields.ded_amt"),
|
key: t("jobs.fields.ded_amt"),
|
||||||
total: job.job_totals.totals.custPayable.deductible,
|
total: job.job_totals.totals.custPayable.deductible,
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// key: t("jobs.fields.federal_tax_payable"),
|
key: t("jobs.fields.federal_tax_payable"),
|
||||||
// total: job.job_totals.totals.custPayable.federal_tax,
|
total: job.job_totals.totals.custPayable.federal_tax,
|
||||||
// },
|
},
|
||||||
{
|
{
|
||||||
key: t("jobs.fields.other_amount_payable"),
|
key: t("jobs.fields.other_amount_payable"),
|
||||||
total: job.job_totals.totals.custPayable.other_customer_amount,
|
total: job.job_totals.totals.custPayable.other_customer_amount,
|
||||||
@@ -164,7 +81,7 @@ export function JobTotalsTableTotals({ bodyshop, job }) {
|
|||||||
bold: true,
|
bold: true,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}, [job.job_totals, job.cieca_pft, t, bodyshop.md_responsibility_centers]);
|
}, [job.job_totals, t, bodyshop.region_config]);
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export const GetSupplementDelta = async (client, jobId, newLines) => {
|
|||||||
//Found a relevant matching line. Add it to lines to update.
|
//Found a relevant matching line. Add it to lines to update.
|
||||||
linesToUpdate.push({
|
linesToUpdate.push({
|
||||||
id: existingLines[matchingIndex].id,
|
id: existingLines[matchingIndex].id,
|
||||||
newData: { ...newLine, removed: false, act_price_before_ppc: null },
|
newData: { ...newLine, removed: false },
|
||||||
});
|
});
|
||||||
|
|
||||||
//Splice out item we found for performance.
|
//Splice out item we found for performance.
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ import {
|
|||||||
useQuery,
|
useQuery,
|
||||||
} from "@apollo/client";
|
} from "@apollo/client";
|
||||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
import { useTreatments } from "@splitsoftware/splitio-react";
|
||||||
import { Button, Col, Row, notification } from "antd";
|
import { Col, notification, Row } from "antd";
|
||||||
import Axios from "axios";
|
import Axios from "axios";
|
||||||
import _ from "lodash";
|
import Dinero from "dinero.js";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import React, { useCallback, useEffect, useState } from "react";
|
import React, { useCallback, useEffect, useState } from "react";
|
||||||
@@ -30,6 +30,7 @@ import {
|
|||||||
selectBodyshop,
|
selectBodyshop,
|
||||||
selectCurrentUser,
|
selectCurrentUser,
|
||||||
} from "../../redux/user/user.selectors";
|
} from "../../redux/user/user.selectors";
|
||||||
|
import confirmDialog from "../../utils/asyncConfirm";
|
||||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||||
import CriticalPartsScan from "../../utils/criticalPartsScan";
|
import CriticalPartsScan from "../../utils/criticalPartsScan";
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
@@ -91,15 +92,14 @@ export function JobsAvailableContainer({
|
|||||||
const modalSearchState = useState("");
|
const modalSearchState = useState("");
|
||||||
|
|
||||||
//Import Scenario
|
//Import Scenario
|
||||||
const onOwnerFindModalOk = async (lazyData) => {
|
const onOwnerFindModalOk = async () => {
|
||||||
logImEXEvent("job_import_new");
|
logImEXEvent("job_import_new");
|
||||||
|
|
||||||
setOwnerModalVisible(false);
|
setOwnerModalVisible(false);
|
||||||
|
|
||||||
setInsertLoading(true);
|
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)) {
|
if (!(estData && estData.est_data)) {
|
||||||
//We don't have the right data. Error!
|
//We don't have the right data. Error!
|
||||||
@@ -109,21 +109,17 @@ export function JobsAvailableContainer({
|
|||||||
});
|
});
|
||||||
return;
|
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.
|
//IO-539 Check for Parts Rate on PAL for SGI use case.
|
||||||
await CheckTaxRates(estData.est_data, bodyshop);
|
await CheckTaxRates(estData.est_data, bodyshop);
|
||||||
// }
|
|
||||||
// const newTotals = (
|
const newTotals = (
|
||||||
// await Axios.post("/job/totals", {
|
await Axios.post("/job/totals", {
|
||||||
// job: {
|
job: {
|
||||||
// ...estData.est_data,
|
...estData.est_data,
|
||||||
// joblines: estData.est_data.joblines.data,
|
joblines: estData.est_data.joblines.data,
|
||||||
// },
|
},
|
||||||
// })
|
})
|
||||||
// ).data;
|
).data;
|
||||||
|
|
||||||
let existingVehicles;
|
let existingVehicles;
|
||||||
if (estData.est_data.v_vin) {
|
if (estData.est_data.v_vin) {
|
||||||
@@ -138,9 +134,9 @@ export function JobsAvailableContainer({
|
|||||||
|
|
||||||
const newJob = {
|
const newJob = {
|
||||||
...estData.est_data,
|
...estData.est_data,
|
||||||
// clm_total: Dinero(newTotals.totals.total_repairs).toFormat("0.00"),
|
clm_total: Dinero(newTotals.totals.total_repairs).toFormat("0.00"),
|
||||||
// owner_owing: Dinero(newTotals.totals.custPayable.total).toFormat("0.00"),
|
owner_owing: Dinero(newTotals.totals.custPayable.total).toFormat("0.00"),
|
||||||
// job_totals: newTotals,
|
job_totals: newTotals,
|
||||||
date_open: moment(),
|
date_open: moment(),
|
||||||
status: bodyshop.md_ro_statuses.default_imported,
|
status: bodyshop.md_ro_statuses.default_imported,
|
||||||
notes: {
|
notes: {
|
||||||
@@ -164,23 +160,17 @@ export function JobsAvailableContainer({
|
|||||||
delete newJob.vehicle;
|
delete newJob.vehicle;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof newJob.kmin === "string") {
|
|
||||||
newJob.kmin = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const r = await insertNewJob({
|
const r = await insertNewJob({
|
||||||
variables: {
|
variables: {
|
||||||
job: newJob,
|
job: newJob,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
await Axios.post("/job/totalsssu", {
|
|
||||||
id: r.data.insert_jobs.returning[0].id,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (CriticalPartsScanning.treatment === "on") {
|
if (CriticalPartsScanning.treatment === "on") {
|
||||||
CriticalPartsScan(r.data.insert_jobs.returning[0].id);
|
CriticalPartsScan(r.data.insert_jobs.returning[0].id);
|
||||||
}
|
}
|
||||||
|
|
||||||
notification["success"]({
|
notification["success"]({
|
||||||
message: t("jobs.successes.created"),
|
message: t("jobs.successes.created"),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
@@ -194,7 +184,7 @@ export function JobsAvailableContainer({
|
|||||||
operation: AuditTrailMapping.jobimported(),
|
operation: AuditTrailMapping.jobimported(),
|
||||||
});
|
});
|
||||||
|
|
||||||
await deleteJob({
|
deleteJob({
|
||||||
variables: { id: estData.id },
|
variables: { id: estData.id },
|
||||||
}).then((r) => {
|
}).then((r) => {
|
||||||
refetch();
|
refetch();
|
||||||
@@ -202,16 +192,16 @@ export function JobsAvailableContainer({
|
|||||||
});
|
});
|
||||||
|
|
||||||
setPartsQueueToggle(bodyshop.md_functionality_toggles.parts_queue_toggle);
|
setPartsQueueToggle(bodyshop.md_functionality_toggles.parts_queue_toggle);
|
||||||
} catch (r) {
|
} catch (err) {
|
||||||
//error while inserting
|
//error while inserting
|
||||||
notification["error"]({
|
notification["error"]({
|
||||||
message: t("jobs.errors.creating", { error: r.message }),
|
message: t("jobs.errors.creating", { error: err.message }),
|
||||||
});
|
});
|
||||||
refetch();
|
refetch().catch(e => {console.error(`Something went wrong in jobs available table container - ${err.message || ''}`)});
|
||||||
setInsertLoading(false);
|
setInsertLoading(false);
|
||||||
setPartsQueueToggle(bodyshop.md_functionality_toggles.parts_queue_toggle);
|
setPartsQueueToggle(bodyshop.md_functionality_toggles.parts_queue_toggle);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//Supplement scenario
|
//Supplement scenario
|
||||||
@@ -234,7 +224,6 @@ export function JobsAvailableContainer({
|
|||||||
let supp = replaceEmpty({ ...estData.est_data });
|
let supp = replaceEmpty({ ...estData.est_data });
|
||||||
//IO-539 Check for Parts Rate on PAL for SGI use case.
|
//IO-539 Check for Parts Rate on PAL for SGI use case.
|
||||||
await CheckTaxRates(supp, bodyshop);
|
await CheckTaxRates(supp, bodyshop);
|
||||||
await ResolveCCCLineIssues(supp, bodyshop);
|
|
||||||
|
|
||||||
delete supp.owner;
|
delete supp.owner;
|
||||||
delete supp.vehicle;
|
delete supp.vehicle;
|
||||||
@@ -410,25 +399,6 @@ export function JobsAvailableContainer({
|
|||||||
partsQueueToggle={partsQueueToggle}
|
partsQueueToggle={partsQueueToggle}
|
||||||
setPartsQueueToggle={setPartsQueueToggle}
|
setPartsQueueToggle={setPartsQueueToggle}
|
||||||
/>
|
/>
|
||||||
{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]}>
|
<Row gutter={[16, 16]}>
|
||||||
<Col span={24}>
|
<Col span={24}>
|
||||||
<JobsAvailableTableComponent
|
<JobsAvailableTableComponent
|
||||||
@@ -460,158 +430,115 @@ function replaceEmpty(someObj, replaceValue = null) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function CheckTaxRates(estData, bodyshop) {
|
async function CheckTaxRates(estData, bodyshop) {
|
||||||
// //LKQ Check
|
//LKQ Check
|
||||||
// if (
|
if (
|
||||||
// !estData.parts_tax_rates?.PAL ||
|
!estData.parts_tax_rates?.PAL ||
|
||||||
// estData.parts_tax_rates?.PAL?.prt_tax_rt === null ||
|
estData.parts_tax_rates?.PAL?.prt_tax_rt === null ||
|
||||||
// estData.parts_tax_rates?.PAL?.prt_tax_rt === 0
|
estData.parts_tax_rates?.PAL?.prt_tax_rt === 0
|
||||||
// ) {
|
) {
|
||||||
// const res = await confirmDialog(
|
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.`
|
`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 (res) {
|
||||||
// if (!estData.parts_tax_rates.PAL) {
|
if (!estData.parts_tax_rates.PAL) {
|
||||||
// estData.parts_tax_rates.PAL = {
|
estData.parts_tax_rates.PAL = {
|
||||||
// prt_discp: 0,
|
prt_discp: 0,
|
||||||
// prt_mktyp: true,
|
prt_mktyp: true,
|
||||||
// prt_mkupp: 0,
|
prt_mkupp: 0,
|
||||||
// prt_type: "PAL",
|
prt_type: "PAL",
|
||||||
// };
|
};
|
||||||
// }
|
}
|
||||||
// estData.parts_tax_rates.PAL.prt_tax_rt =
|
estData.parts_tax_rates.PAL.prt_tax_rt =
|
||||||
// bodyshop.bill_tax_rates.state_tax_rate / 100;
|
bodyshop.bill_tax_rates.state_tax_rate / 100;
|
||||||
// estData.parts_tax_rates.PAL.prt_tax_in = true;
|
estData.parts_tax_rates.PAL.prt_tax_in = true;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// //PAC Check
|
//PAC Check
|
||||||
// if (
|
if (
|
||||||
// !estData.parts_tax_rates?.PAC ||
|
!estData.parts_tax_rates?.PAC ||
|
||||||
// estData.parts_tax_rates?.PAC?.prt_tax_rt === null ||
|
estData.parts_tax_rates?.PAC?.prt_tax_rt === null ||
|
||||||
// estData.parts_tax_rates?.PAC?.prt_tax_rt === 0
|
estData.parts_tax_rates?.PAC?.prt_tax_rt === 0
|
||||||
// ) {
|
) {
|
||||||
// const res = await confirmDialog(
|
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.`
|
`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 (res) {
|
||||||
// if (!estData.parts_tax_rates.PAC) {
|
if (!estData.parts_tax_rates.PAC) {
|
||||||
// estData.parts_tax_rates.PAC = {
|
estData.parts_tax_rates.PAC = {
|
||||||
// prt_discp: 0,
|
prt_discp: 0,
|
||||||
// prt_mktyp: true,
|
prt_mktyp: true,
|
||||||
// prt_mkupp: 0,
|
prt_mkupp: 0,
|
||||||
// prt_type: "PAC",
|
prt_type: "PAC",
|
||||||
// };
|
};
|
||||||
// }
|
}
|
||||||
// estData.parts_tax_rates.PAC.prt_tax_rt =
|
estData.parts_tax_rates.PAC.prt_tax_rt =
|
||||||
// bodyshop.bill_tax_rates.state_tax_rate / 100;
|
bodyshop.bill_tax_rates.state_tax_rate / 100;
|
||||||
// estData.parts_tax_rates.PAC.prt_tax_in = true;
|
estData.parts_tax_rates.PAC.prt_tax_in = true;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
//PAM Check
|
//PAM Check
|
||||||
if (!estData.parts_tax_rates?.PAM) {
|
if (
|
||||||
estData.parts_tax_rates.PAM = estData.parts_tax_rates.PAC;
|
!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 (
|
||||||
// if (
|
!estData.parts_tax_rates?.PAR ||
|
||||||
// !estData.parts_tax_rates?.PAM ||
|
estData.parts_tax_rates?.PAR?.prt_tax_rt === null ||
|
||||||
// estData.parts_tax_rates?.PAM?.prt_tax_rt === null ||
|
estData.parts_tax_rates?.PAR?.prt_tax_rt === 0
|
||||||
// estData.parts_tax_rates?.PAM?.prt_tax_rt === 0
|
) {
|
||||||
// ) {
|
const res = await confirmDialog(
|
||||||
// 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.`
|
||||||
// `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 (res) {
|
if (!estData.parts_tax_rates.PAR) {
|
||||||
// if (!estData.parts_tax_rates.PAM) {
|
estData.parts_tax_rates.PAR = {
|
||||||
// estData.parts_tax_rates.PAM = {
|
prt_discp: 0,
|
||||||
// prt_discp: 0,
|
prt_mktyp: true,
|
||||||
// prt_mktyp: true,
|
prt_mkupp: 0,
|
||||||
// prt_mkupp: 0,
|
prt_type: "PAR",
|
||||||
// prt_type: "PAM",
|
};
|
||||||
// };
|
}
|
||||||
// }
|
estData.parts_tax_rates.PAR.prt_tax_rt =
|
||||||
// estData.parts_tax_rates.PAM.prt_tax_rt =
|
bodyshop.bill_tax_rates.state_tax_rate / 100;
|
||||||
// bodyshop.bill_tax_rates.state_tax_rate / 100;
|
estData.parts_tax_rates.PAR.prt_tax_in = true;
|
||||||
// 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;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
//IO-1387 If a sublet line is NOT R&R, use the labor tax. If it is, use the sublet tax rate.
|
//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.
|
//Currently limited to SK shops only.
|
||||||
if (bodyshop.region_config === "CA_SK") {
|
//if (bodyshop.region_config === "CA_SK") {
|
||||||
estData.joblines.data.forEach((jl, index) => {
|
estData.joblines.data.forEach((jl, index) => {
|
||||||
if (
|
if (
|
||||||
(jl.part_type === "PASL" || jl.part_type === "PAS") &&
|
(jl.part_type === "PASL" || jl.part_type === "PAS") &&
|
||||||
jl.lbr_op !== "OP11"
|
jl.lbr_op !== "OP11"
|
||||||
) {
|
) {
|
||||||
estData.joblines.data[index].tax_part = jl.lbr_tax;
|
estData.joblines.data[index].tax_part = jl.lbr_tax;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Set markup lines and tax lines as taxable.
|
//Set markup lines and tax lines as taxable.
|
||||||
//900510 is a mark up. 900510 is a discount.
|
//900510 is a mark up. 900510 is a discount.
|
||||||
if (jl.db_ref === "900510") {
|
if (jl.db_ref === "900510") {
|
||||||
estData.joblines.data[index].tax_part = true;
|
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;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
//}
|
||||||
//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,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,8 +36,6 @@ export function JobsCloseAutoAllocate({ bodyshop, joblines, form, disabled }) {
|
|||||||
ret.profitcenter_part = defaults.profits["MAPA"];
|
ret.profitcenter_part = defaults.profits["MAPA"];
|
||||||
} else if (lineDesc.includes("ats amount")) {
|
} else if (lineDesc.includes("ats amount")) {
|
||||||
ret.profitcenter_part = defaults.profits["ATS"];
|
ret.profitcenter_part = defaults.profits["ATS"];
|
||||||
} else if (jl.act_price > 0) {
|
|
||||||
ret.profitcenter_part = defaults.profits["PAO"];
|
|
||||||
} else {
|
} else {
|
||||||
ret.profitcenter_part = null;
|
ret.profitcenter_part = null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
@@ -12,12 +12,6 @@ import FormItemPhone, {
|
|||||||
} from "../form-items-formatted/phone-form-item.component";
|
} from "../form-items-formatted/phone-form-item.component";
|
||||||
import JobsDetailRatesChangeButton from "../jobs-detail-rates-change-button/jobs-detail-rates-change-button.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 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 JobsMarkPstExempt from "../jobs-mark-pst-exempt/jobs-mark-pst-exempt.component";
|
||||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
@@ -264,28 +258,26 @@ export function JobsCreateJobsInfo({ bodyshop, form, selected }) {
|
|||||||
<CurrencyInput />
|
<CurrencyInput />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
{
|
<LayoutFormRow>
|
||||||
// <LayoutFormRow>
|
<Form.Item
|
||||||
// <Form.Item
|
label={t("jobs.fields.federal_tax_rate")}
|
||||||
// label={t("jobs.fields.federal_tax_rate")}
|
name="federal_tax_rate"
|
||||||
// name="federal_tax_rate"
|
>
|
||||||
// >
|
<InputNumber min={0} max={1} precision={2} />
|
||||||
// <InputNumber min={0} max={1} precision={2} />
|
</Form.Item>
|
||||||
// </Form.Item>
|
<Form.Item
|
||||||
// <Form.Item
|
label={t("jobs.fields.state_tax_rate")}
|
||||||
// label={t("jobs.fields.state_tax_rate")}
|
name="state_tax_rate"
|
||||||
// name="state_tax_rate"
|
>
|
||||||
// >
|
<InputNumber min={0} max={1} precision={2} />
|
||||||
// <InputNumber min={0} max={1} precision={2} />
|
</Form.Item>
|
||||||
// </Form.Item>
|
<Form.Item
|
||||||
// <Form.Item
|
label={t("jobs.fields.local_tax_rate")}
|
||||||
// label={t("jobs.fields.local_tax_rate")}
|
name="local_tax_rate"
|
||||||
// name="local_tax_rate"
|
>
|
||||||
// >
|
<InputNumber min={0} max={1} precision={2} />
|
||||||
// <InputNumber min={0} max={1} precision={2} />
|
</Form.Item>
|
||||||
// </Form.Item>
|
</LayoutFormRow>
|
||||||
// </LayoutFormRow>
|
|
||||||
}
|
|
||||||
<LayoutFormRow>
|
<LayoutFormRow>
|
||||||
<Form.Item label={t("jobs.fields.rate_lab")} name="rate_lab">
|
<Form.Item label={t("jobs.fields.rate_lab")} name="rate_lab">
|
||||||
<CurrencyInput />
|
<CurrencyInput />
|
||||||
@@ -364,10 +356,6 @@ export function JobsCreateJobsInfo({ bodyshop, form, selected }) {
|
|||||||
required={selected && true}
|
required={selected && true}
|
||||||
form={form}
|
form={form}
|
||||||
/>
|
/>
|
||||||
<JobsDetailRatesLabor form={form} />
|
|
||||||
<JobsDetailRatesMaterials form={form} />
|
|
||||||
<JobsDetailRatesOther form={form} />
|
|
||||||
<JobsDetailRatesTaxes form={form} />
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,8 +50,6 @@ const mapDispatchToProps = (dispatch) => ({
|
|||||||
dispatch(setModalContext({ context: context, modal: "jobCosting" })),
|
dispatch(setModalContext({ context: context, modal: "jobCosting" })),
|
||||||
setTimeTicketContext: (context) =>
|
setTimeTicketContext: (context) =>
|
||||||
dispatch(setModalContext({ context: context, modal: "timeTicket" })),
|
dispatch(setModalContext({ context: context, modal: "timeTicket" })),
|
||||||
setTimeTicketTaskContext: (context) =>
|
|
||||||
dispatch(setModalContext({ context: context, modal: "timeTicketTask" })),
|
|
||||||
setCardPaymentContext: (context) =>
|
setCardPaymentContext: (context) =>
|
||||||
dispatch(setModalContext({ context: context, modal: "cardPayment" })),
|
dispatch(setModalContext({ context: context, modal: "cardPayment" })),
|
||||||
insertAuditTrail: ({ jobid, operation }) =>
|
insertAuditTrail: ({ jobid, operation }) =>
|
||||||
@@ -69,7 +67,6 @@ export function JobsDetailHeaderActions({
|
|||||||
setJobCostingContext,
|
setJobCostingContext,
|
||||||
jobRO,
|
jobRO,
|
||||||
setTimeTicketContext,
|
setTimeTicketContext,
|
||||||
setTimeTicketTaskContext,
|
|
||||||
setCardPaymentContext,
|
setCardPaymentContext,
|
||||||
insertAuditTrail,
|
insertAuditTrail,
|
||||||
}) {
|
}) {
|
||||||
@@ -271,24 +268,6 @@ export function JobsDetailHeaderActions({
|
|||||||
>
|
>
|
||||||
{t("timetickets.actions.enter")}
|
{t("timetickets.actions.enter")}
|
||||||
</Menu.Item>
|
</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
|
<Menu.Item
|
||||||
key="enterpayments"
|
key="enterpayments"
|
||||||
disabled={!job.converted}
|
disabled={!job.converted}
|
||||||
|
|||||||
@@ -5,13 +5,9 @@ import { createStructuredSelector } from "reselect";
|
|||||||
import { selectJobReadOnly } from "../../redux/application/application.selectors";
|
import { selectJobReadOnly } from "../../redux/application/application.selectors";
|
||||||
import LaborAllocationsTableComponent from "../labor-allocations-table/labor-allocations-table.component";
|
import LaborAllocationsTableComponent from "../labor-allocations-table/labor-allocations-table.component";
|
||||||
import TimeTicketList from "../time-ticket-list/time-ticket-list.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({
|
const mapStateToProps = createStructuredSelector({
|
||||||
jobRO: selectJobReadOnly,
|
jobRO: selectJobReadOnly,
|
||||||
bodyshop: selectBodyshop,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, null)(JobsDetailLaborContainer);
|
export default connect(mapStateToProps, null)(JobsDetailLaborContainer);
|
||||||
@@ -52,7 +48,6 @@ const adjSpan = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function JobsDetailLaborContainer({
|
export function JobsDetailLaborContainer({
|
||||||
bodyshop,
|
|
||||||
jobRO,
|
jobRO,
|
||||||
job,
|
job,
|
||||||
jobId,
|
jobId,
|
||||||
@@ -63,12 +58,6 @@ export function JobsDetailLaborContainer({
|
|||||||
techConsole,
|
techConsole,
|
||||||
adjustments,
|
adjustments,
|
||||||
}) {
|
}) {
|
||||||
const { Enhanced_Payroll } = useTreatments(
|
|
||||||
["Enhanced_Payroll"],
|
|
||||||
{},
|
|
||||||
bodyshop.imexshopid
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Row gutter={[16, 16]}>
|
<Row gutter={[16, 16]}>
|
||||||
<Col {...ticketSpan}>
|
<Col {...ticketSpan}>
|
||||||
@@ -81,28 +70,14 @@ export function JobsDetailLaborContainer({
|
|||||||
jobId={jobId}
|
jobId={jobId}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
|
<Col {...adjSpan}>
|
||||||
{Enhanced_Payroll.treatment === "on" ? (
|
<LaborAllocationsTableComponent
|
||||||
<Col {...adjSpan}>
|
jobId={jobId}
|
||||||
<PayrollLaborAllocationsTable
|
joblines={joblines}
|
||||||
jobId={jobId}
|
timetickets={timetickets}
|
||||||
joblines={joblines}
|
adjustments={adjustments}
|
||||||
timetickets={timetickets}
|
/>
|
||||||
refetch={refetch}
|
</Col>
|
||||||
adjustments={adjustments}
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
) : (
|
|
||||||
<Col {...adjSpan}>
|
|
||||||
<LaborAllocationsTableComponent
|
|
||||||
jobId={jobId}
|
|
||||||
joblines={joblines}
|
|
||||||
timetickets={timetickets}
|
|
||||||
refetch={refetch}
|
|
||||||
adjustments={adjustments}
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
)}
|
|
||||||
</Row>
|
</Row>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 JobBillsTotal from "../job-bills-total/job-bills-total.component";
|
||||||
import PartsOrderListTableComponent from "../parts-order-list-table/parts-order-list-table.component";
|
import PartsOrderListTableComponent from "../parts-order-list-table/parts-order-list-table.component";
|
||||||
import PartsOrderModal from "../parts-order-modal/parts-order-modal.container";
|
import PartsOrderModal from "../parts-order-modal/parts-order-modal.container";
|
||||||
import PartsDispatchTable from "../parts-dispatch-table/parts-dispatch-table.component";
|
|
||||||
|
|
||||||
export default function JobsDetailPliComponent({
|
export default function JobsDetailPliComponent({
|
||||||
job,
|
job,
|
||||||
billsQuery,
|
billsQuery,
|
||||||
handleBillOnRowClick,
|
handleBillOnRowClick,
|
||||||
handlePartsOrderOnRowClick,
|
handlePartsOrderOnRowClick,
|
||||||
handlePartsDispatchOnRowClick,
|
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@@ -45,13 +43,6 @@ export default function JobsDetailPliComponent({
|
|||||||
billsQuery={billsQuery}
|
billsQuery={billsQuery}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={24}>
|
|
||||||
<PartsDispatchTable
|
|
||||||
job={job}
|
|
||||||
handleOnRowClick={handlePartsDispatchOnRowClick}
|
|
||||||
billsQuery={billsQuery}
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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 (
|
return (
|
||||||
<JobsDetailPliComponent
|
<JobsDetailPliComponent
|
||||||
job={job}
|
job={job}
|
||||||
billsQuery={billsQuery}
|
billsQuery={billsQuery}
|
||||||
handleBillOnRowClick={handleBillOnRowClick}
|
handleBillOnRowClick={handleBillOnRowClick}
|
||||||
handlePartsOrderOnRowClick={handlePartsOrderOnRowClick}
|
handlePartsOrderOnRowClick={handlePartsOrderOnRowClick}
|
||||||
handlePartsDispatchOnRowClick={handlePartsDispatchOnRowClick}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { selectJobReadOnly } from "../../redux/application/application.selectors";
|
import { selectJobReadOnly } from "../../redux/application/application.selectors";
|
||||||
import { selectBodyshop } from "../../redux/user/user.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 CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
||||||
import JobsDetailRatesChangeButton from "../jobs-detail-rates-change-button/jobs-detail-rates-change-button.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 JobsMarkPstExempt from "../jobs-mark-pst-exempt/jobs-mark-pst-exempt.component";
|
||||||
import FormRow from "../layout-form-row/layout-form-row.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 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({
|
const mapStateToProps = createStructuredSelector({
|
||||||
jobRO: selectJobReadOnly,
|
jobRO: selectJobReadOnly,
|
||||||
@@ -80,7 +84,14 @@ export function JobsDetailRates({ jobRO, form, job, bodyshop }) {
|
|||||||
>
|
>
|
||||||
<CurrencyInput disabled={jobRO || bodyshop.cdk_dealerid} />
|
<CurrencyInput disabled={jobRO || bodyshop.cdk_dealerid} />
|
||||||
</Form.Item>
|
</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
|
<Form.Item
|
||||||
label={t("jobs.fields.auto_add_ats")}
|
label={t("jobs.fields.auto_add_ats")}
|
||||||
name="auto_add_ats"
|
name="auto_add_ats"
|
||||||
@@ -109,7 +120,41 @@ export function JobsDetailRates({ jobRO, form, job, bodyshop }) {
|
|||||||
}}
|
}}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</FormRow>
|
</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
|
<Divider
|
||||||
orientation="left"
|
orientation="left"
|
||||||
type="horizontal"
|
type="horizontal"
|
||||||
@@ -197,15 +242,7 @@ export function JobsDetailRates({ jobRO, form, job, bodyshop }) {
|
|||||||
<CurrencyInput min={0} disabled={jobRO} />
|
<CurrencyInput min={0} disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</FormRow>
|
</FormRow>
|
||||||
<Divider orientation="left">Tax Profile</Divider>
|
|
||||||
|
|
||||||
<JobsDetailRatesProfileOVerride form={form} />
|
|
||||||
|
|
||||||
<JobsDetailRatesParts form={form} />
|
<JobsDetailRatesParts form={form} />
|
||||||
<JobsDetailRatesLabor form={form} />
|
|
||||||
<JobsDetailRatesMaterials form={form} />
|
|
||||||
<JobsDetailRatesOther form={form} />
|
|
||||||
<JobsDetailRatesTaxes form={form} />
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
|
||||||
@@ -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);
|
|
||||||
@@ -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);
|
|
||||||
@@ -29,7 +29,7 @@ export function JobsDetailRatesParts({
|
|||||||
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
||||||
name={["parts_tax_rates", "PAA", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
|
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")}
|
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
|
||||||
name={["parts_tax_rates", "PAA", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
|
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
|
||||||
@@ -68,58 +68,18 @@ export function JobsDetailRatesParts({
|
|||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
|
||||||
min={0}
|
|
||||||
max={100}
|
|
||||||
precision={4}
|
|
||||||
disabled={jobRO}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</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>
|
||||||
<LayoutFormRow header={t("joblines.fields.part_types.PAC")}>
|
<LayoutFormRow header={t("joblines.fields.part_types.PAC")}>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
||||||
name={["parts_tax_rates", "PAC", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
|
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")}
|
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
|
||||||
name={["parts_tax_rates", "PAC", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
|
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
|
||||||
@@ -158,58 +118,18 @@ export function JobsDetailRatesParts({
|
|||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
|
||||||
min={0}
|
|
||||||
max={100}
|
|
||||||
precision={4}
|
|
||||||
disabled={jobRO}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</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>
|
||||||
<LayoutFormRow header={t("joblines.fields.part_types.PAL")}>
|
<LayoutFormRow header={t("joblines.fields.part_types.PAL")}>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
||||||
name={["parts_tax_rates", "PAL", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
|
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")}
|
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
|
||||||
name={["parts_tax_rates", "PAL", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
|
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
|
||||||
@@ -248,58 +168,18 @@ export function JobsDetailRatesParts({
|
|||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
|
||||||
min={0}
|
|
||||||
max={100}
|
|
||||||
precision={4}
|
|
||||||
disabled={jobRO}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</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>
|
||||||
<LayoutFormRow header={t("joblines.fields.part_types.PAG")}>
|
<LayoutFormRow header={t("joblines.fields.part_types.PAG")}>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
||||||
name={["parts_tax_rates", "PAG", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
|
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")}
|
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
|
||||||
name={["parts_tax_rates", "PAG", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
|
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
|
||||||
@@ -338,58 +218,18 @@ export function JobsDetailRatesParts({
|
|||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
|
||||||
min={0}
|
|
||||||
max={100}
|
|
||||||
precision={4}
|
|
||||||
disabled={jobRO}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</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>
|
||||||
<LayoutFormRow header={t("joblines.fields.part_types.PAM")}>
|
<LayoutFormRow header={t("joblines.fields.part_types.PAM")}>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
||||||
name={["parts_tax_rates", "PAM", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
|
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")}
|
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
|
||||||
name={["parts_tax_rates", "PAM", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
|
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
|
||||||
@@ -428,58 +268,18 @@ export function JobsDetailRatesParts({
|
|||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
|
||||||
min={0}
|
|
||||||
max={100}
|
|
||||||
precision={4}
|
|
||||||
disabled={jobRO}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</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>
|
||||||
<LayoutFormRow header={t("joblines.fields.part_types.PAN")}>
|
<LayoutFormRow header={t("joblines.fields.part_types.PAN")}>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
||||||
name={["parts_tax_rates", "PAN", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
|
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")}
|
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
|
||||||
name={["parts_tax_rates", "PAN", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
|
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
|
||||||
@@ -518,58 +318,18 @@ export function JobsDetailRatesParts({
|
|||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
|
||||||
min={0}
|
|
||||||
max={100}
|
|
||||||
precision={4}
|
|
||||||
disabled={jobRO}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</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>
|
||||||
<LayoutFormRow header={t("joblines.fields.part_types.PAO")}>
|
<LayoutFormRow header={t("joblines.fields.part_types.PAO")}>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
||||||
name={["parts_tax_rates", "PAO", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
|
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")}
|
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
|
||||||
name={["parts_tax_rates", "PAO", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
|
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
|
||||||
@@ -608,58 +368,18 @@ export function JobsDetailRatesParts({
|
|||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
|
||||||
min={0}
|
|
||||||
max={100}
|
|
||||||
precision={4}
|
|
||||||
disabled={jobRO}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</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>
|
||||||
<LayoutFormRow header={t("joblines.fields.part_types.PAP")}>
|
<LayoutFormRow header={t("joblines.fields.part_types.PAP")}>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
||||||
name={["parts_tax_rates", "PAP", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
|
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")}
|
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
|
||||||
name={["parts_tax_rates", "PAP", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
|
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
|
||||||
@@ -698,58 +418,18 @@ export function JobsDetailRatesParts({
|
|||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
|
||||||
min={0}
|
|
||||||
max={100}
|
|
||||||
precision={4}
|
|
||||||
disabled={jobRO}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</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>
|
||||||
<LayoutFormRow header={t("joblines.fields.part_types.PAR")}>
|
<LayoutFormRow header={t("joblines.fields.part_types.PAR")}>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
||||||
name={["parts_tax_rates", "PAR", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
|
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")}
|
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
|
||||||
name={["parts_tax_rates", "PAR", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
|
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
|
||||||
@@ -788,58 +468,18 @@ export function JobsDetailRatesParts({
|
|||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
|
||||||
min={0}
|
|
||||||
max={100}
|
|
||||||
precision={4}
|
|
||||||
disabled={jobRO}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</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>
|
||||||
<LayoutFormRow header={t("joblines.fields.part_types.PAS")}>
|
<LayoutFormRow header={t("joblines.fields.part_types.PAS")}>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
||||||
name={["parts_tax_rates", "PAS", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
|
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")}
|
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
|
||||||
name={["parts_tax_rates", "PAS", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
|
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
|
||||||
@@ -878,58 +518,18 @@ export function JobsDetailRatesParts({
|
|||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
|
||||||
min={0}
|
|
||||||
max={100}
|
|
||||||
precision={4}
|
|
||||||
disabled={jobRO}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</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>
|
||||||
<LayoutFormRow header={t("joblines.fields.part_types.PASL")}>
|
<LayoutFormRow header={t("joblines.fields.part_types.PASL")}>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
||||||
name={["parts_tax_rates", "PASL", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
|
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")}
|
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
|
||||||
name={["parts_tax_rates", "PASL", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
|
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
|
||||||
@@ -968,58 +568,18 @@ export function JobsDetailRatesParts({
|
|||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
|
||||||
min={0}
|
|
||||||
max={100}
|
|
||||||
precision={4}
|
|
||||||
disabled={jobRO}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</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>
|
||||||
<LayoutFormRow header={t("joblines.fields.part_types.CCDR")}>
|
<LayoutFormRow header={t("joblines.fields.part_types.CCDR")}>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
||||||
name={["parts_tax_rates", "CCDR", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
|
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")}
|
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
|
||||||
name={["parts_tax_rates", "CCDR", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
|
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")}
|
label={t("jobs.fields.parts_tax_rates.prt_tax_rt")}
|
||||||
name={["parts_tax_rates", "CCDR", "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>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<LayoutFormRow header={t("joblines.fields.part_types.CCF")}>
|
<LayoutFormRow header={t("joblines.fields.part_types.CCF")}>
|
||||||
@@ -1053,7 +613,7 @@ export function JobsDetailRatesParts({
|
|||||||
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
||||||
name={["parts_tax_rates", "CCF", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
|
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")}
|
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
|
||||||
name={["parts_tax_rates", "CCF", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
|
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")}
|
label={t("jobs.fields.parts_tax_rates.prt_tax_rt")}
|
||||||
name={["parts_tax_rates", "CCF", "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>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<LayoutFormRow header={t("joblines.fields.part_types.CCM")}>
|
<LayoutFormRow header={t("joblines.fields.part_types.CCM")}>
|
||||||
@@ -1087,7 +647,7 @@ export function JobsDetailRatesParts({
|
|||||||
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
||||||
name={["parts_tax_rates", "CCM", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
|
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")}
|
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
|
||||||
name={["parts_tax_rates", "CCM", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
|
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")}
|
label={t("jobs.fields.parts_tax_rates.prt_tax_rt")}
|
||||||
name={["parts_tax_rates", "CCM", "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>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<LayoutFormRow header={t("joblines.fields.part_types.CCC")}>
|
<LayoutFormRow header={t("joblines.fields.part_types.CCC")}>
|
||||||
@@ -1121,7 +681,7 @@ export function JobsDetailRatesParts({
|
|||||||
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
||||||
name={["parts_tax_rates", "CCC", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
|
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")}
|
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
|
||||||
name={["parts_tax_rates", "CCC", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
|
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")}
|
label={t("jobs.fields.parts_tax_rates.prt_tax_rt")}
|
||||||
name={["parts_tax_rates", "CCC", "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>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<LayoutFormRow header={t("joblines.fields.part_types.CCD")}>
|
<LayoutFormRow header={t("joblines.fields.part_types.CCD")}>
|
||||||
@@ -1155,7 +715,7 @@ export function JobsDetailRatesParts({
|
|||||||
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
||||||
name={["parts_tax_rates", "CCD", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_mktyp")}
|
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")}
|
label={t("jobs.fields.parts_tax_rates.prt_mkupp")}
|
||||||
name={["parts_tax_rates", "CCD", "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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.parts_tax_rates.prt_tax_in")}
|
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")}
|
label={t("jobs.fields.parts_tax_rates.prt_tax_rt")}
|
||||||
name={["parts_tax_rates", "CCD", "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>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<LayoutFormRow>
|
<LayoutFormRow>
|
||||||
<Form.Item label={t("jobs.fields.tax_tow_rt")} name="tax_tow_rt">
|
<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>
|
||||||
<Form.Item label={t("jobs.fields.tax_str_rt")} name="tax_str_rt">
|
<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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.tax_paint_mat_rt")}
|
label={t("jobs.fields.tax_paint_mat_rt")}
|
||||||
name="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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.tax_shop_mat_rt")}
|
label={t("jobs.fields.tax_shop_mat_rt")}
|
||||||
name="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>
|
||||||
<Form.Item label={t("jobs.fields.tax_sub_rt")} name="tax_sub_rt">
|
<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>
|
||||||
<Form.Item label={t("jobs.fields.tax_lbr_rt")} name="tax_lbr_rt">
|
<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>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.tax_levies_rt")}
|
label={t("jobs.fields.tax_levies_rt")}
|
||||||
name="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>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
</Collapse.Panel>
|
</Collapse.Panel>
|
||||||
|
|||||||
@@ -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>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -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>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,105 +1,117 @@
|
|||||||
import {
|
import {BranchesOutlined, ExclamationCircleFilled, PauseCircleOutlined, SyncOutlined,} from "@ant-design/icons";
|
||||||
SyncOutlined,
|
import {useQuery} from "@apollo/client";
|
||||||
ExclamationCircleFilled,
|
import {Button, Card, Grid, Input, Space, Table, Tooltip, Typography} from "antd";
|
||||||
PauseCircleOutlined,
|
|
||||||
BranchesOutlined,
|
|
||||||
} from "@ant-design/icons";
|
|
||||||
import { useQuery } from "@apollo/client";
|
|
||||||
import { Button, Card, Grid, Input, Space, Table, Tooltip } from "antd";
|
|
||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import React, { useState } from "react";
|
import React, {useEffect, useState} from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import {connect} from "react-redux";
|
||||||
import { Link, useHistory, useLocation } from "react-router-dom";
|
import {Link, useHistory, useLocation} from "react-router-dom";
|
||||||
import { createStructuredSelector } from "reselect";
|
import {createStructuredSelector} from "reselect";
|
||||||
import { QUERY_ALL_ACTIVE_JOBS } from "../../graphql/jobs.queries";
|
import {QUERY_ALL_ACTIVE_JOBS_PAGINATED} from "../../graphql/jobs.queries";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||||
import { onlyUnique } from "../../utils/arrayHelper";
|
import {onlyUnique} from "../../utils/arrayHelper";
|
||||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||||
import { alphaSort } from "../../utils/sorters";
|
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
import ChatOpenButton from "../chat-open-button/chat-open-button.component";
|
import ChatOpenButton from "../chat-open-button/chat-open-button.component";
|
||||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
|
import {flattenDeep} from "lodash";
|
||||||
|
import { pageLimit } from '../../utils/config';
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
});
|
});
|
||||||
|
|
||||||
export function JobsList({ bodyshop }) {
|
const mapDispatchToProps = () => ({
|
||||||
const searchParams = queryString.parse(useLocation().search);
|
});
|
||||||
const { selected } = searchParams;
|
|
||||||
|
export function JobsList({bodyshop,}) {
|
||||||
|
const search = queryString.parse(useLocation().search);
|
||||||
|
const [openSearchResults, setOpenSearchResults] = useState([]);
|
||||||
|
const [searchLoading, setSearchLoading] = useState(false);
|
||||||
|
const {page, selected, sortorder, sortcolumn,statusFilters} = search;
|
||||||
|
|
||||||
const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
|
const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
|
||||||
.filter((screen) => !!screen[1])
|
.filter((screen) => !!screen[1])
|
||||||
.slice(-1)[0];
|
.slice(-1)[0];
|
||||||
const { loading, error, data, refetch } = useQuery(QUERY_ALL_ACTIVE_JOBS, {
|
|
||||||
|
const {loading, error, data, refetch} = useQuery(QUERY_ALL_ACTIVE_JOBS_PAGINATED, {
|
||||||
variables: {
|
variables: {
|
||||||
statuses: bodyshop.md_ro_statuses.active_statuses || ["Open", "Open*"],
|
offset: page ? (page - 1) * pageLimit : 0,
|
||||||
|
limit: pageLimit,
|
||||||
|
statusFilters: statusFilters ? JSON.parse(statusFilters) : bodyshop.md_ro_statuses.active_statuses || ["Open", "Open*"],
|
||||||
|
order: [
|
||||||
|
{
|
||||||
|
[sortcolumn || "ro_number"]:
|
||||||
|
sortorder && sortorder !== "false"
|
||||||
|
? (sortorder === "descend"
|
||||||
|
? "desc"
|
||||||
|
: "asc")
|
||||||
|
: "desc",
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
fetchPolicy: "network-only",
|
fetchPolicy: "network-only",
|
||||||
nextFetchPolicy: "network-only",
|
nextFetchPolicy: "network-only",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const total = data?.jobs_aggregate?.aggregate?.count || 0;
|
||||||
|
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
sortedInfo: {},
|
filteredInfo: {text: ""},
|
||||||
filteredInfo: { text: "" },
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const {t} = useTranslation();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const [searchText, setSearchText] = useState("");
|
|
||||||
|
|
||||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
const jobs = data?.jobs || [];
|
||||||
|
|
||||||
const jobs = data
|
|
||||||
? searchText === ""
|
|
||||||
? data.jobs
|
|
||||||
: data.jobs.filter(
|
|
||||||
(j) =>
|
|
||||||
(j.ro_number || "")
|
|
||||||
.toString()
|
|
||||||
.toLowerCase()
|
|
||||||
.includes(searchText.toLowerCase()) ||
|
|
||||||
(j.ownr_co_nm || "")
|
|
||||||
.toLowerCase()
|
|
||||||
.includes(searchText.toLowerCase()) ||
|
|
||||||
(j.comments || "")
|
|
||||||
.toLowerCase()
|
|
||||||
.includes(searchText.toLowerCase()) ||
|
|
||||||
(j.ownr_fn || "")
|
|
||||||
.toLowerCase()
|
|
||||||
.includes(searchText.toLowerCase()) ||
|
|
||||||
(j.ownr_ln || "")
|
|
||||||
.toLowerCase()
|
|
||||||
.includes(searchText.toLowerCase()) ||
|
|
||||||
(j.clm_no || "").toLowerCase().includes(searchText.toLowerCase()) ||
|
|
||||||
(j.plate_no || "")
|
|
||||||
.toLowerCase()
|
|
||||||
.includes(searchText.toLowerCase()) ||
|
|
||||||
(j.v_model_desc || "")
|
|
||||||
.toLowerCase()
|
|
||||||
.includes(searchText.toLowerCase()) ||
|
|
||||||
(j.est_ct_fn || "")
|
|
||||||
.toLowerCase()
|
|
||||||
.includes(searchText.toLowerCase()) ||
|
|
||||||
(j.est_ct_ln || "")
|
|
||||||
.toLowerCase()
|
|
||||||
.includes(searchText.toLowerCase()) ||
|
|
||||||
(j.v_make_desc || "")
|
|
||||||
.toLowerCase()
|
|
||||||
.includes(searchText.toLowerCase())
|
|
||||||
)
|
|
||||||
: [];
|
|
||||||
|
|
||||||
const handleTableChange = (pagination, filters, sorter) => {
|
const handleTableChange = (pagination, filters, sorter) => {
|
||||||
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
|
search.page = pagination.current;
|
||||||
|
search.sortcolumn = sorter.column && sorter.column.key;
|
||||||
|
search.sortorder = sorter.order;
|
||||||
|
|
||||||
|
if (filters.status) {
|
||||||
|
search.statusFilters = JSON.stringify(flattenDeep(filters.status));
|
||||||
|
} else {
|
||||||
|
delete search.statusFilters;
|
||||||
|
}
|
||||||
|
|
||||||
|
history.push({search: queryString.stringify(search)});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (search.search && search.search.trim() !== "") {
|
||||||
|
searchJobs().catch(e => {
|
||||||
|
console.error('Something went wrong searching for jobs in the job-list component', e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (error) return <AlertComponent message={error.message} type="error"/>;
|
||||||
|
|
||||||
|
async function searchJobs(value) {
|
||||||
|
try {
|
||||||
|
setSearchLoading(true);
|
||||||
|
const searchData = await axios.post("/search", {
|
||||||
|
search: value || search.search,
|
||||||
|
index: "jobs",
|
||||||
|
});
|
||||||
|
setOpenSearchResults(searchData.data.hits.hits.map((s) => s._source));
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Error while fetching search results", error);
|
||||||
|
} finally {
|
||||||
|
setSearchLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const handleOnRowClick = (record) => {
|
const handleOnRowClick = (record) => {
|
||||||
if (record) {
|
if (record) {
|
||||||
if (record.id) {
|
if (record.id) {
|
||||||
history.push({
|
history.push({
|
||||||
search: queryString.stringify({
|
search: queryString.stringify({
|
||||||
...searchParams,
|
...search,
|
||||||
selected: record.id,
|
selected: record.id,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
@@ -112,11 +124,9 @@ export function JobsList({ bodyshop }) {
|
|||||||
title: t("jobs.fields.ro_number"),
|
title: t("jobs.fields.ro_number"),
|
||||||
dataIndex: "ro_number",
|
dataIndex: "ro_number",
|
||||||
key: "ro_number",
|
key: "ro_number",
|
||||||
sorter: (a, b) =>
|
sorter: true,
|
||||||
parseInt((a.ro_number || "0").replace(/\D/g, "")) -
|
|
||||||
parseInt((b.ro_number || "0").replace(/\D/g, "")),
|
|
||||||
sortOrder:
|
sortOrder:
|
||||||
state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
|
sortcolumn === "ro_number" && sortorder,
|
||||||
|
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<Link
|
<Link
|
||||||
@@ -126,14 +136,14 @@ export function JobsList({ bodyshop }) {
|
|||||||
<Space>
|
<Space>
|
||||||
{record.ro_number || t("general.labels.na")}
|
{record.ro_number || t("general.labels.na")}
|
||||||
{record.production_vars && record.production_vars.alert ? (
|
{record.production_vars && record.production_vars.alert ? (
|
||||||
<ExclamationCircleFilled className="production-alert" />
|
<ExclamationCircleFilled className="production-alert"/>
|
||||||
) : null}
|
) : null}
|
||||||
{record.suspended && (
|
{record.suspended && (
|
||||||
<PauseCircleOutlined style={{ color: "orangered" }} />
|
<PauseCircleOutlined style={{color: "orangered"}}/>
|
||||||
)}
|
)}
|
||||||
{record.iouparent && (
|
{record.iouparent && (
|
||||||
<Tooltip title={t("jobs.labels.iou")}>
|
<Tooltip title={t("jobs.labels.iou")}>
|
||||||
<BranchesOutlined style={{ color: "orangered" }} />
|
<BranchesOutlined style={{color: "orangered"}}/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
</Space>
|
</Space>
|
||||||
@@ -145,22 +155,20 @@ export function JobsList({ bodyshop }) {
|
|||||||
dataIndex: "owner",
|
dataIndex: "owner",
|
||||||
key: "owner",
|
key: "owner",
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
|
|
||||||
responsive: ["md"],
|
responsive: ["md"],
|
||||||
sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
|
sorter: false,
|
||||||
sortOrder:
|
sortOrder: sortcolumn === "owner" && sortorder,
|
||||||
state.sortedInfo.columnKey === "owner" && state.sortedInfo.order,
|
|
||||||
render: (text, record) => {
|
render: (text, record) => {
|
||||||
return record.ownerid ? (
|
return record.ownerid ? (
|
||||||
<Link
|
<Link
|
||||||
to={"/manage/owners/" + record.ownerid}
|
to={"/manage/owners/" + record.ownerid}
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
>
|
>
|
||||||
<OwnerNameDisplay ownerObject={record} />
|
<OwnerNameDisplay ownerObject={record}/>
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
<span>
|
<span>
|
||||||
<OwnerNameDisplay ownerObject={record} />
|
<OwnerNameDisplay ownerObject={record}/>
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -172,7 +180,7 @@ export function JobsList({ bodyshop }) {
|
|||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
responsive: ["md"],
|
responsive: ["md"],
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<ChatOpenButton phone={record.ownr_ph1} jobid={record.id} />
|
<ChatOpenButton phone={record.ownr_ph1} jobid={record.id}/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -182,7 +190,7 @@ export function JobsList({ bodyshop }) {
|
|||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
responsive: ["md"],
|
responsive: ["md"],
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<ChatOpenButton phone={record.ownr_ph2} jobid={record.id} />
|
<ChatOpenButton phone={record.ownr_ph2} jobid={record.id}/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -191,25 +199,17 @@ export function JobsList({ bodyshop }) {
|
|||||||
dataIndex: "status",
|
dataIndex: "status",
|
||||||
key: "status",
|
key: "status",
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
|
sorter: true,
|
||||||
sorter: (a, b) => alphaSort(a.status, b.status),
|
|
||||||
sortOrder:
|
sortOrder:
|
||||||
state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
|
sortcolumn === "status" && sortorder,
|
||||||
filters:
|
filters:bodyshop.md_ro_statuses.statuses.map((s) => {
|
||||||
(jobs &&
|
return { text: s, value: [s] };
|
||||||
jobs
|
}),
|
||||||
.map((j) => j.status)
|
|
||||||
.filter(onlyUnique)
|
|
||||||
.map((s) => {
|
|
||||||
return {
|
|
||||||
text: s || "No Status*",
|
|
||||||
value: [s],
|
|
||||||
};
|
|
||||||
})) ||
|
|
||||||
[],
|
|
||||||
onFilter: (value, record) => value.includes(record.status),
|
onFilter: (value, record) => value.includes(record.status),
|
||||||
|
render: (text, record) => {
|
||||||
|
return record.status || t("general.labels.na");
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
title: t("jobs.fields.vehicle"),
|
title: t("jobs.fields.vehicle"),
|
||||||
dataIndex: "vehicle",
|
dataIndex: "vehicle",
|
||||||
@@ -237,11 +237,10 @@ export function JobsList({ bodyshop }) {
|
|||||||
dataIndex: "plate_no",
|
dataIndex: "plate_no",
|
||||||
key: "plate_no",
|
key: "plate_no",
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
|
|
||||||
responsive: ["md"],
|
responsive: ["md"],
|
||||||
sorter: (a, b) => alphaSort(a.plate_no, b.plate_no),
|
sorter: true,
|
||||||
sortOrder:
|
sortOrder:
|
||||||
state.sortedInfo.columnKey === "plate_no" && state.sortedInfo.order,
|
sortcolumn === "plate_no" && sortorder,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("jobs.fields.clm_no"),
|
title: t("jobs.fields.clm_no"),
|
||||||
@@ -249,9 +248,9 @@ export function JobsList({ bodyshop }) {
|
|||||||
key: "clm_no",
|
key: "clm_no",
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
responsive: ["md"],
|
responsive: ["md"],
|
||||||
sorter: (a, b) => alphaSort(a.clm_no, b.clm_no),
|
sorter: true,
|
||||||
sortOrder:
|
sortOrder:
|
||||||
state.sortedInfo.columnKey === "clm_no" && state.sortedInfo.order,
|
sortcolumn === "clm_no" && sortorder,
|
||||||
render: (text, record) =>
|
render: (text, record) =>
|
||||||
`${record.clm_no || ""}${
|
`${record.clm_no || ""}${
|
||||||
record.po_number ? ` (PO: ${record.po_number})` : ""
|
record.po_number ? ` (PO: ${record.po_number})` : ""
|
||||||
@@ -262,19 +261,20 @@ export function JobsList({ bodyshop }) {
|
|||||||
dataIndex: "ins_co_nm",
|
dataIndex: "ins_co_nm",
|
||||||
key: "ins_co_nm",
|
key: "ins_co_nm",
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
filters:
|
// TODO: Restore Filters?
|
||||||
(jobs &&
|
// filters:
|
||||||
jobs
|
// (jobs &&
|
||||||
.map((j) => j.ins_co_nm)
|
// jobs
|
||||||
.filter(onlyUnique)
|
// .map((j) => j.ins_co_nm)
|
||||||
.map((s) => {
|
// .filter(onlyUnique)
|
||||||
return {
|
// .map((s) => {
|
||||||
text: s,
|
// return {
|
||||||
value: [s],
|
// text: s,
|
||||||
};
|
// value: [s],
|
||||||
})) ||
|
// };
|
||||||
[],
|
// })) ||
|
||||||
onFilter: (value, record) => value.includes(record.ins_co_nm),
|
// [],
|
||||||
|
// onFilter: (value, record) => value.includes(record.ins_co_nm),
|
||||||
responsive: ["md"],
|
responsive: ["md"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -283,10 +283,9 @@ export function JobsList({ bodyshop }) {
|
|||||||
key: "clm_total",
|
key: "clm_total",
|
||||||
responsive: ["md"],
|
responsive: ["md"],
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
|
sorter: true,
|
||||||
sorter: (a, b) => a.clm_total - b.clm_total,
|
|
||||||
sortOrder:
|
sortOrder:
|
||||||
state.sortedInfo.columnKey === "clm_total" && state.sortedInfo.order,
|
sortcolumn === "clm_total" && sortorder,
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<CurrencyFormatter>{record.clm_total}</CurrencyFormatter>
|
<CurrencyFormatter>{record.clm_total}</CurrencyFormatter>
|
||||||
),
|
),
|
||||||
@@ -297,23 +296,24 @@ export function JobsList({ bodyshop }) {
|
|||||||
key: "jobs.labels.estimator",
|
key: "jobs.labels.estimator",
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
responsive: ["xl"],
|
responsive: ["xl"],
|
||||||
filterSearch: true,
|
// TODO Restore Filters?
|
||||||
filters:
|
// filterSearch: true,
|
||||||
(jobs &&
|
// filters:
|
||||||
jobs
|
// (jobs &&
|
||||||
.map((j) => `${j.est_ct_fn || ""} ${j.est_ct_ln || ""}`.trim())
|
// jobs
|
||||||
.filter(onlyUnique)
|
// .map((j) => `${j.est_ct_fn || ""} ${j.est_ct_ln || ""}`.trim())
|
||||||
.map((s) => {
|
// .filter(onlyUnique)
|
||||||
return {
|
// .map((s) => {
|
||||||
text: s || "N/A",
|
// return {
|
||||||
value: [s],
|
// text: s || "N/A",
|
||||||
};
|
// value: [s],
|
||||||
})) ||
|
// };
|
||||||
[],
|
// })) ||
|
||||||
onFilter: (value, record) =>
|
// [],
|
||||||
value.includes(
|
// onFilter: (value, record) =>
|
||||||
`${record.est_ct_fn || ""} ${record.est_ct_ln || ""}`.trim()
|
// value.includes(
|
||||||
),
|
// `${record.est_ct_fn || ""} ${record.est_ct_ln || ""}`.trim()
|
||||||
|
// ),
|
||||||
render: (text, record) =>
|
render: (text, record) =>
|
||||||
`${record.est_ct_fn || ""} ${record.est_ct_ln || ""}`.trim(),
|
`${record.est_ct_fn || ""} ${record.est_ct_ln || ""}`.trim(),
|
||||||
},
|
},
|
||||||
@@ -349,26 +349,57 @@ export function JobsList({ bodyshop }) {
|
|||||||
title={t("titles.bc.jobs-active")}
|
title={t("titles.bc.jobs-active")}
|
||||||
extra={
|
extra={
|
||||||
<Space wrap>
|
<Space wrap>
|
||||||
|
{search.search && (
|
||||||
|
<>
|
||||||
|
<Typography.Title level={4}>
|
||||||
|
{t("general.labels.searchresults", { search: search.search })}
|
||||||
|
</Typography.Title>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
delete search.search;
|
||||||
|
delete search.page;
|
||||||
|
history.push({ search: queryString.stringify(search) });
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("general.actions.clear")}
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<Button onClick={() => refetch()}>
|
<Button onClick={() => refetch()}>
|
||||||
<SyncOutlined />
|
<SyncOutlined />
|
||||||
</Button>
|
</Button>
|
||||||
<Input.Search
|
<Input.Search
|
||||||
placeholder={t("general.labels.search")}
|
placeholder={search.search || t("general.labels.search")}
|
||||||
onChange={(e) => {
|
onSearch={(value) => {
|
||||||
setSearchText(e.target.value);
|
search.search = value;
|
||||||
|
history.push({ search: queryString.stringify(search) });
|
||||||
|
searchJobs(value);
|
||||||
}}
|
}}
|
||||||
value={searchText}
|
loading={loading || searchLoading}
|
||||||
enterButton
|
enterButton
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Table
|
<Table
|
||||||
loading={loading}
|
loading={loading || searchLoading }
|
||||||
pagination={{ defaultPageSize: 50 }}
|
pagination={
|
||||||
|
search?.search
|
||||||
|
? {
|
||||||
|
pageSize: pageLimit,
|
||||||
|
showSizeChanger: false,
|
||||||
|
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
pageSize: pageLimit,
|
||||||
|
current: parseInt(page || 1),
|
||||||
|
total: total,
|
||||||
|
showSizeChanger: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
dataSource={jobs}
|
dataSource={search?.search ? openSearchResults : jobs}
|
||||||
scroll={{
|
scroll={{
|
||||||
x: selectedBreakpoint ? scrollMapper[selectedBreakpoint[0]] : "100%",
|
x: selectedBreakpoint ? scrollMapper[selectedBreakpoint[0]] : "100%",
|
||||||
}}
|
}}
|
||||||
@@ -380,9 +411,9 @@ export function JobsList({ bodyshop }) {
|
|||||||
type: "radio",
|
type: "radio",
|
||||||
}}
|
}}
|
||||||
onChange={handleTableChange}
|
onChange={handleTableChange}
|
||||||
onRow={(record, rowIndex) => {
|
onRow={(record) => {
|
||||||
return {
|
return {
|
||||||
onClick: (event) => {
|
onClick: () => {
|
||||||
handleOnRowClick(record);
|
handleOnRowClick(record);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -392,4 +423,4 @@ export function JobsList({ bodyshop }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps, null)(JobsList);
|
export default connect(mapStateToProps, mapDispatchToProps)(JobsList);
|
||||||
|
|||||||
@@ -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);
|
|
||||||
@@ -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>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
|
||||||
import { Card, Col, Input, Row, Space, Typography } from "antd";
|
import { Card, Col, Input, Row, Space, Typography } from "antd";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
@@ -24,13 +23,8 @@ export function PrintCenterJobsComponent({ printCenterModal, bodyshop }) {
|
|||||||
const { id: jobId, job } = printCenterModal.context;
|
const { id: jobId, job } = printCenterModal.context;
|
||||||
const tempList = TemplateList("job", {});
|
const tempList = TemplateList("job", {});
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { Enhanced_Payroll } = useTreatments(
|
|
||||||
["Enhanced_Payroll"],
|
|
||||||
{},
|
|
||||||
bodyshop.imexshopid
|
|
||||||
);
|
|
||||||
|
|
||||||
const Templates =
|
const JobsReportsList =
|
||||||
bodyshop.cdk_dealerid === null && bodyshop.pbs_serialnumber === null
|
bodyshop.cdk_dealerid === null && bodyshop.pbs_serialnumber === null
|
||||||
? Object.keys(tempList)
|
? Object.keys(tempList)
|
||||||
.map((key) => {
|
.map((key) => {
|
||||||
@@ -57,26 +51,7 @@ export function PrintCenterJobsComponent({ printCenterModal, bodyshop }) {
|
|||||||
bodyshop.region_config.includes(Object.keys(temp.regions)) ===
|
bodyshop.region_config.includes(Object.keys(temp.regions)) ===
|
||||||
true)
|
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 =
|
const filteredJobsReportsList =
|
||||||
search !== ""
|
search !== ""
|
||||||
? JobsReportsList.filter((r) =>
|
? JobsReportsList.filter((r) =>
|
||||||
|
|||||||
@@ -9,11 +9,9 @@ export default function PrintWrapperComponent({
|
|||||||
children,
|
children,
|
||||||
id,
|
id,
|
||||||
emailOnly = false,
|
emailOnly = false,
|
||||||
disabled,
|
|
||||||
}) {
|
}) {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const handlePrint = async (type) => {
|
const handlePrint = async (type) => {
|
||||||
if (disabled) return;
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
await GenerateDocument(templateObject, messageObject, type, id);
|
await GenerateDocument(templateObject, messageObject, type, id);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
@@ -22,18 +20,8 @@ export default function PrintWrapperComponent({
|
|||||||
return (
|
return (
|
||||||
<Space>
|
<Space>
|
||||||
{children || null}
|
{children || null}
|
||||||
{!emailOnly && (
|
{!emailOnly && <PrinterFilled onClick={() => handlePrint("p")} />}
|
||||||
<PrinterFilled
|
<MailFilled onClick={() => handlePrint("e")} />
|
||||||
disabled={disabled}
|
|
||||||
onClick={() => handlePrint("p")}
|
|
||||||
style={{ cursor: disabled ? "not-allowed" : null }}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<MailFilled
|
|
||||||
disabled={disabled}
|
|
||||||
onClick={() => handlePrint("e")}
|
|
||||||
style={{ cursor: disabled ? "not-allowed" : null }}
|
|
||||||
/>
|
|
||||||
{loading && <Spin />}
|
{loading && <Spin />}
|
||||||
</Space>
|
</Space>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -24,8 +24,6 @@ import ProductionListColumnNote from "./production-list-columns.productionnote.c
|
|||||||
import ProductionListColumnCategory from "./production-list-columns.status.category";
|
import ProductionListColumnCategory from "./production-list-columns.status.category";
|
||||||
import ProductionListColumnStatus from "./production-list-columns.status.component";
|
import ProductionListColumnStatus from "./production-list-columns.status.component";
|
||||||
import ProductionlistColumnTouchTime from "./prodution-list-columns.touchtime.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, bodyshop }) => {
|
const r = ({ technician, state, activeStatuses, bodyshop }) => {
|
||||||
return [
|
return [
|
||||||
@@ -40,29 +38,6 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => {
|
|||||||
</Link>
|
</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"),
|
title: i18n.t("jobs.fields.ro_number"),
|
||||||
dataIndex: "ro_number",
|
dataIndex: "ro_number",
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ export function ProductionListDetail({
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
placement="right"
|
placement="right"
|
||||||
width={"50%"}
|
width={"33%"}
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
visible={selected}
|
visible={selected}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { useLazyQuery } from "@apollo/client";
|
import { useLazyQuery } from "@apollo/client";
|
||||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Card,
|
Card,
|
||||||
@@ -20,7 +19,6 @@ import { createStructuredSelector } from "reselect";
|
|||||||
import { QUERY_ACTIVE_EMPLOYEES } from "../../graphql/employees.queries";
|
import { QUERY_ACTIVE_EMPLOYEES } from "../../graphql/employees.queries";
|
||||||
import { QUERY_ALL_VENDORS } from "../../graphql/vendors.queries";
|
import { QUERY_ALL_VENDORS } from "../../graphql/vendors.queries";
|
||||||
import { selectReportCenter } from "../../redux/modals/modals.selectors";
|
import { selectReportCenter } from "../../redux/modals/modals.selectors";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
|
||||||
import DatePIckerRanges from "../../utils/DatePickerRanges";
|
import DatePIckerRanges from "../../utils/DatePickerRanges";
|
||||||
import { GenerateDocument } from "../../utils/RenderTemplate";
|
import { GenerateDocument } from "../../utils/RenderTemplate";
|
||||||
import { TemplateList } from "../../utils/TemplateConstants";
|
import { TemplateList } from "../../utils/TemplateConstants";
|
||||||
@@ -29,7 +27,6 @@ import VendorSearchSelect from "../vendor-search-select/vendor-search-select.com
|
|||||||
import "./report-center-modal.styles.scss";
|
import "./report-center-modal.styles.scss";
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
reportCenterModal: selectReportCenter,
|
reportCenterModal: selectReportCenter,
|
||||||
bodyshop: selectBodyshop,
|
|
||||||
});
|
});
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||||
@@ -39,38 +36,16 @@ export default connect(
|
|||||||
mapDispatchToProps
|
mapDispatchToProps
|
||||||
)(ReportCenterModalComponent);
|
)(ReportCenterModalComponent);
|
||||||
|
|
||||||
export function ReportCenterModalComponent({ reportCenterModal, bodyshop }) {
|
export function ReportCenterModalComponent({ reportCenterModal }) {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
const { Enhanced_Payroll } = useTreatments(
|
|
||||||
["Enhanced_Payroll"],
|
|
||||||
{},
|
|
||||||
bodyshop.imexshopid
|
|
||||||
);
|
|
||||||
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const Templates = TemplateList("report_center");
|
const Templates = TemplateList("report_center");
|
||||||
const ReportsList =
|
const ReportsList = Object.keys(Templates).map((key) => {
|
||||||
Enhanced_Payroll.treatment === "on"
|
return Templates[key];
|
||||||
? 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 { visible } = reportCenterModal;
|
||||||
|
|
||||||
const [callVendorQuery, { data: vendorData, called: vendorCalled }] =
|
const [callVendorQuery, { data: vendorData, called: vendorCalled }] =
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
Switch,
|
Switch,
|
||||||
Table,
|
Table,
|
||||||
} from "antd";
|
} from "antd";
|
||||||
|
import { useForm } from "antd/es/form/Form";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import querystring from "query-string";
|
import querystring from "query-string";
|
||||||
import React, { useEffect } from "react";
|
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 FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
|
||||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
import ShopEmployeeAddVacation from "./shop-employees-add-vacation.component";
|
import ShopEmployeeAddVacation from "./shop-employees-add-vacation.component";
|
||||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -47,7 +46,7 @@ const mapDispatchToProps = (dispatch) => ({
|
|||||||
|
|
||||||
export function ShopEmployeesFormComponent({ bodyshop }) {
|
export function ShopEmployeesFormComponent({ bodyshop }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [form] = Form.useForm();
|
const [form] = useForm();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const search = querystring.parse(useLocation().search);
|
const search = querystring.parse(useLocation().search);
|
||||||
const [deleteVacation] = useMutation(DELETE_VACATION);
|
const [deleteVacation] = useMutation(DELETE_VACATION);
|
||||||
@@ -57,11 +56,7 @@ export function ShopEmployeesFormComponent({ bodyshop }) {
|
|||||||
fetchPolicy: "network-only",
|
fetchPolicy: "network-only",
|
||||||
nextFetchPolicy: "network-only",
|
nextFetchPolicy: "network-only",
|
||||||
});
|
});
|
||||||
const { Enhanced_Payroll } = useTreatments(
|
|
||||||
["Enhanced_Payroll"],
|
|
||||||
{},
|
|
||||||
bodyshop.imexshopid
|
|
||||||
);
|
|
||||||
const client = useApolloClient();
|
const client = useApolloClient();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (data && data.employees_by_pk) form.setFieldsValue(data.employees_by_pk);
|
if (data && data.employees_by_pk) form.setFieldsValue(data.employees_by_pk);
|
||||||
@@ -367,7 +362,7 @@ export function ShopEmployeesFormComponent({ bodyshop }) {
|
|||||||
{t("timetickets.labels.shift")}
|
{t("timetickets.labels.shift")}
|
||||||
</Select.Option>
|
</Select.Option>
|
||||||
|
|
||||||
{bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber || Enhanced_Payroll.treatment === "on"
|
{bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber
|
||||||
? CiecaSelect(false, true)
|
? CiecaSelect(false, true)
|
||||||
: bodyshop.md_responsibility_centers.costs.map(
|
: bodyshop.md_responsibility_centers.costs.map(
|
||||||
(c) => (
|
(c) => (
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import ShopInfoResponsibilityCenterComponent from "./shop-info.responsibilitycen
|
|||||||
import ShopInfoROStatusComponent from "./shop-info.rostatus.component";
|
import ShopInfoROStatusComponent from "./shop-info.rostatus.component";
|
||||||
import ShopInfoSchedulingComponent from "./shop-info.scheduling.component";
|
import ShopInfoSchedulingComponent from "./shop-info.scheduling.component";
|
||||||
import ShopInfoSpeedPrint from "./shop-info.speedprint.component";
|
import ShopInfoSpeedPrint from "./shop-info.speedprint.component";
|
||||||
import ShopInfoTaskPresets from "./shop-info.task-presets.component";
|
|
||||||
import { useHistory, useLocation } from "react-router-dom";
|
import { useHistory, useLocation } from "react-router-dom";
|
||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
|
|
||||||
@@ -97,12 +96,6 @@ export function ShopInfoComponent({ bodyshop, form, saveLoading }) {
|
|||||||
<ShopInfoPartsScan form={form} />
|
<ShopInfoPartsScan form={form} />
|
||||||
</Tabs.TabPane>
|
</Tabs.TabPane>
|
||||||
)}
|
)}
|
||||||
<Tabs.TabPane
|
|
||||||
key="task-presets"
|
|
||||||
tab={t("bodyshop.labels.task-presets")}
|
|
||||||
>
|
|
||||||
<ShopInfoTaskPresets form={form} />
|
|
||||||
</Tabs.TabPane>
|
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -189,22 +189,20 @@ export function ShopInfoGeneral({ form, bodyshop }) {
|
|||||||
<Switch />
|
<Switch />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
{
|
<Form.Item shouldUpdate noStyle>
|
||||||
// <Form.Item shouldUpdate noStyle>
|
{() => (
|
||||||
// {() => (
|
<Form.Item
|
||||||
// <Form.Item
|
label={t("bodyshop.labels.qbo_usa")}
|
||||||
// label={t("bodyshop.labels.qbo_usa")}
|
shouldUpdate
|
||||||
// shouldUpdate
|
valuePropName="checked"
|
||||||
// valuePropName="checked"
|
name={["accountingconfig", "qbo_usa"]}
|
||||||
// name={["accountingconfig", "qbo_usa"]}
|
>
|
||||||
// >
|
<Switch
|
||||||
// <Switch
|
disabled={!form.getFieldValue(["accountingconfig", "qbo"])}
|
||||||
// disabled={!form.getFieldValue(["accountingconfig", "qbo"])}
|
/>
|
||||||
// />
|
</Form.Item>
|
||||||
// </Form.Item>
|
)}
|
||||||
// )}
|
</Form.Item>
|
||||||
// </Form.Item>
|
|
||||||
}
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("bodyshop.labels.qbo_departmentid")}
|
label={t("bodyshop.labels.qbo_departmentid")}
|
||||||
name={["accountingconfig", "qbo_departmentid"]}
|
name={["accountingconfig", "qbo_departmentid"]}
|
||||||
@@ -293,34 +291,36 @@ export function ShopInfoGeneral({ form, bodyshop }) {
|
|||||||
>
|
>
|
||||||
<InputNumber min={0} precision={2} />
|
<InputNumber min={0} precision={2} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
{
|
<Form.Item
|
||||||
// <Form.Item
|
label={t("bodyshop.fields.federal_tax_id")}
|
||||||
// label={t("bodyshop.fields.federal_tax_id")}
|
name="federal_tax_id"
|
||||||
// name="federal_tax_id"
|
rules={[
|
||||||
// >
|
{
|
||||||
// <Input />
|
required: true,
|
||||||
// </Form.Item>
|
//message: t("general.validation.required"),
|
||||||
}
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("bodyshop.fields.state_tax_id")}
|
label={t("bodyshop.fields.state_tax_id")}
|
||||||
name="state_tax_id"
|
name="state_tax_id"
|
||||||
>
|
>
|
||||||
<Input />
|
<Input />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
{
|
<Form.Item
|
||||||
// <Form.Item
|
label={t("bodyshop.fields.invoice_federal_tax_rate")}
|
||||||
// label={t("bodyshop.fields.invoice_federal_tax_rate")}
|
name={["bill_tax_rates", "federal_tax_rate"]}
|
||||||
// name={["bill_tax_rates", "federal_tax_rate"]}
|
rules={[
|
||||||
// rules={[
|
{
|
||||||
// {
|
required: true,
|
||||||
// required: true,
|
//message: t("general.validation.required"),
|
||||||
// //message: t("general.validation.required"),
|
},
|
||||||
// },
|
]}
|
||||||
// ]}
|
>
|
||||||
// >
|
<InputNumber />
|
||||||
// <InputNumber />
|
</Form.Item>
|
||||||
// </Form.Item>
|
|
||||||
}
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("bodyshop.fields.invoice_state_tax_rate")}
|
label={t("bodyshop.fields.invoice_state_tax_rate")}
|
||||||
name={["bill_tax_rates", "state_tax_rate"]}
|
name={["bill_tax_rates", "state_tax_rate"]}
|
||||||
|
|||||||
@@ -400,18 +400,6 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
|
|||||||
>
|
>
|
||||||
<InputNumber />
|
<InputNumber />
|
||||||
</Form.Item>
|
</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"]}
|
|
||||||
>
|
|
||||||
<InputNumber />
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("bodyshop.fields.rbac.owners.list")}
|
label={t("bodyshop.fields.rbac.owners.list")}
|
||||||
rules={[
|
rules={[
|
||||||
@@ -544,42 +532,6 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
|
|||||||
>
|
>
|
||||||
<InputNumber />
|
<InputNumber />
|
||||||
</Form.Item>
|
</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
|
<Form.Item
|
||||||
label={t("bodyshop.fields.rbac.shop.vendors")}
|
label={t("bodyshop.fields.rbac.shop.vendors")}
|
||||||
rules={[
|
rules={[
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
|
|||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
import { useTreatments } from "@splitsoftware/splitio-react";
|
||||||
import ShopInfoResponsibilitycentersTaxesComponent from "./shop-info.responsibilitycenters.taxes.component";
|
|
||||||
|
|
||||||
const SelectorDiv = styled.div`
|
const SelectorDiv = styled.div`
|
||||||
.ant-form-item .ant-select {
|
.ant-form-item .ant-select {
|
||||||
@@ -4117,124 +4116,122 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
|
|||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
</SelectorDiv>
|
</SelectorDiv>
|
||||||
|
|
||||||
{
|
<LayoutFormRow
|
||||||
// <LayoutFormRow
|
header={t("bodyshop.labels.responsibilitycenters.tax_accounts")}
|
||||||
// header={t("bodyshop.labels.responsibilitycenters.tax_accounts")}
|
id="tax_accounts"
|
||||||
// id="tax_accounts"
|
>
|
||||||
// >
|
<Form.Item
|
||||||
// <Form.Item
|
label={t("bodyshop.fields.responsibilitycenters.federal_tax")}
|
||||||
// label={t("bodyshop.fields.responsibilitycenters.federal_tax")}
|
rules={[
|
||||||
// rules={[
|
{
|
||||||
// {
|
required: true,
|
||||||
// required: true,
|
//message: t("general.validation.required"),
|
||||||
// //message: t("general.validation.required"),
|
},
|
||||||
// },
|
]}
|
||||||
// ]}
|
name={["md_responsibility_centers", "taxes", "federal", "name"]}
|
||||||
// name={["md_responsibility_centers", "taxes", "federal", "name"]}
|
>
|
||||||
// >
|
<Input />
|
||||||
// <Input />
|
</Form.Item>
|
||||||
// </Form.Item>
|
{/* <Form.Item
|
||||||
// {/* <Form.Item
|
label={t("bodyshop.fields.responsibilitycenter_accountnumber")}
|
||||||
// label={t("bodyshop.fields.responsibilitycenter_accountnumber")}
|
rules={[
|
||||||
// rules={[
|
{
|
||||||
// {
|
required: true,
|
||||||
// required: true,
|
//message: t("general.validation.required"),
|
||||||
// //message: t("general.validation.required"),
|
},
|
||||||
// },
|
]}
|
||||||
// ]}
|
name={[
|
||||||
// name={[
|
"md_responsibility_centers",
|
||||||
// "md_responsibility_centers",
|
"taxes",
|
||||||
// "taxes",
|
"federal",
|
||||||
// "federal",
|
"accountnumber",
|
||||||
// "accountnumber",
|
]}
|
||||||
// ]}
|
>
|
||||||
// >
|
<Input />
|
||||||
// <Input />
|
</Form.Item> */}
|
||||||
// </Form.Item> */}
|
{/* <Form.Item
|
||||||
// {/* <Form.Item
|
label={t("bodyshop.fields.responsibilitycenter_accountname")}
|
||||||
// label={t("bodyshop.fields.responsibilitycenter_accountname")}
|
rules={[
|
||||||
// rules={[
|
{
|
||||||
// {
|
required: true,
|
||||||
// required: true,
|
//message: t("general.validation.required"),
|
||||||
// //message: t("general.validation.required"),
|
},
|
||||||
// },
|
]}
|
||||||
// ]}
|
name={[
|
||||||
// name={[
|
"md_responsibility_centers",
|
||||||
// "md_responsibility_centers",
|
"taxes",
|
||||||
// "taxes",
|
"federal",
|
||||||
// "federal",
|
"accountname",
|
||||||
// "accountname",
|
]}
|
||||||
// ]}
|
>
|
||||||
// >
|
<Input />
|
||||||
// <Input />
|
</Form.Item> */}
|
||||||
// </Form.Item> */}
|
<Form.Item
|
||||||
// <Form.Item
|
label={t("bodyshop.fields.responsibilitycenter_accountdesc")}
|
||||||
// label={t("bodyshop.fields.responsibilitycenter_accountdesc")}
|
rules={[
|
||||||
// rules={[
|
{
|
||||||
// {
|
required: true,
|
||||||
// required: true,
|
//message: t("general.validation.required"),
|
||||||
// //message: t("general.validation.required"),
|
},
|
||||||
// },
|
]}
|
||||||
// ]}
|
name={[
|
||||||
// name={[
|
"md_responsibility_centers",
|
||||||
// "md_responsibility_centers",
|
"taxes",
|
||||||
// "taxes",
|
"federal",
|
||||||
// "federal",
|
"accountdesc",
|
||||||
// "accountdesc",
|
]}
|
||||||
// ]}
|
>
|
||||||
// >
|
<Input />
|
||||||
// <Input />
|
</Form.Item>
|
||||||
// </Form.Item>
|
<Form.Item
|
||||||
// <Form.Item
|
label={t("bodyshop.fields.responsibilitycenter_accountitem")}
|
||||||
// label={t("bodyshop.fields.responsibilitycenter_accountitem")}
|
rules={[
|
||||||
// rules={[
|
{
|
||||||
// {
|
required: true,
|
||||||
// required: true,
|
//message: t("general.validation.required"),
|
||||||
// //message: t("general.validation.required"),
|
},
|
||||||
// },
|
]}
|
||||||
// ]}
|
name={[
|
||||||
// name={[
|
"md_responsibility_centers",
|
||||||
// "md_responsibility_centers",
|
"taxes",
|
||||||
// "taxes",
|
"federal",
|
||||||
// "federal",
|
"accountitem",
|
||||||
// "accountitem",
|
]}
|
||||||
// ]}
|
>
|
||||||
// >
|
<Input />
|
||||||
// <Input />
|
</Form.Item>
|
||||||
// </Form.Item>
|
{(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
|
||||||
// {(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
|
<Form.Item
|
||||||
// <Form.Item
|
label={t("bodyshop.fields.dms.dms_acctnumber")}
|
||||||
// label={t("bodyshop.fields.dms.dms_acctnumber")}
|
rules={[
|
||||||
// rules={[
|
{
|
||||||
// {
|
required: true,
|
||||||
// required: true,
|
//message: t("general.validation.required"),
|
||||||
// //message: t("general.validation.required"),
|
},
|
||||||
// },
|
]}
|
||||||
// ]}
|
name={[
|
||||||
// name={[
|
"md_responsibility_centers",
|
||||||
// "md_responsibility_centers",
|
"taxes",
|
||||||
// "taxes",
|
"federal",
|
||||||
// "federal",
|
"dms_acctnumber",
|
||||||
// "dms_acctnumber",
|
]}
|
||||||
// ]}
|
>
|
||||||
// >
|
<Input />
|
||||||
// <Input />
|
</Form.Item>
|
||||||
// </Form.Item>
|
)}
|
||||||
// )}
|
<Form.Item
|
||||||
// <Form.Item
|
label={t("bodyshop.fields.responsibilitycenter_rate")}
|
||||||
// label={t("bodyshop.fields.responsibilitycenter_rate")}
|
rules={[
|
||||||
// rules={[
|
{
|
||||||
// {
|
required: true,
|
||||||
// required: true,
|
//message: t("general.validation.required"),
|
||||||
// //message: t("general.validation.required"),
|
},
|
||||||
// },
|
]}
|
||||||
// ]}
|
name={["md_responsibility_centers", "taxes", "federal", "rate"]}
|
||||||
// name={["md_responsibility_centers", "taxes", "federal", "rate"]}
|
>
|
||||||
// >
|
<InputNumber precision={2} />
|
||||||
// <InputNumber precision={2} />
|
</Form.Item>
|
||||||
// </Form.Item>
|
</LayoutFormRow>
|
||||||
// </LayoutFormRow>
|
|
||||||
}
|
|
||||||
{DmsAp.treatment === "on" && (
|
{DmsAp.treatment === "on" && (
|
||||||
<LayoutFormRow id="federal_tax_itc">
|
<LayoutFormRow id="federal_tax_itc">
|
||||||
<Form.Item
|
<Form.Item
|
||||||
@@ -4350,242 +4347,202 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
)}
|
)}
|
||||||
{
|
<LayoutFormRow id="state_tax">
|
||||||
// <LayoutFormRow id="state_tax">
|
<Form.Item
|
||||||
// <Form.Item
|
label={t("bodyshop.fields.responsibilitycenters.state_tax")}
|
||||||
// label={t("bodyshop.fields.responsibilitycenters.state_tax")}
|
rules={[
|
||||||
// rules={[
|
{
|
||||||
// {
|
required: true,
|
||||||
// required: true,
|
//message: t("general.validation.required"),
|
||||||
// //message: t("general.validation.required"),
|
},
|
||||||
// },
|
]}
|
||||||
// ]}
|
name={["md_responsibility_centers", "taxes", "state", "name"]}
|
||||||
// name={["md_responsibility_centers", "taxes", "state", "name"]}
|
>
|
||||||
// >
|
<Input />
|
||||||
// <Input />
|
</Form.Item>
|
||||||
// </Form.Item>
|
{/* <Form.Item
|
||||||
// {/* <Form.Item
|
label={t("bodyshop.fields.responsibilitycenter_accountnumber")}
|
||||||
// label={t("bodyshop.fields.responsibilitycenter_accountnumber")}
|
rules={[
|
||||||
// rules={[
|
{
|
||||||
// {
|
required: true,
|
||||||
// required: true,
|
//message: t("general.validation.required"),
|
||||||
// //message: t("general.validation.required"),
|
},
|
||||||
// },
|
]}
|
||||||
// ]}
|
name={[
|
||||||
// name={[
|
"md_responsibility_centers",
|
||||||
// "md_responsibility_centers",
|
"taxes",
|
||||||
// "taxes",
|
"state",
|
||||||
// "state",
|
"accountnumber",
|
||||||
// "accountnumber",
|
]}
|
||||||
// ]}
|
>
|
||||||
// >
|
<Input />
|
||||||
// <Input />
|
</Form.Item>
|
||||||
// </Form.Item>
|
<Form.Item
|
||||||
// <Form.Item
|
label={t("bodyshop.fields.responsibilitycenter_accountname")}
|
||||||
// label={t("bodyshop.fields.responsibilitycenter_accountname")}
|
rules={[
|
||||||
// rules={[
|
{
|
||||||
// {
|
required: true,
|
||||||
// required: true,
|
//message: t("general.validation.required"),
|
||||||
// //message: t("general.validation.required"),
|
},
|
||||||
// },
|
]}
|
||||||
// ]}
|
name={["md_responsibility_centers", "taxes", "state", "accountname"]}
|
||||||
// name={["md_responsibility_centers", "taxes", "state", "accountname"]}
|
>
|
||||||
// >
|
<Input />
|
||||||
// <Input />
|
</Form.Item> */}
|
||||||
// </Form.Item> */}
|
<Form.Item
|
||||||
// <Form.Item
|
label={t("bodyshop.fields.responsibilitycenter_accountdesc")}
|
||||||
// label={t("bodyshop.fields.responsibilitycenter_accountdesc")}
|
rules={[
|
||||||
// rules={[
|
{
|
||||||
// {
|
required: true,
|
||||||
// required: true,
|
//message: t("general.validation.required"),
|
||||||
// //message: t("general.validation.required"),
|
},
|
||||||
// },
|
]}
|
||||||
// ]}
|
name={["md_responsibility_centers", "taxes", "state", "accountdesc"]}
|
||||||
// name={["md_responsibility_centers", "taxes", "state", "accountdesc"]}
|
>
|
||||||
// >
|
<Input />
|
||||||
// <Input />
|
</Form.Item>
|
||||||
// </Form.Item>
|
<Form.Item
|
||||||
// <Form.Item
|
label={t("bodyshop.fields.responsibilitycenter_accountitem")}
|
||||||
// label={t("bodyshop.fields.responsibilitycenter_accountitem")}
|
rules={[
|
||||||
// rules={[
|
{
|
||||||
// {
|
required: true,
|
||||||
// required: true,
|
//message: t("general.validation.required"),
|
||||||
// //message: t("general.validation.required"),
|
},
|
||||||
// },
|
]}
|
||||||
// ]}
|
name={["md_responsibility_centers", "taxes", "state", "accountitem"]}
|
||||||
// name={["md_responsibility_centers", "taxes", "state", "accountitem"]}
|
>
|
||||||
// >
|
<Input />
|
||||||
// <Input />
|
</Form.Item>
|
||||||
// </Form.Item>
|
{(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
|
||||||
// {(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
|
<Form.Item
|
||||||
// <Form.Item
|
label={t("bodyshop.fields.dms.dms_acctnumber")}
|
||||||
// label={t("bodyshop.fields.dms.dms_acctnumber")}
|
rules={[
|
||||||
// rules={[
|
{
|
||||||
// {
|
required: true,
|
||||||
// required: true,
|
//message: t("general.validation.required"),
|
||||||
// //message: t("general.validation.required"),
|
},
|
||||||
// },
|
]}
|
||||||
// ]}
|
name={[
|
||||||
// name={[
|
"md_responsibility_centers",
|
||||||
// "md_responsibility_centers",
|
"taxes",
|
||||||
// "taxes",
|
"state",
|
||||||
// "state",
|
"dms_acctnumber",
|
||||||
// "dms_acctnumber",
|
]}
|
||||||
// ]}
|
>
|
||||||
// >
|
<Input />
|
||||||
// <Input />
|
</Form.Item>
|
||||||
// </Form.Item>
|
)}
|
||||||
// )}
|
<Form.Item
|
||||||
// <Form.Item
|
label={t("bodyshop.fields.responsibilitycenter_rate")}
|
||||||
// label={t("bodyshop.fields.responsibilitycenter_rate")}
|
rules={[
|
||||||
// rules={[
|
{
|
||||||
// {
|
required: true,
|
||||||
// required: true,
|
//message: t("general.validation.required"),
|
||||||
// //message: t("general.validation.required"),
|
},
|
||||||
// },
|
]}
|
||||||
// ]}
|
name={["md_responsibility_centers", "taxes", "state", "rate"]}
|
||||||
// name={["md_responsibility_centers", "taxes", "state", "rate"]}
|
>
|
||||||
// >
|
<InputNumber precision={2} />
|
||||||
// <InputNumber precision={2} />
|
</Form.Item>
|
||||||
// </Form.Item>
|
</LayoutFormRow>
|
||||||
// </LayoutFormRow>
|
<LayoutFormRow id="local_tax">
|
||||||
}
|
<Form.Item
|
||||||
<ShopInfoResponsibilitycentersTaxesComponent form={form} />
|
label={t("bodyshop.fields.responsibilitycenters.local_tax")}
|
||||||
<Form.Item
|
rules={[
|
||||||
label={t("bodyshop.fields.responsibilitycenters.itemexemptcode")}
|
{
|
||||||
rules={[
|
required: true,
|
||||||
{
|
//message: t("general.validation.required"),
|
||||||
required: true,
|
},
|
||||||
//message: t("general.validation.required"),
|
]}
|
||||||
},
|
name={["md_responsibility_centers", "taxes", "local", "name"]}
|
||||||
]}
|
>
|
||||||
name={["md_responsibility_centers", "taxes", "itemexemptcode"]}
|
<Input />
|
||||||
>
|
</Form.Item>
|
||||||
<Input />
|
{/* <Form.Item
|
||||||
</Form.Item>
|
label={t("bodyshop.fields.responsibilitycenter_accountnumber")}
|
||||||
<Form.Item
|
rules={[
|
||||||
label={t("bodyshop.fields.responsibilitycenters.invoiceexemptcode")}
|
{
|
||||||
rules={[
|
required: true,
|
||||||
{
|
//message: t("general.validation.required"),
|
||||||
required: true,
|
},
|
||||||
//message: t("general.validation.required"),
|
]}
|
||||||
},
|
name={[
|
||||||
]}
|
"md_responsibility_centers",
|
||||||
name={["md_responsibility_centers", "taxes", "invoiceexemptcode"]}
|
"taxes",
|
||||||
>
|
"local",
|
||||||
<Input />
|
"accountnumber",
|
||||||
</Form.Item>
|
]}
|
||||||
|
>
|
||||||
{
|
<Input />
|
||||||
// <LayoutFormRow id="local_tax">
|
</Form.Item>
|
||||||
// <Form.Item
|
<Form.Item
|
||||||
// label={t("bodyshop.fields.responsibilitycenters.local_tax")}
|
label={t("bodyshop.fields.responsibilitycenter_accountname")}
|
||||||
// rules={[
|
rules={[
|
||||||
// {
|
{
|
||||||
// required: true,
|
required: true,
|
||||||
// //message: t("general.validation.required"),
|
//message: t("general.validation.required"),
|
||||||
// },
|
},
|
||||||
// ]}
|
]}
|
||||||
// name={["md_responsibility_centers", "taxes", "local", "name"]}
|
name={["md_responsibility_centers", "taxes", "local", "accountname"]}
|
||||||
// >
|
>
|
||||||
// <Input />
|
<Input />
|
||||||
// </Form.Item>
|
</Form.Item> */}
|
||||||
// {/* <Form.Item
|
<Form.Item
|
||||||
// label={t("bodyshop.fields.responsibilitycenter_accountnumber")}
|
label={t("bodyshop.fields.responsibilitycenter_accountdesc")}
|
||||||
// rules={[
|
rules={[
|
||||||
// {
|
{
|
||||||
// required: true,
|
required: true,
|
||||||
// //message: t("general.validation.required"),
|
//message: t("general.validation.required"),
|
||||||
// },
|
},
|
||||||
// ]}
|
]}
|
||||||
// name={[
|
name={["md_responsibility_centers", "taxes", "local", "accountdesc"]}
|
||||||
// "md_responsibility_centers",
|
>
|
||||||
// "taxes",
|
<Input />
|
||||||
// "local",
|
</Form.Item>
|
||||||
// "accountnumber",
|
<Form.Item
|
||||||
// ]}
|
label={t("bodyshop.fields.responsibilitycenter_accountitem")}
|
||||||
// >
|
rules={[
|
||||||
// <Input />
|
{
|
||||||
// </Form.Item>
|
required: true,
|
||||||
// <Form.Item
|
//message: t("general.validation.required"),
|
||||||
// label={t("bodyshop.fields.responsibilitycenter_accountname")}
|
},
|
||||||
// rules={[
|
]}
|
||||||
// {
|
name={["md_responsibility_centers", "taxes", "local", "accountitem"]}
|
||||||
// required: true,
|
>
|
||||||
// //message: t("general.validation.required"),
|
<Input />
|
||||||
// },
|
</Form.Item>
|
||||||
// ]}
|
{(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
|
||||||
// name={["md_responsibility_centers", "taxes", "local", "accountname"]}
|
<Form.Item
|
||||||
// >
|
label={t("bodyshop.fields.dms.dms_acctnumber")}
|
||||||
// <Input />
|
rules={[
|
||||||
// </Form.Item> */}
|
{
|
||||||
// <Form.Item
|
required: true,
|
||||||
// label={t("bodyshop.fields.responsibilitycenter_accountdesc")}
|
//message: t("general.validation.required"),
|
||||||
// rules={[
|
},
|
||||||
// {
|
]}
|
||||||
// required: true,
|
name={[
|
||||||
// //message: t("general.validation.required"),
|
"md_responsibility_centers",
|
||||||
// },
|
"taxes",
|
||||||
// ]}
|
"local",
|
||||||
// name={[
|
"dms_acctnumber",
|
||||||
// "md_responsibility_centers",
|
]}
|
||||||
// "taxes",
|
>
|
||||||
// "local",
|
<Input />
|
||||||
// "accountdesc",
|
</Form.Item>
|
||||||
// ]}
|
)}
|
||||||
// >
|
<Form.Item
|
||||||
// <Input />
|
label={t("bodyshop.fields.responsibilitycenter_rate")}
|
||||||
// </Form.Item>
|
rules={[
|
||||||
// <Form.Item
|
{
|
||||||
// label={t("bodyshop.fields.responsibilitycenter_accountitem")}
|
required: true,
|
||||||
// rules={[
|
//message: t("general.validation.required"),
|
||||||
// {
|
},
|
||||||
// required: true,
|
]}
|
||||||
// //message: t("general.validation.required"),
|
name={["md_responsibility_centers", "taxes", "local", "rate"]}
|
||||||
// },
|
>
|
||||||
// ]}
|
<InputNumber precision={2} />
|
||||||
// name={[
|
</Form.Item>
|
||||||
// "md_responsibility_centers",
|
</LayoutFormRow>
|
||||||
// "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">
|
<LayoutFormRow header={<div>AR</div>} id="AR">
|
||||||
{/* <Form.Item
|
{/* <Form.Item
|
||||||
label={t("bodyshop.fields.responsibilitycenters.ar")}
|
label={t("bodyshop.fields.responsibilitycenters.ar")}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -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>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
|
|
||||||
export default function ShopEmployeeTeamMember({teamMember}) {
|
|
||||||
return (
|
|
||||||
<div>ShopEmployeeTeamMember</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
@@ -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>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
import { LockOutlined, UserOutlined } from "@ant-design/icons";
|
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 queryString from "query-string";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { Link, Redirect, useLocation } from "react-router-dom";
|
import { Link, Redirect, useLocation } from "react-router-dom";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import RomeLogo from "../../assets/RomeOnlineBlue.png";
|
import ImEXOnlineLogo from "../../assets/logo192.png";
|
||||||
import {
|
import {
|
||||||
emailSignInStart,
|
emailSignInStart,
|
||||||
sendPasswordReset,
|
sendPasswordReset,
|
||||||
@@ -53,7 +53,8 @@ export function SignInComponent({
|
|||||||
return (
|
return (
|
||||||
<div className="login-container">
|
<div className="login-container">
|
||||||
<div className="login-logo-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>
|
</div>
|
||||||
<Form onFinish={handleFinish} form={form} size="large">
|
<Form onFinish={handleFinish} form={form} size="large">
|
||||||
<Form.Item
|
<Form.Item
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
|
|||||||
import JobSearchSelect from "../job-search-select/job-search-select.component";
|
import JobSearchSelect from "../job-search-select/job-search-select.component";
|
||||||
import JobsDetailLaborContainer from "../jobs-detail-labor/jobs-detail-labor.container";
|
import JobsDetailLaborContainer from "../jobs-detail-labor/jobs-detail-labor.container";
|
||||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -17,11 +16,6 @@ const mapStateToProps = createStructuredSelector({
|
|||||||
|
|
||||||
export function TechClockInComponent({ form, bodyshop, technician }) {
|
export function TechClockInComponent({ form, bodyshop, technician }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { Enhanced_Payroll } = useTreatments(
|
|
||||||
["Enhanced_Payroll"],
|
|
||||||
{},
|
|
||||||
bodyshop.imexshopid
|
|
||||||
);
|
|
||||||
const emps = bodyshop.employees.filter((e) => e.id === technician.id)[0];
|
const emps = bodyshop.employees.filter((e) => e.id === technician.id)[0];
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@@ -59,7 +53,7 @@ export function TechClockInComponent({ form, bodyshop, technician }) {
|
|||||||
<Select.Option key={item.cost_center} value={item.cost_center}>
|
<Select.Option key={item.cost_center} value={item.cost_center}>
|
||||||
{item.cost_center === "timetickets.labels.shift"
|
{item.cost_center === "timetickets.labels.shift"
|
||||||
? t(item.cost_center)
|
? t(item.cost_center)
|
||||||
: bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber || Enhanced_Payroll.treatment === "on"
|
: bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber
|
||||||
? t(
|
? t(
|
||||||
`joblines.fields.lbr_types.${item.cost_center.toUpperCase()}`
|
`joblines.fields.lbr_types.${item.cost_center.toUpperCase()}`
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import {
|
|||||||
} from "../../redux/user/user.selectors";
|
} from "../../redux/user/user.selectors";
|
||||||
import TechJobPrintTickets from "../tech-job-print-tickets/tech-job-print-tickets.component";
|
import TechJobPrintTickets from "../tech-job-print-tickets/tech-job-print-tickets.component";
|
||||||
import TechClockInComponent from "./tech-job-clock-in-form.component";
|
import TechClockInComponent from "./tech-job-clock-in-form.component";
|
||||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
technician: selectTechnician,
|
technician: selectTechnician,
|
||||||
@@ -33,10 +32,9 @@ export function TechClockInContainer({
|
|||||||
bodyshop,
|
bodyshop,
|
||||||
currentUser,
|
currentUser,
|
||||||
}) {
|
}) {
|
||||||
const { Enhanced_Payroll } = useTreatments(
|
console.log(
|
||||||
["Enhanced_Payroll"],
|
"🚀 ~ file: tech-job-clock-in-form.container.jsx:30 ~ technician:",
|
||||||
{},
|
technician
|
||||||
bodyshop.imexshopid
|
|
||||||
);
|
);
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
@@ -70,7 +68,7 @@ export function TechClockInContainer({
|
|||||||
jobid: values.jobid,
|
jobid: values.jobid,
|
||||||
cost_center: values.cost_center,
|
cost_center: values.cost_center,
|
||||||
ciecacode:
|
ciecacode:
|
||||||
bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber || Enhanced_Payroll.treatment === 'on'
|
bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber
|
||||||
? values.cost_center
|
? values.cost_center
|
||||||
: Object.keys(
|
: Object.keys(
|
||||||
bodyshop.md_responsibility_centers.defaults.costs
|
bodyshop.md_responsibility_centers.defaults.costs
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
|
|||||||
import { CalculateAllocationsTotals } from "../labor-allocations-table/labor-allocations-table.utility";
|
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 TechJobClockoutDelete from "../tech-job-clock-out-delete/tech-job-clock-out-delete.component";
|
||||||
import { LaborAllocationContainer } from "../time-ticket-modal/time-ticket-modal.component";
|
import { LaborAllocationContainer } from "../time-ticket-modal/time-ticket-modal.component";
|
||||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -44,12 +43,6 @@ export function TechClockOffButton({
|
|||||||
const [updateTimeticket] = useMutation(UPDATE_TIME_TICKET);
|
const [updateTimeticket] = useMutation(UPDATE_TIME_TICKET);
|
||||||
const [updateJobStatus] = useMutation(UPDATE_JOB_STATUS);
|
const [updateJobStatus] = useMutation(UPDATE_JOB_STATUS);
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const { Enhanced_Payroll } = useTreatments(
|
|
||||||
["Enhanced_Payroll"],
|
|
||||||
{},
|
|
||||||
bodyshop.imexshopid
|
|
||||||
);
|
|
||||||
|
|
||||||
const { queryLoading, data: lineTicketData } = useQuery(
|
const { queryLoading, data: lineTicketData } = useQuery(
|
||||||
GET_LINE_TICKET_BY_PK,
|
GET_LINE_TICKET_BY_PK,
|
||||||
{
|
{
|
||||||
@@ -83,9 +76,7 @@ export function TechClockOffButton({
|
|||||||
?.rate,
|
?.rate,
|
||||||
flat_rate: emps && emps.flat_rate,
|
flat_rate: emps && emps.flat_rate,
|
||||||
ciecacode:
|
ciecacode:
|
||||||
bodyshop.cdk_dealerid ||
|
bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber
|
||||||
bodyshop.pbs_serialnumber ||
|
|
||||||
Enhanced_Payroll.treatment === "on"
|
|
||||||
? values.cost_center
|
? values.cost_center
|
||||||
: Object.keys(
|
: Object.keys(
|
||||||
bodyshop.md_responsibility_centers.defaults.costs
|
bodyshop.md_responsibility_centers.defaults.costs
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
import Icon, {
|
import Icon, { SearchOutlined, ScheduleOutlined } from "@ant-design/icons";
|
||||||
SearchOutlined,
|
|
||||||
ScheduleOutlined,
|
|
||||||
UserAddOutlined,
|
|
||||||
CarOutlined,
|
|
||||||
} from "@ant-design/icons";
|
|
||||||
import { Layout, Menu } from "antd";
|
import { Layout, Menu } from "antd";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@@ -16,38 +11,22 @@ import { createStructuredSelector } from "reselect";
|
|||||||
import { techLogout } from "../../redux/tech/tech.actions";
|
import { techLogout } from "../../redux/tech/tech.actions";
|
||||||
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||||
import { BsKanban } from "react-icons/bs";
|
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 { Sider } = Layout;
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
technician: selectTechnician,
|
technician: selectTechnician,
|
||||||
bodyshop: selectBodyshop,
|
|
||||||
});
|
});
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
techLogout: () => dispatch(techLogout()),
|
techLogout: () => dispatch(techLogout()),
|
||||||
setTimeTicketTaskContext: (context) =>
|
|
||||||
dispatch(setModalContext({ context: context, modal: "timeTicketTask" })),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export function TechSider({
|
export function TechSider({ technician, techLogout }) {
|
||||||
technician,
|
|
||||||
techLogout,
|
|
||||||
bodyshop,
|
|
||||||
setTimeTicketTaskContext,
|
|
||||||
}) {
|
|
||||||
const [collapsed, setCollapsed] = useState(true);
|
const [collapsed, setCollapsed] = useState(true);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const onCollapse = (collapsed) => {
|
const onCollapse = (collapsed) => {
|
||||||
setCollapsed(collapsed);
|
setCollapsed(collapsed);
|
||||||
};
|
};
|
||||||
const { Enhanced_Payroll } = useTreatments(
|
|
||||||
["Enhanced_Payroll"],
|
|
||||||
{},
|
|
||||||
bodyshop.imexshopid
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Sider
|
<Sider
|
||||||
@@ -72,38 +51,13 @@ export function TechSider({
|
|||||||
<Menu.Item key="2" disabled={!!!technician} icon={<SearchOutlined />}>
|
<Menu.Item key="2" disabled={!!!technician} icon={<SearchOutlined />}>
|
||||||
<Link to={`/tech/joblookup`}>{t("menus.tech.joblookup")}</Link>
|
<Link to={`/tech/joblookup`}>{t("menus.tech.joblookup")}</Link>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
{Enhanced_Payroll.treatment === "on" ? (
|
<Menu.Item
|
||||||
<>
|
key="3"
|
||||||
<Menu.Item
|
disabled={!!!technician}
|
||||||
key="TechAssignedProdJobs"
|
icon={<Icon component={FaBusinessTime} />}
|
||||||
disabled={!!!technician}
|
>
|
||||||
icon={<UserAddOutlined />}
|
<Link to={`/tech/jobclock`}>{t("menus.tech.jobclockin")}</Link>
|
||||||
>
|
</Menu.Item>
|
||||||
<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
|
<Menu.Item
|
||||||
key="4"
|
key="4"
|
||||||
disabled={!!!technician}
|
disabled={!!!technician}
|
||||||
@@ -114,15 +68,6 @@ export function TechSider({
|
|||||||
<Menu.Item key="5" disabled={!!!technician} icon={<ScheduleOutlined />}>
|
<Menu.Item key="5" disabled={!!!technician} icon={<ScheduleOutlined />}>
|
||||||
<Link to={`/tech/list`}>{t("menus.tech.productionlist")}</Link>
|
<Link to={`/tech/list`}>{t("menus.tech.productionlist")}</Link>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
<Menu.Item
|
|
||||||
key="dispatchedparts"
|
|
||||||
disabled={!!!technician}
|
|
||||||
icon={<CarOutlined />}
|
|
||||||
>
|
|
||||||
<Link to={`/tech/dispatchedparts`}>
|
|
||||||
{t("menus.tech.dispatchedparts")}
|
|
||||||
</Link>
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
key="6"
|
key="6"
|
||||||
disabled={!!!technician}
|
disabled={!!!technician}
|
||||||
@@ -130,7 +75,6 @@ export function TechSider({
|
|||||||
>
|
>
|
||||||
<Link to={`/tech/board`}> {t("menus.tech.productionboard")}</Link>
|
<Link to={`/tech/board`}> {t("menus.tech.productionboard")}</Link>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
|
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
key="7"
|
key="7"
|
||||||
disabled={!!!technician}
|
disabled={!!!technician}
|
||||||
|
|||||||
@@ -1,142 +0,0 @@
|
|||||||
import { DownOutlined } from "@ant-design/icons";
|
|
||||||
import {
|
|
||||||
Button,
|
|
||||||
Checkbox,
|
|
||||||
Col,
|
|
||||||
Form,
|
|
||||||
InputNumber,
|
|
||||||
Popover,
|
|
||||||
Radio,
|
|
||||||
Row,
|
|
||||||
Space,
|
|
||||||
Spin,
|
|
||||||
} from "antd";
|
|
||||||
import React, { useState } from "react";
|
|
||||||
import { GET_JOB_INFO_DRAW_CALCULATIONS } from "../../graphql/jobs-lines.queries";
|
|
||||||
import { useQuery } from "@apollo/client";
|
|
||||||
|
|
||||||
export default function TimeTicketCalculatorComponent({
|
|
||||||
setProductiveHours,
|
|
||||||
|
|
||||||
jobid,
|
|
||||||
}) {
|
|
||||||
const { loading, data: lineTicketData } = useQuery(GET_JOB_INFO_DRAW_CALCULATIONS, {
|
|
||||||
variables: { id: jobid },
|
|
||||||
skip: !jobid,
|
|
||||||
fetchPolicy: "network-only",
|
|
||||||
nextFetchPolicy: "network-only",
|
|
||||||
});
|
|
||||||
|
|
||||||
const [visible, setVisible] = useState(false);
|
|
||||||
const handleOpenChange = (flag) => setVisible(flag);
|
|
||||||
const handleFinish = ({ type, hourstype, percent }) => {
|
|
||||||
//setProductiveHours(values);
|
|
||||||
//setVisible(false);
|
|
||||||
const eligibleHours = Array.isArray(hourstype)
|
|
||||||
? lineTicketData.joblines.reduce(
|
|
||||||
(acc, val) =>
|
|
||||||
acc + (hourstype.includes(val.mod_lbr_ty) ? val.mod_lb_hrs : 0),
|
|
||||||
0
|
|
||||||
)
|
|
||||||
: lineTicketData.joblines.reduce(
|
|
||||||
(acc, val) =>
|
|
||||||
acc + (hourstype === val.mod_lbr_ty ? val.mod_lb_hrs : 0),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
if (type === "draw") {
|
|
||||||
setProductiveHours(eligibleHours * (percent / 100));
|
|
||||||
} else if (type === "cut") {
|
|
||||||
setProductiveHours(eligibleHours * (percent / 100));
|
|
||||||
console.log(
|
|
||||||
"Cut selected, rate set to: ",
|
|
||||||
lineTicketData.jobs_by_pk[`rate_${hourstype.toLowerCase()}`]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const popContent = (
|
|
||||||
<Spin spinning={loading}>
|
|
||||||
<Form onFinish={handleFinish}>
|
|
||||||
<Form.Item name="type">
|
|
||||||
<Radio.Group>
|
|
||||||
<Radio.Button value="draw">Draw</Radio.Button>
|
|
||||||
<Radio.Button value="cut">Cut of Sale</Radio.Button>
|
|
||||||
</Radio.Group>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item noStyle shouldUpdate>
|
|
||||||
{({ getFieldValue }) => (
|
|
||||||
<Form.Item name="hourstype">
|
|
||||||
{getFieldValue("type") === "draw" ? (
|
|
||||||
<Checkbox.Group>
|
|
||||||
<Row>
|
|
||||||
<Col span={8}>
|
|
||||||
<Checkbox value="LAB" style={{ lineHeight: "32px" }}>
|
|
||||||
Body
|
|
||||||
</Checkbox>
|
|
||||||
</Col>
|
|
||||||
<Col span={8}>
|
|
||||||
<Checkbox value="LAR" style={{ lineHeight: "32px" }}>
|
|
||||||
Refinish
|
|
||||||
</Checkbox>
|
|
||||||
</Col>
|
|
||||||
<Col span={8}>
|
|
||||||
<Checkbox value="LAM" style={{ lineHeight: "32px" }}>
|
|
||||||
Mechanical
|
|
||||||
</Checkbox>
|
|
||||||
</Col>
|
|
||||||
<Col span={8}>
|
|
||||||
<Checkbox value="LAF" style={{ lineHeight: "32px" }}>
|
|
||||||
Frame
|
|
||||||
</Checkbox>
|
|
||||||
</Col>
|
|
||||||
<Col span={8}>
|
|
||||||
<Checkbox value="LAG" style={{ lineHeight: "32px" }}>
|
|
||||||
Glass
|
|
||||||
</Checkbox>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
</Checkbox.Group>
|
|
||||||
) : (
|
|
||||||
<Radio.Group>
|
|
||||||
<Radio value="LAB">Body</Radio>
|
|
||||||
|
|
||||||
<Radio value="LAR">Refinish</Radio>
|
|
||||||
|
|
||||||
<Radio value="LAM">Mechanical</Radio>
|
|
||||||
|
|
||||||
<Radio value="LAF">Frame</Radio>
|
|
||||||
|
|
||||||
<Radio value="LAG">Glass</Radio>
|
|
||||||
</Radio.Group>
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item name="percent">
|
|
||||||
<InputNumber min={0} max={100} precision={1} addonAfter="%" />
|
|
||||||
</Form.Item>
|
|
||||||
<Button htmlType="submit">Calculate</Button>
|
|
||||||
</Form>
|
|
||||||
</Spin>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Popover
|
|
||||||
content={popContent}
|
|
||||||
trigger={["click"]}
|
|
||||||
open={visible}
|
|
||||||
onOpenChange={handleOpenChange}
|
|
||||||
placement="right"
|
|
||||||
destroyTooltipOnHide
|
|
||||||
>
|
|
||||||
<Button onClick={(e) => e.preventDefault()}>
|
|
||||||
<Space>
|
|
||||||
Draw Calculator
|
|
||||||
<DownOutlined />
|
|
||||||
</Space>
|
|
||||||
</Button>
|
|
||||||
</Popover>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,277 +0,0 @@
|
|||||||
import { useQuery } from "@apollo/client";
|
|
||||||
import {
|
|
||||||
Button,
|
|
||||||
Form,
|
|
||||||
InputNumber,
|
|
||||||
Modal,
|
|
||||||
Radio,
|
|
||||||
Select,
|
|
||||||
Space,
|
|
||||||
Table,
|
|
||||||
Typography,
|
|
||||||
} from "antd";
|
|
||||||
import Dinero from "dinero.js";
|
|
||||||
import React, { useState } from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { connect } from "react-redux";
|
|
||||||
import { createStructuredSelector } from "reselect";
|
|
||||||
import { GET_JOB_INFO_DRAW_CALCULATIONS } from "../../graphql/jobs-lines.queries";
|
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
|
||||||
import FormDatePicker from "../form-date-picker/form-date-picker.component";
|
|
||||||
import JobSearchSelectComponent from "../job-search-select/job-search-select.component";
|
|
||||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
|
||||||
bodyshop: selectBodyshop,
|
|
||||||
});
|
|
||||||
const mapDispatchToProps = (dispatch) => ({});
|
|
||||||
export default connect(
|
|
||||||
mapStateToProps,
|
|
||||||
mapDispatchToProps
|
|
||||||
)(TimeTicketListTeamPay);
|
|
||||||
|
|
||||||
export function TimeTicketListTeamPay({ bodyshop, context, actions }) {
|
|
||||||
//const { refetch } = actions;
|
|
||||||
const { jobId } = context;
|
|
||||||
const [visible, setVisible] = useState(false);
|
|
||||||
const [form] = Form.useForm();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const {
|
|
||||||
//loading,
|
|
||||||
data: lineTicketData,
|
|
||||||
} = useQuery(GET_JOB_INFO_DRAW_CALCULATIONS, {
|
|
||||||
variables: { id: jobId },
|
|
||||||
skip: !jobId,
|
|
||||||
fetchPolicy: "network-only",
|
|
||||||
nextFetchPolicy: "network-only",
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleOk = () => {
|
|
||||||
setVisible(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Modal
|
|
||||||
width={"80%"}
|
|
||||||
open={visible}
|
|
||||||
destroyOnClose
|
|
||||||
onOk={handleOk}
|
|
||||||
onCancel={() => setVisible(false)}
|
|
||||||
>
|
|
||||||
<Form layout="vertical" form={form} initialValues={{ jobid: jobId }}>
|
|
||||||
<LayoutFormRow grow noDivider>
|
|
||||||
<Form.Item shouldUpdate>
|
|
||||||
{() => (
|
|
||||||
<Form.Item
|
|
||||||
name="jobid"
|
|
||||||
label={t("timetickets.fields.ro_number")}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: !(
|
|
||||||
form.getFieldValue("cost_center") ===
|
|
||||||
"timetickets.labels.shift"
|
|
||||||
),
|
|
||||||
//message: t("general.validation.required"),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<JobSearchSelectComponent
|
|
||||||
convertedOnly={!bodyshop.tt_allow_post_to_invoiced}
|
|
||||||
notExported={!bodyshop.tt_allow_post_to_invoiced}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
label={t("timetickets.fields.date")}
|
|
||||||
name="date"
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
//message: t("general.validation.required"),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<FormDatePicker />
|
|
||||||
</Form.Item>
|
|
||||||
</LayoutFormRow>
|
|
||||||
|
|
||||||
<LayoutFormRow grow noDivider>
|
|
||||||
<Form.Item name="team" label="Team">
|
|
||||||
<Select
|
|
||||||
options={Teams.map((team) => ({
|
|
||||||
value: team.name,
|
|
||||||
label: team.name,
|
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item name="hourstype">
|
|
||||||
<Radio.Group>
|
|
||||||
<Radio value="LAB">Body</Radio>
|
|
||||||
<Radio value="LAR">Refinish</Radio>
|
|
||||||
<Radio value="LAM">Mechanical</Radio>
|
|
||||||
<Radio value="LAF">Frame</Radio>
|
|
||||||
<Radio value="LAG">Glass</Radio>
|
|
||||||
</Radio.Group>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item name="percent">
|
|
||||||
<InputNumber min={0} max={100} precision={1} addonAfter="%" />
|
|
||||||
</Form.Item>
|
|
||||||
</LayoutFormRow>
|
|
||||||
|
|
||||||
<Form.Item shouldUpdate noStyle>
|
|
||||||
{({ getFieldsValue }) => {
|
|
||||||
const formData = getFieldsValue();
|
|
||||||
|
|
||||||
let data = [];
|
|
||||||
let eligibleHours = 0;
|
|
||||||
const theTeam = Teams.find((team) => team.name === formData.team);
|
|
||||||
if (theTeam) {
|
|
||||||
eligibleHours =
|
|
||||||
lineTicketData.joblines.reduce(
|
|
||||||
(acc, val) =>
|
|
||||||
acc +
|
|
||||||
(formData.hourstype === val.mod_lbr_ty
|
|
||||||
? val.mod_lb_hrs
|
|
||||||
: 0),
|
|
||||||
0
|
|
||||||
) * (formData.percent / 100 || 0);
|
|
||||||
|
|
||||||
data = theTeam.employees.map((e) => {
|
|
||||||
return {
|
|
||||||
employeeid: e.employeeid,
|
|
||||||
percentage: e.percentage,
|
|
||||||
rate: e.rates[formData.hourstype],
|
|
||||||
cost_center:
|
|
||||||
bodyshop.md_responsibility_centers.defaults.costs[
|
|
||||||
formData.hourstype
|
|
||||||
],
|
|
||||||
productivehrs:
|
|
||||||
Math.round(eligibleHours * 100 * (e.percentage / 100)) /
|
|
||||||
100,
|
|
||||||
pay: Dinero({
|
|
||||||
amount: Math.round(
|
|
||||||
(e.rates[formData.hourstype] || 0) * 100
|
|
||||||
),
|
|
||||||
})
|
|
||||||
.multiply(
|
|
||||||
Math.round(eligibleHours * 100 * (e.percentage / 100)) /
|
|
||||||
100
|
|
||||||
)
|
|
||||||
.toFormat("$0.00"),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Table
|
|
||||||
dataSource={data}
|
|
||||||
rowKey={"employeeid"}
|
|
||||||
title={() => (
|
|
||||||
<Space>
|
|
||||||
<Typography.Title level={4}>
|
|
||||||
Tickets to be Created
|
|
||||||
</Typography.Title>
|
|
||||||
<span>{`(${eligibleHours} hours to split)`}</span>
|
|
||||||
</Space>
|
|
||||||
)}
|
|
||||||
columns={[
|
|
||||||
{
|
|
||||||
title: t("timetickets.fields.employee"),
|
|
||||||
dataIndex: "employee",
|
|
||||||
key: "employee",
|
|
||||||
render: (text, record) => {
|
|
||||||
const emp = bodyshop.employees.find(
|
|
||||||
(e) => e.id === record.employeeid
|
|
||||||
);
|
|
||||||
return `${emp?.first_name} ${emp?.last_name}`;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t("timetickets.fields.cost_center"),
|
|
||||||
dataIndex: "cost_center",
|
|
||||||
key: "cost_center",
|
|
||||||
|
|
||||||
render: (text, record) =>
|
|
||||||
record.cost_center === "timetickets.labels.shift"
|
|
||||||
? t(record.cost_center)
|
|
||||||
: record.cost_center,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t("timetickets.fields.productivehrs"),
|
|
||||||
dataIndex: "productivehrs",
|
|
||||||
key: "productivehrs",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Percentage",
|
|
||||||
dataIndex: "percentage",
|
|
||||||
key: "percentage",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Rate",
|
|
||||||
dataIndex: "rate",
|
|
||||||
key: "rate",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Pay",
|
|
||||||
dataIndex: "pay",
|
|
||||||
key: "pay",
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</Form.Item>
|
|
||||||
</Form>
|
|
||||||
</Modal>
|
|
||||||
<Button onClick={() => setVisible(true)}>Assign Team Pay </Button>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const Teams = [
|
|
||||||
{
|
|
||||||
name: "Team A",
|
|
||||||
employees: [
|
|
||||||
{
|
|
||||||
employeeid: "9f1bdc23-8dc2-4b6a-8ca1-5f83a6fdcc22",
|
|
||||||
percentage: 50,
|
|
||||||
rates: {
|
|
||||||
LAB: 10,
|
|
||||||
LAR: 15,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
employeeid: "201db66c-96c7-41ec-bed4-76842ba93087",
|
|
||||||
percentage: 50,
|
|
||||||
rates: {
|
|
||||||
LAB: 20,
|
|
||||||
LAR: 25,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Team B",
|
|
||||||
employees: [
|
|
||||||
{
|
|
||||||
employeeid: "9f1bdc23-8dc2-4b6a-8ca1-5f83a6fdcc22",
|
|
||||||
percentage: 75,
|
|
||||||
rates: {
|
|
||||||
LAB: 100,
|
|
||||||
LAR: 150,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
employeeid: "201db66c-96c7-41ec-bed4-76842ba93087",
|
|
||||||
percentage: 25,
|
|
||||||
rates: {
|
|
||||||
LAB: 200,
|
|
||||||
LAR: 250,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
import { EditFilled, SyncOutlined } from "@ant-design/icons";
|
import { EditFilled } from "@ant-design/icons";
|
||||||
import { Button, Card, Checkbox, Space, Table } from "antd";
|
import { Card, Space, Table } from "antd";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import React, { useMemo, useState } from "react";
|
import React, { useMemo, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
|
||||||
import {
|
import {
|
||||||
selectAuthLevel,
|
selectAuthLevel,
|
||||||
selectBodyshop,
|
selectBodyshop,
|
||||||
@@ -19,22 +18,18 @@ import RbacWrapper, {
|
|||||||
HasRbacAccess,
|
HasRbacAccess,
|
||||||
} from "../rbac-wrapper/rbac-wrapper.component";
|
} from "../rbac-wrapper/rbac-wrapper.component";
|
||||||
import TimeTicketEnterButton from "../time-ticket-enter-button/time-ticket-enter-button.component";
|
import TimeTicketEnterButton from "../time-ticket-enter-button/time-ticket-enter-button.component";
|
||||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
authLevel: selectAuthLevel,
|
authLevel: selectAuthLevel,
|
||||||
currentUser: selectCurrentUser,
|
currentUser: selectCurrentUser,
|
||||||
});
|
});
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
setTimeTicketTaskContext: (context) =>
|
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||||
dispatch(setModalContext({ context: context, modal: "timeTicketTask" })),
|
|
||||||
});
|
});
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(TimeTicketList);
|
export default connect(mapStateToProps, mapDispatchToProps)(TimeTicketList);
|
||||||
|
|
||||||
export function TimeTicketList({
|
export function TimeTicketList({
|
||||||
bodyshop,
|
bodyshop,
|
||||||
setTimeTicketTaskContext,
|
|
||||||
authLevel,
|
authLevel,
|
||||||
currentUser,
|
currentUser,
|
||||||
disabled,
|
disabled,
|
||||||
@@ -51,11 +46,7 @@ export function TimeTicketList({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { Enhanced_Payroll } = useTreatments(
|
|
||||||
["Enhanced_Payroll"],
|
|
||||||
{},
|
|
||||||
bodyshop.imexshopid
|
|
||||||
);
|
|
||||||
const totals = useMemo(() => {
|
const totals = useMemo(() => {
|
||||||
if (timetickets)
|
if (timetickets)
|
||||||
return timetickets.reduce(
|
return timetickets.reduce(
|
||||||
@@ -70,14 +61,6 @@ export function TimeTicketList({
|
|||||||
}, [timetickets]);
|
}, [timetickets]);
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
|
||||||
title: t("timetickets.fields.committed"),
|
|
||||||
dataIndex: "committed_at",
|
|
||||||
key: "committed_at",
|
|
||||||
render: (text, record) => (
|
|
||||||
<Checkbox disabled checked={record.committed_at} />
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: t("timetickets.fields.date"),
|
title: t("timetickets.fields.date"),
|
||||||
dataIndex: "date",
|
dataIndex: "date",
|
||||||
@@ -135,26 +118,21 @@ export function TimeTicketList({
|
|||||||
}) || [],
|
}) || [],
|
||||||
onFilter: (value, record) => value.includes(record.cost_center),
|
onFilter: (value, record) => value.includes(record.cost_center),
|
||||||
},
|
},
|
||||||
...(jobId
|
{
|
||||||
? []
|
title: t("jobs.fields.ro_number"),
|
||||||
: [
|
dataIndex: "ro_number",
|
||||||
{
|
key: "ro_number",
|
||||||
title: t("jobs.fields.ro_number"),
|
sorter: (a, b) =>
|
||||||
dataIndex: "ro_number",
|
alphaSort(a.job && a.job.ro_number, b.job && b.job.ro_number),
|
||||||
key: "ro_number",
|
sortOrder:
|
||||||
sorter: (a, b) =>
|
state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
|
||||||
alphaSort(a.job && a.job.ro_number, b.job && b.job.ro_number),
|
render: (text, record) =>
|
||||||
sortOrder:
|
record.job && (
|
||||||
state.sortedInfo.columnKey === "ro_number" &&
|
<Link to={"/manage/jobs/" + record.job.id}>
|
||||||
state.sortedInfo.order,
|
{record.job.ro_number || "N/A"}
|
||||||
render: (text, record) =>
|
</Link>
|
||||||
record.job && (
|
),
|
||||||
<Link to={"/manage/jobs/" + record.job.id}>
|
},
|
||||||
{record.job.ro_number || "N/A"}
|
|
||||||
</Link>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
]),
|
|
||||||
{
|
{
|
||||||
title: t("timetickets.fields.productivehrs"),
|
title: t("timetickets.fields.productivehrs"),
|
||||||
dataIndex: "productivehrs",
|
dataIndex: "productivehrs",
|
||||||
@@ -164,20 +142,14 @@ export function TimeTicketList({
|
|||||||
state.sortedInfo.columnKey === "productivehrs" &&
|
state.sortedInfo.columnKey === "productivehrs" &&
|
||||||
state.sortedInfo.order,
|
state.sortedInfo.order,
|
||||||
},
|
},
|
||||||
...(Enhanced_Payroll.treatment === "on"
|
{
|
||||||
? []
|
title: t("timetickets.fields.actualhrs"),
|
||||||
: [
|
dataIndex: "actualhrs",
|
||||||
{
|
key: "actualhrs",
|
||||||
title: t("timetickets.fields.actualhrs"),
|
sorter: (a, b) => a.actualhrs - b.actualhrs,
|
||||||
dataIndex: "actualhrs",
|
sortOrder:
|
||||||
key: "actualhrs",
|
state.sortedInfo.columnKey === "actualhrs" && state.sortedInfo.order,
|
||||||
sorter: (a, b) => a.actualhrs - b.actualhrs,
|
},
|
||||||
sortOrder:
|
|
||||||
state.sortedInfo.columnKey === "actualhrs" &&
|
|
||||||
state.sortedInfo.order,
|
|
||||||
},
|
|
||||||
]),
|
|
||||||
|
|
||||||
{
|
{
|
||||||
title: t("timetickets.fields.memo"),
|
title: t("timetickets.fields.memo"),
|
||||||
dataIndex: "memo",
|
dataIndex: "memo",
|
||||||
@@ -188,59 +160,42 @@ export function TimeTicketList({
|
|||||||
render: (text, record) =>
|
render: (text, record) =>
|
||||||
record.clockon || record.clockoff ? t(record.memo) : record.memo,
|
record.clockon || record.clockoff ? t(record.memo) : record.memo,
|
||||||
},
|
},
|
||||||
...(Enhanced_Payroll.treatment === "on"
|
{
|
||||||
? [
|
title: t("timetickets.fields.clockon"),
|
||||||
{
|
dataIndex: "clockon",
|
||||||
title: t("timetickets.fields.task_name"),
|
key: "clockon",
|
||||||
dataIndex: "task_name",
|
|
||||||
key: "task_name",
|
|
||||||
sorter: (a, b) => alphaSort(a.task_name, b.task_name),
|
|
||||||
sortOrder:
|
|
||||||
state.sortedInfo.columnKey === "task_name" &&
|
|
||||||
state.sortedInfo.order,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: []),
|
|
||||||
...(Enhanced_Payroll.treatment === "on"
|
|
||||||
? []
|
|
||||||
: [
|
|
||||||
{
|
|
||||||
title: t("timetickets.fields.clockon"),
|
|
||||||
dataIndex: "clockon",
|
|
||||||
key: "clockon",
|
|
||||||
|
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<DateTimeFormatter>{record.clockon}</DateTimeFormatter>
|
<DateTimeFormatter>{record.clockon}</DateTimeFormatter>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("timetickets.fields.clockoff"),
|
title: t("timetickets.fields.clockoff"),
|
||||||
dataIndex: "clockoff",
|
dataIndex: "clockoff",
|
||||||
key: "clockoff",
|
key: "clockoff",
|
||||||
|
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<DateTimeFormatter>{record.clockoff}</DateTimeFormatter>
|
<DateTimeFormatter>{record.clockoff}</DateTimeFormatter>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("timetickets.fields.clockhours"),
|
title: t("timetickets.fields.clockhours"),
|
||||||
dataIndex: "clockhours",
|
dataIndex: "clockhours",
|
||||||
key: "clockhours",
|
key: "clockhours",
|
||||||
render: (text, record) => {
|
render: (text, record) => {
|
||||||
if (record.clockoff && record.clockon)
|
if (record.clockoff && record.clockon)
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{moment(record.clockoff)
|
{moment(record.clockoff)
|
||||||
.diff(moment(record.clockon), "hours", true)
|
.diff(moment(record.clockon), "hours", true)
|
||||||
.toFixed(2)}
|
.toFixed(2)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
else {
|
else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]),
|
|
||||||
{
|
{
|
||||||
title: t("timetickets.fields.created_by"),
|
title: t("timetickets.fields.created_by"),
|
||||||
dataIndex: "created_by",
|
dataIndex: "created_by",
|
||||||
@@ -250,15 +205,6 @@ export function TimeTicketList({
|
|||||||
state.sortedInfo.columnKey === "created_by" && state.sortedInfo.order,
|
state.sortedInfo.columnKey === "created_by" && state.sortedInfo.order,
|
||||||
render: (text, record) => record.created_by,
|
render: (text, record) => record.created_by,
|
||||||
},
|
},
|
||||||
// {
|
|
||||||
// title: "Pay",
|
|
||||||
// dataIndex: "pay",
|
|
||||||
// key: "pay",
|
|
||||||
// render: (text, record) =>
|
|
||||||
// Dinero({ amount: Math.round(record.rate * 100) })
|
|
||||||
// .multiply(record.flat_rate ? record.productivehrs : record.actualhrs)
|
|
||||||
// .toFormat("$0.00"),
|
|
||||||
// },
|
|
||||||
{
|
{
|
||||||
title: t("general.labels.actions"),
|
title: t("general.labels.actions"),
|
||||||
dataIndex: "actions",
|
dataIndex: "actions",
|
||||||
@@ -288,11 +234,6 @@ export function TimeTicketList({
|
|||||||
timeticket: record,
|
timeticket: record,
|
||||||
}}
|
}}
|
||||||
disabled={
|
disabled={
|
||||||
HasRbacAccess({
|
|
||||||
bodyshop,
|
|
||||||
authLevel: authLevel,
|
|
||||||
action: "timetickets:editcommitted",
|
|
||||||
}) &&
|
|
||||||
HasRbacAccess({
|
HasRbacAccess({
|
||||||
bodyshop,
|
bodyshop,
|
||||||
authLevel: authLevel,
|
authLevel: authLevel,
|
||||||
@@ -320,19 +261,6 @@ export function TimeTicketList({
|
|||||||
title={t("timetickets.labels.timetickets")}
|
title={t("timetickets.labels.timetickets")}
|
||||||
extra={
|
extra={
|
||||||
<Space wrap>
|
<Space wrap>
|
||||||
{jobId && bodyshop.md_tasks_presets.enable_tasks && (
|
|
||||||
<Button
|
|
||||||
disabled={disabled}
|
|
||||||
onClick={() => {
|
|
||||||
setTimeTicketTaskContext({
|
|
||||||
actions: { refetch: refetch },
|
|
||||||
context: { jobid: jobId },
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t("timetickets.actions.claimtasks")}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
{jobId &&
|
{jobId &&
|
||||||
(techConsole ? null : (
|
(techConsole ? null : (
|
||||||
<TimeTicketEnterButton
|
<TimeTicketEnterButton
|
||||||
@@ -349,13 +277,6 @@ export function TimeTicketList({
|
|||||||
</TimeTicketEnterButton>
|
</TimeTicketEnterButton>
|
||||||
))}
|
))}
|
||||||
{extra}
|
{extra}
|
||||||
<Button
|
|
||||||
onClick={async () => {
|
|
||||||
refetch();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<SyncOutlined />
|
|
||||||
</Button>
|
|
||||||
</Space>
|
</Space>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -19,8 +19,6 @@ import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
|||||||
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
||||||
import { HasRbacAccess } from "../rbac-wrapper/rbac-wrapper.component";
|
import { HasRbacAccess } from "../rbac-wrapper/rbac-wrapper.component";
|
||||||
import TimeTicketList from "../time-ticket-list/time-ticket-list.component";
|
import TimeTicketList from "../time-ticket-list/time-ticket-list.component";
|
||||||
import TimeTicketCalculatorComponent from "../time-ticket-calculator/time-ticket-calculator.component";
|
|
||||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -38,15 +36,9 @@ export function TimeTicketModalComponent({
|
|||||||
authLevel,
|
authLevel,
|
||||||
employeeAutoCompleteOptions,
|
employeeAutoCompleteOptions,
|
||||||
isEdit,
|
isEdit,
|
||||||
disabled,
|
|
||||||
employeeSelectDisabled,
|
employeeSelectDisabled,
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { Enhanced_Payroll } = useTreatments(
|
|
||||||
["Enhanced_Payroll"],
|
|
||||||
{},
|
|
||||||
bodyshop.imexshopid
|
|
||||||
);
|
|
||||||
const [loadLineTicketData, { called, loading, data: lineTicketData }] =
|
const [loadLineTicketData, { called, loading, data: lineTicketData }] =
|
||||||
useLazyQuery(GET_LINE_TICKET_BY_PK, {
|
useLazyQuery(GET_LINE_TICKET_BY_PK, {
|
||||||
fetchPolicy: "network-only",
|
fetchPolicy: "network-only",
|
||||||
@@ -57,14 +49,14 @@ export function TimeTicketModalComponent({
|
|||||||
<Select
|
<Select
|
||||||
value={value === "timetickets.labels.shift" ? t(value) : value}
|
value={value === "timetickets.labels.shift" ? t(value) : value}
|
||||||
{...props}
|
{...props}
|
||||||
disabled={value === "timetickets.labels.shift" || disabled}
|
disabled={value === "timetickets.labels.shift"}
|
||||||
>
|
>
|
||||||
{emps &&
|
{emps &&
|
||||||
emps.rates.map((item) => (
|
emps.rates.map((item) => (
|
||||||
<Select.Option key={item.cost_center} value={item.cost_center}>
|
<Select.Option key={item.cost_center} value={item.cost_center}>
|
||||||
{item.cost_center === "timetickets.labels.shift"
|
{item.cost_center === "timetickets.labels.shift"
|
||||||
? t(item.cost_center)
|
? t(item.cost_center)
|
||||||
: bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber || Enhanced_Payroll.treatment === 'on'
|
: bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber
|
||||||
? t(
|
? t(
|
||||||
`joblines.fields.lbr_types.${item.cost_center.toUpperCase()}`
|
`joblines.fields.lbr_types.${item.cost_center.toUpperCase()}`
|
||||||
)
|
)
|
||||||
@@ -80,7 +72,7 @@ export function TimeTicketModalComponent({
|
|||||||
<Input
|
<Input
|
||||||
value={value?.startsWith("timetickets.") ? t(value) : value}
|
value={value?.startsWith("timetickets.") ? t(value) : value}
|
||||||
{...props}
|
{...props}
|
||||||
disabled={value?.startsWith("timetickets.") || disabled}
|
disabled={value?.startsWith("timetickets.")}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -134,7 +126,7 @@ export function TimeTicketModalComponent({
|
|||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<EmployeeSearchSelect
|
<EmployeeSearchSelect
|
||||||
disabled={employeeSelectDisabled || disabled}
|
disabled={employeeSelectDisabled}
|
||||||
options={employeeAutoCompleteOptions}
|
options={employeeAutoCompleteOptions}
|
||||||
onSelect={(value) => {
|
onSelect={(value) => {
|
||||||
const emps =
|
const emps =
|
||||||
@@ -186,73 +178,65 @@ export function TimeTicketModalComponent({
|
|||||||
<LayoutFormRow>
|
<LayoutFormRow>
|
||||||
<Form.Item shouldUpdate>
|
<Form.Item shouldUpdate>
|
||||||
{() => (
|
{() => (
|
||||||
<>
|
<Form.Item
|
||||||
<Form.Item
|
label={t("timetickets.fields.productivehrs")}
|
||||||
label={t("timetickets.fields.productivehrs")}
|
name="productivehrs"
|
||||||
name="productivehrs"
|
rules={[
|
||||||
rules={[
|
({ getFieldValue }) => ({
|
||||||
({ getFieldValue }) => ({
|
validator(rule, value) {
|
||||||
validator(rule, value) {
|
if (!bodyshop.tt_enforce_hours_for_tech_console) {
|
||||||
if (!bodyshop.tt_enforce_hours_for_tech_console) {
|
return Promise.resolve();
|
||||||
return Promise.resolve();
|
}
|
||||||
}
|
if (
|
||||||
if (
|
!value ||
|
||||||
!value ||
|
getFieldValue("cost_center") === null ||
|
||||||
getFieldValue("cost_center") === null ||
|
!lineTicketData
|
||||||
!lineTicketData
|
)
|
||||||
)
|
return Promise.resolve();
|
||||||
return Promise.resolve();
|
|
||||||
|
|
||||||
//Check the cost center,
|
//Check the cost center,
|
||||||
const totals = CalculateAllocationsTotals(
|
const totals = CalculateAllocationsTotals(
|
||||||
bodyshop,
|
bodyshop,
|
||||||
lineTicketData.joblines,
|
lineTicketData.joblines,
|
||||||
lineTicketData.timetickets,
|
lineTicketData.timetickets,
|
||||||
lineTicketData.jobs_by_pk.lbr_adjustments
|
lineTicketData.jobs_by_pk.lbr_adjustments
|
||||||
|
);
|
||||||
|
|
||||||
|
const fieldTypeToCheck =
|
||||||
|
bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber
|
||||||
|
? "mod_lbr_ty"
|
||||||
|
: "cost_center";
|
||||||
|
|
||||||
|
const costCenterDiff =
|
||||||
|
Math.round(
|
||||||
|
totals.find(
|
||||||
|
(total) =>
|
||||||
|
total[fieldTypeToCheck] ===
|
||||||
|
getFieldValue("cost_center")
|
||||||
|
)?.difference * 10
|
||||||
|
) / 10;
|
||||||
|
|
||||||
|
if (value > costCenterDiff)
|
||||||
|
return Promise.reject(
|
||||||
|
t(
|
||||||
|
"timetickets.validation.hoursenteredmorethanavailable"
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
else {
|
||||||
const fieldTypeToCheck =
|
return Promise.resolve();
|
||||||
bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber
|
}
|
||||||
? "mod_lbr_ty"
|
|
||||||
: "cost_center";
|
|
||||||
|
|
||||||
const costCenterDiff =
|
|
||||||
Math.round(
|
|
||||||
totals.find(
|
|
||||||
(total) =>
|
|
||||||
total[fieldTypeToCheck] ===
|
|
||||||
getFieldValue("cost_center")
|
|
||||||
)?.difference * 10
|
|
||||||
) / 10;
|
|
||||||
|
|
||||||
if (value > costCenterDiff)
|
|
||||||
return Promise.reject(
|
|
||||||
t(
|
|
||||||
"timetickets.validation.hoursenteredmorethanavailable"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
else {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
required:
|
|
||||||
form.getFieldValue("cost_center") !==
|
|
||||||
"timetickets.labels.shift",
|
|
||||||
//message: t("general.validation.required"),
|
|
||||||
},
|
},
|
||||||
]}
|
}),
|
||||||
>
|
{
|
||||||
<InputNumber precision={1} />
|
required:
|
||||||
</Form.Item>
|
form.getFieldValue("cost_center") !==
|
||||||
<TimeTicketCalculatorComponent
|
"timetickets.labels.shift",
|
||||||
jobid={form.getFieldValue("jobid")}
|
//message: t("general.validation.required"),
|
||||||
setProductiveHours={(productivehrs) =>
|
},
|
||||||
form.setFieldsValue({ productivehrs })
|
]}
|
||||||
}
|
>
|
||||||
/>
|
<InputNumber precision={1} />
|
||||||
</>
|
</Form.Item>
|
||||||
)}
|
)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
@@ -286,7 +270,6 @@ export function TimeTicketModalComponent({
|
|||||||
<FormDateTimePicker
|
<FormDateTimePicker
|
||||||
minuteStep={5}
|
minuteStep={5}
|
||||||
disabled={
|
disabled={
|
||||||
disabled ||
|
|
||||||
!HasRbacAccess({
|
!HasRbacAccess({
|
||||||
bodyshop,
|
bodyshop,
|
||||||
authLevel,
|
authLevel,
|
||||||
@@ -325,7 +308,6 @@ export function TimeTicketModalComponent({
|
|||||||
<FormDateTimePicker
|
<FormDateTimePicker
|
||||||
minuteStep={5}
|
minuteStep={5}
|
||||||
disabled={
|
disabled={
|
||||||
disabled ||
|
|
||||||
!HasRbacAccess({
|
!HasRbacAccess({
|
||||||
bodyshop,
|
bodyshop,
|
||||||
authLevel,
|
authLevel,
|
||||||
@@ -381,12 +363,7 @@ export function TimeTicketModalComponent({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function LaborAllocationContainer({
|
export function LaborAllocationContainer({ jobid, loading, lineTicketData }) {
|
||||||
jobid,
|
|
||||||
loading,
|
|
||||||
lineTicketData,
|
|
||||||
hideTimeTickets = false,
|
|
||||||
}) {
|
|
||||||
if (loading) return <LoadingSkeleton />;
|
if (loading) return <LoadingSkeleton />;
|
||||||
if (!lineTicketData) return null;
|
if (!lineTicketData) return null;
|
||||||
return (
|
return (
|
||||||
@@ -397,13 +374,12 @@ export function LaborAllocationContainer({
|
|||||||
timetickets={lineTicketData.timetickets}
|
timetickets={lineTicketData.timetickets}
|
||||||
adjustments={lineTicketData.jobs_by_pk.lbr_adjustments}
|
adjustments={lineTicketData.jobs_by_pk.lbr_adjustments}
|
||||||
/>
|
/>
|
||||||
{!hideTimeTickets && (
|
|
||||||
<TimeTicketList
|
<TimeTicketList
|
||||||
loading={loading}
|
loading={loading}
|
||||||
timetickets={lineTicketData.timetickets}
|
timetickets={lineTicketData.timetickets}
|
||||||
techConsole
|
techConsole
|
||||||
/>
|
/>
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ import { toggleModalVisible } from "../../redux/modals/modals.actions";
|
|||||||
import { selectTimeTicket } from "../../redux/modals/modals.selectors";
|
import { selectTimeTicket } from "../../redux/modals/modals.selectors";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import TimeTicketModalComponent from "./time-ticket-modal.component";
|
import TimeTicketModalComponent from "./time-ticket-modal.component";
|
||||||
import TimeTicketsCommitToggleComponent from "../time-tickets-commit-toggle/time-tickets-commit-toggle.component";
|
|
||||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
timeTicketModal: selectTimeTicket,
|
timeTicketModal: selectTimeTicket,
|
||||||
@@ -36,11 +34,7 @@ export function TimeTicketModalContainer({
|
|||||||
const [enterAgain, setEnterAgain] = useState(false);
|
const [enterAgain, setEnterAgain] = useState(false);
|
||||||
const [insertTicket] = useMutation(INSERT_NEW_TIME_TICKET);
|
const [insertTicket] = useMutation(INSERT_NEW_TIME_TICKET);
|
||||||
const [updateTicket] = useMutation(UPDATE_TIME_TICKET);
|
const [updateTicket] = useMutation(UPDATE_TIME_TICKET);
|
||||||
const { Enhanced_Payroll } = useTreatments(
|
|
||||||
["Enhanced_Payroll"],
|
|
||||||
{},
|
|
||||||
bodyshop.imexshopid
|
|
||||||
);
|
|
||||||
const { data: EmployeeAutoCompleteData } = useQuery(QUERY_ACTIVE_EMPLOYEES, {
|
const { data: EmployeeAutoCompleteData } = useQuery(QUERY_ACTIVE_EMPLOYEES, {
|
||||||
skip: !timeTicketModal.visible,
|
skip: !timeTicketModal.visible,
|
||||||
fetchPolicy: "network-only",
|
fetchPolicy: "network-only",
|
||||||
@@ -153,7 +147,7 @@ export function TimeTicketModalContainer({
|
|||||||
if (!!changedFields.cost_center && !!EmployeeAutoCompleteData) {
|
if (!!changedFields.cost_center && !!EmployeeAutoCompleteData) {
|
||||||
form.setFieldsValue({
|
form.setFieldsValue({
|
||||||
ciecacode:
|
ciecacode:
|
||||||
bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber || Enhanced_Payroll.treatment === 'on'
|
bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber
|
||||||
? changedFields.cost_center
|
? changedFields.cost_center
|
||||||
: Object.keys(
|
: Object.keys(
|
||||||
bodyshop.md_responsibility_centers.defaults.costs
|
bodyshop.md_responsibility_centers.defaults.costs
|
||||||
@@ -181,11 +175,7 @@ export function TimeTicketModalContainer({
|
|||||||
footer={
|
footer={
|
||||||
<span>
|
<span>
|
||||||
<Button onClick={handleCancel}>{t("general.actions.cancel")}</Button>
|
<Button onClick={handleCancel}>{t("general.actions.cancel")}</Button>
|
||||||
<Button
|
<Button loading={loading} onClick={() => form.submit()}>
|
||||||
loading={loading}
|
|
||||||
disabled={timeTicketModal.context?.timeticket?.committed_at}
|
|
||||||
onClick={() => form.submit()}
|
|
||||||
>
|
|
||||||
{t("general.actions.save")}
|
{t("general.actions.save")}
|
||||||
</Button>
|
</Button>
|
||||||
{timeTicketModal.context && timeTicketModal.context.id ? null : (
|
{timeTicketModal.context && timeTicketModal.context.id ? null : (
|
||||||
@@ -209,7 +199,6 @@ export function TimeTicketModalContainer({
|
|||||||
autoComplete={"off"}
|
autoComplete={"off"}
|
||||||
form={form}
|
form={form}
|
||||||
onFinishFailed={() => setEnterAgain(false)}
|
onFinishFailed={() => setEnterAgain(false)}
|
||||||
disabled={timeTicketModal.context?.timeticket?.committed_at}
|
|
||||||
initialValues={
|
initialValues={
|
||||||
timeTicketModal.context.timeticket
|
timeTicketModal.context.timeticket
|
||||||
? {
|
? {
|
||||||
@@ -230,9 +219,6 @@ export function TimeTicketModalContainer({
|
|||||||
<PageHeader
|
<PageHeader
|
||||||
extra={
|
extra={
|
||||||
<Space>
|
<Space>
|
||||||
<TimeTicketsCommitToggleComponent
|
|
||||||
timeticket={timeTicketModal.context?.timeticket}
|
|
||||||
/>
|
|
||||||
<Button onClick={handleCancel}>
|
<Button onClick={handleCancel}>
|
||||||
{t("general.actions.cancel")}
|
{t("general.actions.cancel")}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -256,16 +242,14 @@ export function TimeTicketModalContainer({
|
|||||||
<TimeTicketModalComponent
|
<TimeTicketModalComponent
|
||||||
isEdit={timeTicketModal.context.id}
|
isEdit={timeTicketModal.context.id}
|
||||||
form={form}
|
form={form}
|
||||||
disabled={timeTicketModal.context?.timeticket?.committed_at}
|
|
||||||
employeeAutoCompleteOptions={
|
employeeAutoCompleteOptions={
|
||||||
EmployeeAutoCompleteData && EmployeeAutoCompleteData.employees
|
EmployeeAutoCompleteData && EmployeeAutoCompleteData.employees
|
||||||
}
|
}
|
||||||
employeeSelectDisabled={
|
employeeSelectDisabled={
|
||||||
timeTicketModal.context?.timeticket?.committed_at ||
|
timeTicketModal.context?.timeticket?.employeeid &&
|
||||||
(timeTicketModal.context?.timeticket?.employeeid &&
|
|
||||||
!timeTicketModal.context.id
|
!timeTicketModal.context.id
|
||||||
? true
|
? true
|
||||||
: false)
|
: false
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Form>
|
</Form>
|
||||||
|
|||||||
@@ -1,197 +0,0 @@
|
|||||||
import {
|
|
||||||
Alert,
|
|
||||||
Col,
|
|
||||||
Form,
|
|
||||||
Radio,
|
|
||||||
Row,
|
|
||||||
Skeleton,
|
|
||||||
Space,
|
|
||||||
Spin,
|
|
||||||
Typography,
|
|
||||||
} 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";
|
|
||||||
import ReadOnlyFormItemComponent from "../form-items-formatted/read-only-form-item.component";
|
|
||||||
import JobSearchSelectComponent from "../job-search-select/job-search-select.component";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
|
||||||
//currentUser: selectCurrentUser
|
|
||||||
bodyshop: selectBodyshop,
|
|
||||||
});
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
|
||||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
|
||||||
});
|
|
||||||
export default connect(
|
|
||||||
mapStateToProps,
|
|
||||||
mapDispatchToProps
|
|
||||||
)(TimeTicketTaskModalComponent);
|
|
||||||
|
|
||||||
export function TimeTicketTaskModalComponent({
|
|
||||||
bodyshop,
|
|
||||||
form,
|
|
||||||
loading,
|
|
||||||
completedTasks,
|
|
||||||
unassignedHours,
|
|
||||||
}) {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Row gutter={[16, 16]}>
|
|
||||||
<Col xl={12} lg={24}>
|
|
||||||
<Form.Item
|
|
||||||
name="jobid"
|
|
||||||
label={t("timetickets.fields.ro_number")}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
//message: t("general.validation.required"),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<JobSearchSelectComponent convertedOnly={true} notExported={true} />
|
|
||||||
</Form.Item>
|
|
||||||
<Space wrap>
|
|
||||||
<Form.Item name="task" label={t("timetickets.labels.task")}>
|
|
||||||
{loading ? (
|
|
||||||
<Spin />
|
|
||||||
) : (
|
|
||||||
<Radio.Group
|
|
||||||
optionType="button"
|
|
||||||
options={bodyshop.md_tasks_presets.presets.map((preset) => ({
|
|
||||||
value: preset.name,
|
|
||||||
label: preset.name,
|
|
||||||
disabled: completedTasks
|
|
||||||
.map((task) => task.name)
|
|
||||||
.includes(preset.name),
|
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item dependencies={["task"]}>
|
|
||||||
{() => {
|
|
||||||
const { task } = form.getFieldsValue();
|
|
||||||
const theTaskPreset = bodyshop.md_tasks_presets?.presets?.find(
|
|
||||||
(tp) => tp.name === task
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!task) return null;
|
|
||||||
return (
|
|
||||||
<table className="task-tickets-table">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>{t("bodyshop.fields.md_tasks_presets.percent")}</td>
|
|
||||||
<td>{`${theTaskPreset.percent || 0}%`}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
{t("bodyshop.fields.md_tasks_presets.hourstype")}
|
|
||||||
</td>
|
|
||||||
<td>{theTaskPreset.hourstype.join(", ")}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
{t("bodyshop.fields.md_tasks_presets.nextstatus")}
|
|
||||||
</td>
|
|
||||||
<td>{theTaskPreset.nextstatus}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</Form.Item>
|
|
||||||
</Space>
|
|
||||||
</Col>
|
|
||||||
<Col xl={12} lg={24}>
|
|
||||||
{loading ? (
|
|
||||||
<Skeleton />
|
|
||||||
) : (
|
|
||||||
<Form.List name="timetickets">
|
|
||||||
{(fields, { add, remove, move }) => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Typography.Title level={4}>
|
|
||||||
{t("timetickets.labels.claimtaskpreview")}
|
|
||||||
</Typography.Title>
|
|
||||||
<table className="task-tickets-table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>{t("timetickets.fields.employee")}</th>
|
|
||||||
<th>{t("timetickets.fields.cost_center")}</th>
|
|
||||||
<th>{t("timetickets.fields.ciecacode")}</th>
|
|
||||||
<th>{t("timetickets.fields.productivehrs")}</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{fields.map((field, index) => (
|
|
||||||
<tr key={field.key}>
|
|
||||||
<td>
|
|
||||||
<Form.Item
|
|
||||||
key={`${index}employeeid`}
|
|
||||||
name={[field.name, "employeeid"]}
|
|
||||||
>
|
|
||||||
<ReadOnlyFormItemComponent type="employee" />
|
|
||||||
</Form.Item>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<Form.Item
|
|
||||||
key={`${index}cost_center`}
|
|
||||||
name={[field.name, "cost_center"]}
|
|
||||||
>
|
|
||||||
<ReadOnlyFormItemComponent />
|
|
||||||
</Form.Item>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<Form.Item
|
|
||||||
key={`${index}ciecacode`}
|
|
||||||
name={[field.name, "ciecacode"]}
|
|
||||||
>
|
|
||||||
<ReadOnlyFormItemComponent />
|
|
||||||
</Form.Item>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<Form.Item
|
|
||||||
key={`${index}productivehrs`}
|
|
||||||
name={[field.name, "productivehrs"]}
|
|
||||||
>
|
|
||||||
<ReadOnlyFormItemComponent />
|
|
||||||
</Form.Item>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<Alert
|
|
||||||
type="success"
|
|
||||||
message={t("timetickets.labels.payrollclaimedtasks")}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</Form.List>
|
|
||||||
)}
|
|
||||||
{unassignedHours > 0 && (
|
|
||||||
<Alert
|
|
||||||
type="error"
|
|
||||||
message={t("timetickets.validation.unassignedlines", {
|
|
||||||
unassignedHours: unassignedHours,
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
|
|
||||||
{bodyshop?.md_tasks_presets?.use_approvals && (
|
|
||||||
<Col xl={12} lg={24}>
|
|
||||||
<Alert
|
|
||||||
message={t("tt_approvals.labels.approval_queue_in_use")}
|
|
||||||
type="warning"
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,151 +0,0 @@
|
|||||||
import React, { useCallback, useEffect, useState } from "react";
|
|
||||||
|
|
||||||
import { Form, Modal, notification } from "antd";
|
|
||||||
import axios from "axios";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { connect } from "react-redux";
|
|
||||||
import { createStructuredSelector } from "reselect";
|
|
||||||
import { toggleModalVisible } from "../../redux/modals/modals.actions";
|
|
||||||
import { selectTimeTicketTasks } from "../../redux/modals/modals.selectors";
|
|
||||||
import {
|
|
||||||
selectBodyshop,
|
|
||||||
selectCurrentUser,
|
|
||||||
} from "../../redux/user/user.selectors";
|
|
||||||
import TimeTicketTaskModalComponent from "./time-ticket-task-modal.component";
|
|
||||||
import { useApolloClient } from "@apollo/client";
|
|
||||||
import { QUERY_COMPLETED_TASKS } from "../../graphql/jobs.queries";
|
|
||||||
import "./time-ticket-task-modal.styles.scss";
|
|
||||||
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
|
||||||
timeTicketTasksModal: selectTimeTicketTasks,
|
|
||||||
bodyshop: selectBodyshop,
|
|
||||||
currentUser: selectCurrentUser,
|
|
||||||
technician: selectTechnician,
|
|
||||||
});
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
|
||||||
toggleModalVisible: () => dispatch(toggleModalVisible("timeTicketTask")),
|
|
||||||
});
|
|
||||||
export default connect(
|
|
||||||
mapStateToProps,
|
|
||||||
mapDispatchToProps
|
|
||||||
)(TimeTickeTaskModalContainer);
|
|
||||||
|
|
||||||
export function TimeTickeTaskModalContainer({
|
|
||||||
bodyshop,
|
|
||||||
currentUser,
|
|
||||||
technician,
|
|
||||||
timeTicketTasksModal,
|
|
||||||
toggleModalVisible,
|
|
||||||
}) {
|
|
||||||
const [form] = Form.useForm();
|
|
||||||
const { context, visible, actions } = timeTicketTasksModal;
|
|
||||||
const [completedTasks, setCompletedTasks] = useState([]);
|
|
||||||
const [unassignedHours, setUnassignedHours] = useState(0);
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
const client = useApolloClient();
|
|
||||||
|
|
||||||
async function handleFinish(values) {
|
|
||||||
calculateTickets({ values, handleFinish: true });
|
|
||||||
}
|
|
||||||
const getCompletedTasks = useCallback(
|
|
||||||
async (jobid) => {
|
|
||||||
setLoading(true);
|
|
||||||
|
|
||||||
const { data } = await client.query({
|
|
||||||
query: QUERY_COMPLETED_TASKS,
|
|
||||||
variables: { jobid },
|
|
||||||
});
|
|
||||||
|
|
||||||
setCompletedTasks(data.jobs_by_pk.completed_tasks || []);
|
|
||||||
setLoading(false);
|
|
||||||
},
|
|
||||||
[client]
|
|
||||||
);
|
|
||||||
useEffect(() => {
|
|
||||||
if (visible) {
|
|
||||||
form.setFieldsValue({ ...context, task: null, timetickets: null });
|
|
||||||
if (context.jobid) {
|
|
||||||
getCompletedTasks(context.jobid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [context.jobid, visible, getCompletedTasks, form, context]);
|
|
||||||
|
|
||||||
async function handleValueChange(changedValues, allValues) {
|
|
||||||
if (changedValues.jobid) {
|
|
||||||
getCompletedTasks(changedValues.jobid);
|
|
||||||
}
|
|
||||||
if (allValues.jobid && allValues.task) {
|
|
||||||
calculateTickets({ values: allValues, handleFinish: false });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const calculateTickets = async ({ values, handleFinish }) => {
|
|
||||||
setLoading(true);
|
|
||||||
try {
|
|
||||||
const { data, ...response } = await axios.post("/payroll/claimtask", {
|
|
||||||
jobid: values.jobid,
|
|
||||||
task: values.task,
|
|
||||||
calculateOnly: !handleFinish,
|
|
||||||
employee: technician
|
|
||||||
? {
|
|
||||||
name: `${technician.first_name} ${technician.last_name}`.trim(),
|
|
||||||
employeeid: technician.id,
|
|
||||||
}
|
|
||||||
: { name: currentUser.displayName, email: currentUser.email },
|
|
||||||
});
|
|
||||||
if (response.status === 200 && handleFinish) {
|
|
||||||
//Close the modal
|
|
||||||
if (actions?.refetch) actions.refetch();
|
|
||||||
toggleModalVisible();
|
|
||||||
} else if (handleFinish === false) {
|
|
||||||
form.setFieldsValue({ timetickets: data.ticketsToInsert });
|
|
||||||
setUnassignedHours(data.unassignedHours);
|
|
||||||
} else {
|
|
||||||
notification.open({
|
|
||||||
type: "error",
|
|
||||||
message: t("timetickets.errors.creating", {
|
|
||||||
message: JSON.stringify(data),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
notification.open({
|
|
||||||
type: "error",
|
|
||||||
message: t("timetickets.errors.creating", { message: error.message }),
|
|
||||||
});
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
destroyOnClose
|
|
||||||
open={visible}
|
|
||||||
onCancel={() => {
|
|
||||||
toggleModalVisible();
|
|
||||||
form.resetFields();
|
|
||||||
}}
|
|
||||||
width="80%"
|
|
||||||
onOk={() => form.submit()}
|
|
||||||
>
|
|
||||||
<Form
|
|
||||||
autoComplete={"off"}
|
|
||||||
form={form}
|
|
||||||
layout="vertical"
|
|
||||||
onFinish={handleFinish}
|
|
||||||
initialValues={context}
|
|
||||||
onValuesChange={handleValueChange}
|
|
||||||
>
|
|
||||||
<TimeTicketTaskModalComponent
|
|
||||||
form={form}
|
|
||||||
loading={loading}
|
|
||||||
completedTasks={completedTasks}
|
|
||||||
unassignedHours={unassignedHours}
|
|
||||||
/>
|
|
||||||
</Form>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
.task-tickets-table {
|
|
||||||
table-layout: fixed;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
th,
|
|
||||||
td {
|
|
||||||
padding: 8px;
|
|
||||||
text-align: left;
|
|
||||||
border-bottom: 1px solid #ddd;
|
|
||||||
|
|
||||||
.ant-form-item {
|
|
||||||
margin-bottom: 0px !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tr:hover {
|
|
||||||
background-color: #f5f5f5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
import { useMutation } from "@apollo/client";
|
|
||||||
import { Button, notification } from "antd";
|
|
||||||
import moment from "moment";
|
|
||||||
import React, { useState } from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { connect } from "react-redux";
|
|
||||||
import { createStructuredSelector } from "reselect";
|
|
||||||
import { UPDATE_TIME_TICKET } from "../../graphql/timetickets.queries";
|
|
||||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
|
||||||
import {
|
|
||||||
selectBodyshop,
|
|
||||||
selectCurrentUser,
|
|
||||||
} from "../../redux/user/user.selectors";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
|
||||||
bodyshop: selectBodyshop,
|
|
||||||
currentUser: selectCurrentUser,
|
|
||||||
});
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
|
||||||
setTimeTicketContext: (context) =>
|
|
||||||
dispatch(setModalContext({ context: context, modal: "timeTicket" })),
|
|
||||||
});
|
|
||||||
export function TimeTicketsCommit({
|
|
||||||
bodyshop,
|
|
||||||
currentUser,
|
|
||||||
timeticket,
|
|
||||||
disabled,
|
|
||||||
refetch,
|
|
||||||
setTimeTicketContext,
|
|
||||||
}) {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const [updateTimeTicket] = useMutation(UPDATE_TIME_TICKET);
|
|
||||||
|
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
const handleCommit = async () => {
|
|
||||||
setLoading(true);
|
|
||||||
try {
|
|
||||||
const ticketUpdate = timeticket.committed_at
|
|
||||||
? { commited_by: null, committed_at: null }
|
|
||||||
: {
|
|
||||||
commited_by: currentUser.email,
|
|
||||||
committed_at: moment(),
|
|
||||||
};
|
|
||||||
|
|
||||||
const result = await updateTimeTicket({
|
|
||||||
variables: {
|
|
||||||
timeticketId: timeticket.id,
|
|
||||||
timeticket: ticketUpdate,
|
|
||||||
},
|
|
||||||
update(cache) {
|
|
||||||
cache.modify({
|
|
||||||
fields: {
|
|
||||||
timeTickets(existingtickets, { readField }) {
|
|
||||||
return existingtickets.map((ticket) => {
|
|
||||||
if (timeticket.id === readField("id", ticket)) {
|
|
||||||
return {
|
|
||||||
...ticket,
|
|
||||||
...ticketUpdate,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return ticket;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (result.errors) {
|
|
||||||
notification.open({
|
|
||||||
type: "error",
|
|
||||||
message: t("timetickets.errors.creating", {
|
|
||||||
message: JSON.stringify(result.errors),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
setTimeTicketContext({
|
|
||||||
context: {
|
|
||||||
id: timeticket.id,
|
|
||||||
timeticket: result.data.update_timetickets.returning[0],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
notification.open({
|
|
||||||
type: "success",
|
|
||||||
message: t("timetickets.successes.committed"),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!timeticket?.id) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Button onClick={handleCommit} loading={loading} disabled={!timeticket?.id}>
|
|
||||||
{timeticket?.committed_at
|
|
||||||
? t("timetickets.actions.uncommit")
|
|
||||||
: t("timetickets.actions.commitone")}
|
|
||||||
</Button>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(TimeTicketsCommit);
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
import { useMutation } from "@apollo/client";
|
|
||||||
import { Button, notification } from "antd";
|
|
||||||
import moment from "moment";
|
|
||||||
import React, { useState } from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { connect } from "react-redux";
|
|
||||||
import { createStructuredSelector } from "reselect";
|
|
||||||
import { UPDATE_TIME_TICKETS } from "../../graphql/timetickets.queries";
|
|
||||||
import {
|
|
||||||
selectBodyshop,
|
|
||||||
selectCurrentUser,
|
|
||||||
} from "../../redux/user/user.selectors";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
|
||||||
bodyshop: selectBodyshop,
|
|
||||||
currentUser: selectCurrentUser,
|
|
||||||
});
|
|
||||||
|
|
||||||
export function TimeTicketsCommit({
|
|
||||||
bodyshop,
|
|
||||||
currentUser,
|
|
||||||
timetickets,
|
|
||||||
disabled,
|
|
||||||
loadingCallback,
|
|
||||||
completedCallback,
|
|
||||||
refetch,
|
|
||||||
}) {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const [updateTimeTickets] = useMutation(UPDATE_TIME_TICKETS);
|
|
||||||
|
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
const handleCommit = async () => {
|
|
||||||
setLoading(true);
|
|
||||||
try {
|
|
||||||
const result = await updateTimeTickets({
|
|
||||||
variables: {
|
|
||||||
timeticketIds: timetickets.map((ticket) => ticket.id),
|
|
||||||
timeticket: {
|
|
||||||
commited_by: currentUser.email,
|
|
||||||
committed_at: moment(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
update(cache) {
|
|
||||||
cache.modify({
|
|
||||||
fields: {
|
|
||||||
timeTickets(existingtickets, { readField }) {
|
|
||||||
const modifiedIds = timetickets.map((ticket) => ticket.id);
|
|
||||||
return existingtickets.map((ticket) => {
|
|
||||||
if (modifiedIds.includes(readField("id", ticket))) {
|
|
||||||
return {
|
|
||||||
...ticket,
|
|
||||||
commited_by: currentUser.email,
|
|
||||||
committed_at: moment(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return ticket;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (result.errors) {
|
|
||||||
notification.open({
|
|
||||||
type: "error",
|
|
||||||
message: t("timetickets.errors.creating", {
|
|
||||||
message: JSON.stringify(result.errors),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
notification.open({
|
|
||||||
type: "success",
|
|
||||||
message: t("timetickets.successes.committed"),
|
|
||||||
});
|
|
||||||
if (!!completedCallback) completedCallback([]);
|
|
||||||
if (!!loadingCallback) loadingCallback(false);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
onClick={handleCommit}
|
|
||||||
loading={loading}
|
|
||||||
disabled={disabled || timetickets?.length === 0}
|
|
||||||
>
|
|
||||||
{t("timetickets.actions.commit", { count: timetickets?.length })}
|
|
||||||
</Button>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, null)(TimeTicketsCommit);
|
|
||||||
@@ -10,7 +10,7 @@ import { onlyUnique } from "../../utils/arrayHelper";
|
|||||||
import { alphaSort } from "../../utils/sorters";
|
import { alphaSort } from "../../utils/sorters";
|
||||||
import { TemplateList } from "../../utils/TemplateConstants";
|
import { TemplateList } from "../../utils/TemplateConstants";
|
||||||
import PrintWrapperComponent from "../print-wrapper/print-wrapper.component";
|
import PrintWrapperComponent from "../print-wrapper/print-wrapper.component";
|
||||||
import Dinero from "dinero.js";
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
});
|
});
|
||||||
@@ -129,16 +129,6 @@ const JobRelatedTicketsTable = ({
|
|||||||
return acc;
|
return acc;
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
const pay = item.tickets
|
|
||||||
.filter((ticket) => ticket.cost_center === costCenter)
|
|
||||||
.reduce((acc, val) => {
|
|
||||||
return acc.add(
|
|
||||||
Dinero({ amount: Math.round(val.rate * 100) }).multiply(
|
|
||||||
val.flat_rate ? val.productivehrs : val.actualhrs
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}, Dinero());
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: `${item.jobKey}${costCenter}`,
|
id: `${item.jobKey}${costCenter}`,
|
||||||
costCenter,
|
costCenter,
|
||||||
@@ -146,7 +136,6 @@ const JobRelatedTicketsTable = ({
|
|||||||
actHrs: actHrs.toFixed(1),
|
actHrs: actHrs.toFixed(1),
|
||||||
prodHrs: prodHrs.toFixed(1),
|
prodHrs: prodHrs.toFixed(1),
|
||||||
clockHrs,
|
clockHrs,
|
||||||
pay,
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
@@ -206,15 +195,6 @@ const JobRelatedTicketsTable = ({
|
|||||||
state.sortedInfo.columnKey === "clockHrs" && state.sortedInfo.order,
|
state.sortedInfo.columnKey === "clockHrs" && state.sortedInfo.order,
|
||||||
render: (text, record) => record.clockHrs.toFixed(2),
|
render: (text, record) => record.clockHrs.toFixed(2),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: "Pay",
|
|
||||||
dataIndex: "Pay",
|
|
||||||
key: "Pay",
|
|
||||||
sorter: (a, b) => a.clockHrs - b.clockHrs,
|
|
||||||
sortOrder:
|
|
||||||
state.sortedInfo.columnKey === "clockHrs" && state.sortedInfo.order,
|
|
||||||
render: (text, record) => record.pay.toFormat("$0.00"),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: t("general.labels.actions"),
|
title: t("general.labels.actions"),
|
||||||
dataIndex: "actions",
|
dataIndex: "actions",
|
||||||
|
|||||||
@@ -1,241 +0,0 @@
|
|||||||
import { SyncOutlined } from "@ant-design/icons";
|
|
||||||
import { Button, Card, Space, Table, Tag } from "antd";
|
|
||||||
import Dinero from "dinero.js";
|
|
||||||
import queryString from "query-string";
|
|
||||||
import React, { useState } from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { connect } from "react-redux";
|
|
||||||
import { Link, useHistory, useLocation } from "react-router-dom";
|
|
||||||
import { createStructuredSelector } from "reselect";
|
|
||||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
|
||||||
import {
|
|
||||||
selectAuthLevel,
|
|
||||||
selectBodyshop,
|
|
||||||
} from "../../redux/user/user.selectors";
|
|
||||||
import { DateFormatter, DateTimeFormatter } from "../../utils/DateFormatter";
|
|
||||||
import { onlyUnique } from "../../utils/arrayHelper";
|
|
||||||
import { alphaSort, dateSort } from "../../utils/sorters";
|
|
||||||
import TtApproveButtonComponent from "../tt-approve-button/tt-approve-button.component";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
|
||||||
bodyshop: selectBodyshop,
|
|
||||||
authLevel: selectAuthLevel,
|
|
||||||
});
|
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
|
||||||
setTimeTicketTaskContext: (context) =>
|
|
||||||
dispatch(setModalContext({ context: context, modal: "timeTicketTask" })),
|
|
||||||
});
|
|
||||||
export default connect(
|
|
||||||
mapStateToProps,
|
|
||||||
mapDispatchToProps
|
|
||||||
)(TtApprovalsListComponent);
|
|
||||||
|
|
||||||
export function TtApprovalsListComponent({
|
|
||||||
bodyshop,
|
|
||||||
setTimeTicketTaskContext,
|
|
||||||
authLevel,
|
|
||||||
disabled,
|
|
||||||
loading,
|
|
||||||
tt_approval_queue,
|
|
||||||
total,
|
|
||||||
refetch,
|
|
||||||
techConsole,
|
|
||||||
jobId,
|
|
||||||
extra,
|
|
||||||
}) {
|
|
||||||
const [state, setState] = useState({
|
|
||||||
sortedInfo: {},
|
|
||||||
filteredInfo: { text: "" },
|
|
||||||
});
|
|
||||||
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const history = useHistory();
|
|
||||||
const search = queryString.parse(useLocation().search);
|
|
||||||
const { page } = search;
|
|
||||||
const [selectedTickets, setSelectedTickets] = useState([]);
|
|
||||||
|
|
||||||
const columns = [
|
|
||||||
{
|
|
||||||
title: t("timetickets.fields.date"),
|
|
||||||
dataIndex: "date",
|
|
||||||
key: "date",
|
|
||||||
sorter: (a, b) => dateSort(a.date, b.date),
|
|
||||||
sortOrder:
|
|
||||||
state.sortedInfo.columnKey === "date" && state.sortedInfo.order,
|
|
||||||
render: (text, record) => <DateFormatter>{record.date}</DateFormatter>,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t("timetickets.fields.employee"),
|
|
||||||
dataIndex: "employeeid",
|
|
||||||
key: "employeeid",
|
|
||||||
sorter: (a, b) => alphaSort(a.employee.last_name, b.employee.last_name),
|
|
||||||
sortOrder:
|
|
||||||
state.sortedInfo.columnKey === "employee" && state.sortedInfo.order,
|
|
||||||
render: (text, record) =>
|
|
||||||
`${record.employee.first_name} ${record.employee.last_name}`,
|
|
||||||
filters:
|
|
||||||
tt_approval_queue
|
|
||||||
.map((l) => l.employeeid)
|
|
||||||
.filter(onlyUnique)
|
|
||||||
.map((s) => {
|
|
||||||
return {
|
|
||||||
text: (() => {
|
|
||||||
const emp = bodyshop.employees.find((e) => e.id === s);
|
|
||||||
|
|
||||||
return `${emp?.first_name} ${emp?.last_name}`;
|
|
||||||
})(), //
|
|
||||||
value: [s],
|
|
||||||
};
|
|
||||||
}) || [],
|
|
||||||
onFilter: (value, record) => value.includes(record.employeeid),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t("timetickets.fields.cost_center"),
|
|
||||||
dataIndex: "cost_center",
|
|
||||||
key: "cost_center",
|
|
||||||
sorter: (a, b) => alphaSort(a.cost_center, b.cost_center),
|
|
||||||
render: (text, record) =>
|
|
||||||
record.cost_center === "timetickets.labels.shift"
|
|
||||||
? t(record.cost_center)
|
|
||||||
: record.cost_center,
|
|
||||||
sortOrder:
|
|
||||||
state.sortedInfo.columnKey === "cost_center" && state.sortedInfo.order,
|
|
||||||
filters:
|
|
||||||
tt_approval_queue
|
|
||||||
.map((l) => l.cost_center)
|
|
||||||
.filter(onlyUnique)
|
|
||||||
.map((s) => {
|
|
||||||
return {
|
|
||||||
text: s === "timetickets.labels.shift" ? t(s) : s, //|| "No Status*",
|
|
||||||
value: [s],
|
|
||||||
};
|
|
||||||
}) || [],
|
|
||||||
onFilter: (value, record) => value.includes(record.cost_center),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t("jobs.fields.ro_number"),
|
|
||||||
dataIndex: "ro_number",
|
|
||||||
key: "ro_number",
|
|
||||||
sorter: (a, b) =>
|
|
||||||
alphaSort(a.job && a.job.ro_number, b.job && b.job.ro_number),
|
|
||||||
sortOrder:
|
|
||||||
state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
|
|
||||||
render: (text, record) =>
|
|
||||||
record.job && (
|
|
||||||
<Link to={"/manage/jobs/" + record.job.id}>
|
|
||||||
<Space wrap>
|
|
||||||
{record.job.ro_number || "N/A"}
|
|
||||||
<Tag>{record.job.status}</Tag>
|
|
||||||
</Space>
|
|
||||||
</Link>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t("timetickets.fields.productivehrs"),
|
|
||||||
dataIndex: "productivehrs",
|
|
||||||
key: "productivehrs",
|
|
||||||
sorter: (a, b) => a.productivehrs - b.productivehrs,
|
|
||||||
sortOrder:
|
|
||||||
state.sortedInfo.columnKey === "productivehrs" &&
|
|
||||||
state.sortedInfo.order,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t("timetickets.fields.actualhrs"),
|
|
||||||
dataIndex: "actualhrs",
|
|
||||||
key: "actualhrs",
|
|
||||||
sorter: (a, b) => a.actualhrs - b.actualhrs,
|
|
||||||
sortOrder:
|
|
||||||
state.sortedInfo.columnKey === "actualhrs" && state.sortedInfo.order,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t("timetickets.fields.memo"),
|
|
||||||
dataIndex: "memo",
|
|
||||||
key: "memo",
|
|
||||||
sorter: (a, b) => alphaSort(a.memo, b.memo),
|
|
||||||
sortOrder:
|
|
||||||
state.sortedInfo.columnKey === "memo" && state.sortedInfo.order,
|
|
||||||
render: (text, record) =>
|
|
||||||
record.clockon || record.clockoff ? t(record.memo) : record.memo,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t("timetickets.fields.clockon"),
|
|
||||||
dataIndex: "clockon",
|
|
||||||
key: "clockon",
|
|
||||||
|
|
||||||
render: (text, record) => (
|
|
||||||
<DateTimeFormatter>{record.clockon}</DateTimeFormatter>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Pay",
|
|
||||||
dataIndex: "pay",
|
|
||||||
key: "pay",
|
|
||||||
render: (text, record) =>
|
|
||||||
Dinero({ amount: Math.round(record.rate * 100) })
|
|
||||||
.multiply(record.flat_rate ? record.productivehrs : record.actualhrs)
|
|
||||||
.toFormat("$0.00"),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const handleTableChange = (pagination, filters, sorter) => {
|
|
||||||
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
|
|
||||||
search.page = pagination.current;
|
|
||||||
if (sorter && sorter.column && sorter.column.sortObject) {
|
|
||||||
search.searchObj = JSON.stringify(sorter.column.sortObject(sorter.order));
|
|
||||||
} else {
|
|
||||||
delete search.searchObj;
|
|
||||||
search.sortcolumn = sorter.order ? sorter.columnKey : null;
|
|
||||||
search.sortorder = sorter.order;
|
|
||||||
}
|
|
||||||
|
|
||||||
search.sort = JSON.stringify({ [sorter.columnKey]: sorter.order });
|
|
||||||
history.push({ search: queryString.stringify(search) });
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card
|
|
||||||
title={t("timetickets.labels.timetickets")}
|
|
||||||
extra={
|
|
||||||
<Space wrap>
|
|
||||||
{extra}
|
|
||||||
<TtApproveButtonComponent
|
|
||||||
selectedTickets={selectedTickets}
|
|
||||||
disabled={selectedTickets.length === 0}
|
|
||||||
completedCallback={setSelectedTickets}
|
|
||||||
refetch={refetch}
|
|
||||||
/>
|
|
||||||
<Button onClick={() => refetch()}>
|
|
||||||
<SyncOutlined />
|
|
||||||
</Button>
|
|
||||||
</Space>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Table
|
|
||||||
loading={loading}
|
|
||||||
columns={columns}
|
|
||||||
rowKey="id"
|
|
||||||
scroll={{
|
|
||||||
x: true,
|
|
||||||
}}
|
|
||||||
pagination={{
|
|
||||||
position: "top",
|
|
||||||
pageSize: 25,
|
|
||||||
current: parseInt(page || 1),
|
|
||||||
total: total,
|
|
||||||
}}
|
|
||||||
dataSource={tt_approval_queue}
|
|
||||||
onChange={handleTableChange}
|
|
||||||
rowSelection={{
|
|
||||||
onSelectAll: (selected, selectedRows) =>
|
|
||||||
setSelectedTickets(selectedRows.map((i) => i.id)),
|
|
||||||
onSelect: (record, selected, selectedRows, nativeEvent) => {
|
|
||||||
setSelectedTickets(selectedRows.map((i) => i.id));
|
|
||||||
},
|
|
||||||
selectedRowKeys: selectedTickets,
|
|
||||||
type: "checkbox",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
import { useQuery } from "@apollo/client";
|
|
||||||
import queryString from "query-string";
|
|
||||||
import React from "react";
|
|
||||||
import { connect } from "react-redux";
|
|
||||||
import { useLocation } from "react-router-dom";
|
|
||||||
import { createStructuredSelector } from "reselect";
|
|
||||||
import { QUERY_ALL_TT_APPROVALS_PAGINATED } from "../../graphql/tt-approvals.queries";
|
|
||||||
import {
|
|
||||||
setBreadcrumbs,
|
|
||||||
setSelectedHeader,
|
|
||||||
} from "../../redux/application/application.actions";
|
|
||||||
import AlertComponent from "../alert/alert.component";
|
|
||||||
import TtApprovalsListComponent from "./tt-approvals-list.component";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({});
|
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
|
||||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
|
||||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
|
||||||
});
|
|
||||||
|
|
||||||
export function TimeTicketsContainer({
|
|
||||||
bodyshop,
|
|
||||||
setBreadcrumbs,
|
|
||||||
setSelectedHeader,
|
|
||||||
}) {
|
|
||||||
const searchParams = queryString.parse(useLocation().search);
|
|
||||||
const { page, sortcolumn, sortorder, search, searchObj } = searchParams;
|
|
||||||
|
|
||||||
const { loading, error, data, refetch } = useQuery(
|
|
||||||
QUERY_ALL_TT_APPROVALS_PAGINATED,
|
|
||||||
{
|
|
||||||
fetchPolicy: "network-only",
|
|
||||||
nextFetchPolicy: "network-only",
|
|
||||||
variables: {
|
|
||||||
search: search || "",
|
|
||||||
offset: page ? (page - 1) * 25 : 0,
|
|
||||||
limit: 25,
|
|
||||||
order: [
|
|
||||||
searchObj
|
|
||||||
? JSON.parse(searchObj)
|
|
||||||
: {
|
|
||||||
[sortcolumn || "date"]: sortorder
|
|
||||||
? sortorder === "descend"
|
|
||||||
? "desc"
|
|
||||||
: "asc"
|
|
||||||
: "desc",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TtApprovalsListComponent
|
|
||||||
loading={loading}
|
|
||||||
tt_approval_queue={data ? data.tt_approval_queue : []}
|
|
||||||
total={data ? data.tt_approval_queue_aggregate.aggregate.count : 0}
|
|
||||||
refetch={refetch}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(
|
|
||||||
mapStateToProps,
|
|
||||||
mapDispatchToProps
|
|
||||||
)(TimeTicketsContainer);
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
import { useApolloClient } from "@apollo/client";
|
|
||||||
import { Button, notification } 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 { INSERT_TIME_TICKET_AND_APPROVE } from "../../graphql/timetickets.queries";
|
|
||||||
import { QUERY_TT_APPROVALS_BY_IDS } from "../../graphql/tt-approvals.queries";
|
|
||||||
import {
|
|
||||||
selectAuthLevel,
|
|
||||||
selectBodyshop,
|
|
||||||
selectCurrentUser,
|
|
||||||
} from "../../redux/user/user.selectors";
|
|
||||||
import { HasRbacAccess } from "../rbac-wrapper/rbac-wrapper.component";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
|
||||||
bodyshop: selectBodyshop,
|
|
||||||
currentUser: selectCurrentUser,
|
|
||||||
authLevel: selectAuthLevel,
|
|
||||||
});
|
|
||||||
|
|
||||||
export function TtApproveButton({
|
|
||||||
bodyshop,
|
|
||||||
currentUser,
|
|
||||||
selectedTickets,
|
|
||||||
disabled,
|
|
||||||
authLevel,
|
|
||||||
loadingCallback,
|
|
||||||
completedCallback,
|
|
||||||
refetch,
|
|
||||||
}) {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const client = useApolloClient();
|
|
||||||
|
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
|
|
||||||
const handleQbxml = async () => {
|
|
||||||
setLoading(true);
|
|
||||||
try {
|
|
||||||
const { data } = await client.query({
|
|
||||||
query: QUERY_TT_APPROVALS_BY_IDS,
|
|
||||||
variables: { ids: selectedTickets },
|
|
||||||
});
|
|
||||||
|
|
||||||
const insertResponse = await client.mutate({
|
|
||||||
mutation: INSERT_TIME_TICKET_AND_APPROVE,
|
|
||||||
variables: {
|
|
||||||
timeTicketInput: data.tt_approval_queue.map((tta) => ({
|
|
||||||
..._.omit(tta, ["id", "__typename"]),
|
|
||||||
ttapprovalqueueid: tta.id,
|
|
||||||
})),
|
|
||||||
approvalIds: selectedTickets,
|
|
||||||
approvalUpdate: {
|
|
||||||
approved_at: moment(),
|
|
||||||
approved_by: currentUser.email,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (insertResponse.errors) {
|
|
||||||
notification.open({
|
|
||||||
type: "error",
|
|
||||||
message: t("timetickets.errors.creating", {
|
|
||||||
message: JSON.stringify(insertResponse.errors),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
notification.open({
|
|
||||||
type: "success",
|
|
||||||
message: t("timetickets.successes.created"),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
notification.open({
|
|
||||||
type: "error",
|
|
||||||
message: t("timetickets.errors.creating", {
|
|
||||||
message: error.message,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (!!completedCallback) completedCallback([]);
|
|
||||||
// if (!!loadingCallback) loadingCallback(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
onClick={handleQbxml}
|
|
||||||
loading={loading}
|
|
||||||
disabled={
|
|
||||||
disabled ||
|
|
||||||
!HasRbacAccess({ bodyshop, authLevel, action: "ttapprovals:approve" })
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{t("tt_approvals.actions.approveselected")}
|
|
||||||
</Button>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, null)(TtApproveButton);
|
|
||||||
@@ -55,7 +55,7 @@ export function UserRequestResetPw({
|
|||||||
return (
|
return (
|
||||||
<div className="login-container">
|
<div className="login-container">
|
||||||
<div className="login-logo-container">
|
<div className="login-logo-container">
|
||||||
<img src={ImEXOnlineLogo} height="100" width="100" alt="Rome Online" />
|
<img src={ImEXOnlineLogo} height="100" width="100" alt="ImEX Online" />
|
||||||
<Typography.Title>{t("titles.app")}</Typography.Title>
|
<Typography.Title>{t("titles.app")}</Typography.Title>
|
||||||
</div>
|
</div>
|
||||||
<Typography.Title level={3}>{t("titles.resetpassword")}</Typography.Title>
|
<Typography.Title level={3}>{t("titles.resetpassword")}</Typography.Title>
|
||||||
|
|||||||
@@ -25,7 +25,11 @@ export const QUERY_ALL_BILLS_PAGINATED = gql`
|
|||||||
$limit: Int
|
$limit: Int
|
||||||
$order: [bills_order_by!]!
|
$order: [bills_order_by!]!
|
||||||
) {
|
) {
|
||||||
bills(offset: $offset, limit: $limit, order_by: $order) {
|
bills(
|
||||||
|
offset: $offset
|
||||||
|
limit: $limit
|
||||||
|
order_by: $order
|
||||||
|
) {
|
||||||
id
|
id
|
||||||
vendorid
|
vendorid
|
||||||
vendor {
|
vendor {
|
||||||
@@ -94,23 +98,6 @@ export const QUERY_BILLS_BY_JOBID = gql`
|
|||||||
comments
|
comments
|
||||||
user_email
|
user_email
|
||||||
}
|
}
|
||||||
parts_dispatch(where: { jobid: { _eq: $jobid } }) {
|
|
||||||
id
|
|
||||||
dispatched_at
|
|
||||||
dispatched_by
|
|
||||||
employeeid
|
|
||||||
number
|
|
||||||
parts_dispatch_lines {
|
|
||||||
joblineid
|
|
||||||
id
|
|
||||||
quantity
|
|
||||||
accepted_at
|
|
||||||
jobline {
|
|
||||||
id
|
|
||||||
line_desc
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bills(where: { jobid: { _eq: $jobid } }, order_by: { date: desc }) {
|
bills(where: { jobid: { _eq: $jobid } }, order_by: { date: desc }) {
|
||||||
id
|
id
|
||||||
vendorid
|
vendorid
|
||||||
|
|||||||
@@ -118,21 +118,7 @@ export const QUERY_BODYSHOP = gql`
|
|||||||
md_parts_scan
|
md_parts_scan
|
||||||
enforce_conversion_category
|
enforce_conversion_category
|
||||||
tt_enforce_hours_for_tech_console
|
tt_enforce_hours_for_tech_console
|
||||||
md_tasks_presets
|
|
||||||
use_paint_scale_data
|
use_paint_scale_data
|
||||||
employee_teams(
|
|
||||||
order_by: { name: asc }
|
|
||||||
where: { active: { _eq: true } }
|
|
||||||
) {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
employee_team_members {
|
|
||||||
id
|
|
||||||
employeeid
|
|
||||||
labor_rates
|
|
||||||
percentage
|
|
||||||
}
|
|
||||||
}
|
|
||||||
employees {
|
employees {
|
||||||
user_email
|
user_email
|
||||||
id
|
id
|
||||||
@@ -249,20 +235,6 @@ export const UPDATE_SHOP = gql`
|
|||||||
md_parts_scan
|
md_parts_scan
|
||||||
enforce_conversion_category
|
enforce_conversion_category
|
||||||
tt_enforce_hours_for_tech_console
|
tt_enforce_hours_for_tech_console
|
||||||
md_tasks_presets
|
|
||||||
employee_teams(
|
|
||||||
order_by: { name: asc }
|
|
||||||
where: { active: { _eq: true } }
|
|
||||||
) {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
employee_team_members {
|
|
||||||
id
|
|
||||||
employeeid
|
|
||||||
labor_rates
|
|
||||||
percentage
|
|
||||||
}
|
|
||||||
}
|
|
||||||
employees {
|
employees {
|
||||||
id
|
id
|
||||||
first_name
|
first_name
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user