Compare commits

..

31 Commits

Author SHA1 Message Date
Allan Carr
c0dab92d0e IO-2522 Load Level Table Change 2024-01-05 12:01:47 -08:00
Allan Carr
1a4bc720c2 Merged in release/2023-12-29 (pull request #1127)
Release/2023 12 29
2023-12-29 22:08:52 +00:00
Allan Carr
18998c4dbe Merged in feature/IO-2489-Regi-#-in-Vehicle-Box (pull request #1125)
IO-2489 Registration # in Vehicle Info Box

Approved-by: Dave Richer
2023-12-28 18:56:27 +00:00
Allan Carr
e236d6e912 IO-2489 Registration # in Vehicle Info Box 2023-12-28 10:57:03 -08:00
Allan Carr
523df670df Merged in feature/IO-2512-Date-Estimated-Manual-Job (pull request #1122)
IO-2512 Date Esimated on Manual Created Jobs

Approved-by: Dave Richer
2023-12-28 18:22:43 +00:00
Allan Carr
ce58181fc3 Merged in feature/IO-2500-Courtesy-Car-Readiness-&-Fuel-Level (pull request #1123)
IO-2500 Readiness and Fuel Level

Approved-by: Dave Richer
2023-12-28 18:21:35 +00:00
Allan Carr
bed0669f73 Merged in feature/IO-2513-Fuel-Level-Tooltip (pull request #1124)
IO-2500 Courtesy Car Readiness

Approved-by: Dave Richer
2023-12-28 18:19:16 +00:00
Allan Carr
bdb2951330 IO-2500 Courtesy Car Readiness 2023-12-27 13:55:31 -08:00
Allan Carr
87a01208fb IO-2500 Readiness and Fuel Level 2023-12-27 13:35:29 -08:00
Allan Carr
2daee84fbf IO-2512 Date Esimated on Manual Created Jobs 2023-12-27 11:07:17 -08:00
Allan Carr
cdbf58f3ac Merged in feature/IO-2511-Bill-Label-Reprint (pull request #1121)
IO-2511 Bill Label Reprint

Approved-by: Dave Richer
2023-12-27 16:18:44 +00:00
Allan Carr
f6a59bdf55 IO-2511 Bill Label Reprint 2023-12-26 11:18:39 -08:00
Allan Carr
e12edd977e Merged in release/2023-12-15 (pull request #1120)
Release/2023 12 15

Approved-by: Dave Richer
2023-12-22 18:16:40 +00:00
Allan Carr
b925c991eb Merged in feature/IO-2501-Add-Jobs-Completed-Delivered-Not-Invoiced-Section (pull request #1118)
IO-2501 Correct for missing query variables

Approved-by: Dave Richer
2023-12-22 02:33:30 +00:00
Allan Carr
1e7f43fe3d IO-2501 Correct for missing query variables 2023-12-21 18:32:37 -08:00
Allan Carr
6f21de1901 Merged in feature/IO-2505-Conversation-List-Print (pull request #1116)
IO-2505 Conversation List Print

Approved-by: Dave Richer
2023-12-21 17:37:47 +00:00
Allan Carr
25e8eaa1d4 IO-2505 Conversation List Print 2023-12-21 09:24:25 -08:00
Allan Carr
6fe736ce06 Merged in feature/IO-1366-Audit-Logging (pull request #1114)
IO-1366 Invoice Job Audit Trail

Approved-by: Dave Richer
2023-12-20 20:44:11 +00:00
Allan Carr
482b03c2d1 IO-1366 Invoice Job Audit Trail 2023-12-20 11:52:04 -08:00
Allan Carr
ce3c72fc47 Merged in feature/IO-1366-Audit-Logging (pull request #1113)
IO-1366 Audit Logging for Production Alert

Approved-by: Dave Richer
2023-12-20 19:38:46 +00:00
Allan Carr
1ff5ed4141 IO-1366 Audit Logging for Production Alert 2023-12-20 11:36:42 -08:00
Allan Carr
10e3421572 Merged in feature/IO-2506-Federal-Tax-Exempt-on-Bill-Entry (pull request #1111)
IO-2506 Correct for variable immutibility and nested ifs
2023-12-19 17:16:48 +00:00
Allan Carr
0117237988 IO-2506 Correct for variable immutibility and nested ifs 2023-12-19 09:18:00 -08:00
Allan Carr
373fd817d0 Merged in feature/IO-2506-Federal-Tax-Exempt-on-Bill-Entry (pull request #1108)
IO-2506 Federal Tax Exempt on Bill Entry

Approved-by: Dave Richer
2023-12-19 16:34:38 +00:00
Allan Carr
0ef2d9646d Merged in feature/IO-2509-Report-Center-RBAC (pull request #1109)
IO-2509 Report Center RBAC

Approved-by: Dave Richer
2023-12-19 16:32:29 +00:00
Allan Carr
c8ac417200 IO-2509 Report Center RBAC 2023-12-18 14:12:21 -08:00
Allan Carr
661bedbe5b IO-2506 Federal Tax Exempt on Bill Entry
Will Toggle Federal Tax off on any new line or retroactively toggle it off on all lines when switch is enabled. Limited to PBS or CDK setups.
2023-12-18 12:36:46 -08:00
Allan Carr
2dd56590d3 Admin panel to force email addresses to be lowercase to conform with firebase 2023-12-14 08:57:36 -08:00
Allan Carr
98b760251c Merged in feature/IO-2501-Add-Jobs-Completed-Delivered-Not-Invoiced-Section (pull request #1107)
IO-2501 Add Jobs Complete Not Invoiced Section to Stats

Approved-by: Dave Richer
2023-12-13 18:47:04 +00:00
Allan Carr
b97de32a44 IO-2501 Add Jobs Complete Not Invoiced Section to Stats 2023-12-12 15:41:36 -08:00
Dave Richer
92c8b54f85 Merged in release/2023-12-01 (pull request #1103)
Reversion

Approved-by: Allan Carr
2023-12-04 16:50:13 +00:00
187 changed files with 3062 additions and 16531 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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"
}), }),

View File

@@ -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 = {

View File

@@ -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>

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -10,7 +10,7 @@ import { createStructuredSelector } from "reselect";
import { import {
DELETE_BILL_LINE, DELETE_BILL_LINE,
INSERT_NEW_BILL_LINES, INSERT_NEW_BILL_LINES,
UPDATE_BILL_LINE UPDATE_BILL_LINE,
} from "../../graphql/bill-lines.queries"; } from "../../graphql/bill-lines.queries";
import { QUERY_BILL_BY_PK, UPDATE_BILL } from "../../graphql/bills.queries"; import { QUERY_BILL_BY_PK, UPDATE_BILL } from "../../graphql/bills.queries";
import { insertAuditTrail } from "../../redux/application/application.actions"; import { insertAuditTrail } from "../../redux/application/application.actions";
@@ -20,6 +20,7 @@ import AuditTrailMapping from "../../utils/AuditTrailMappings";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
import BillFormContainer from "../bill-form/bill-form.container"; import BillFormContainer from "../bill-form/bill-form.container";
import BillMarkExportedButton from "../bill-mark-exported-button/bill-mark-exported-button.component"; import BillMarkExportedButton from "../bill-mark-exported-button/bill-mark-exported-button.component";
import BillPrintButton from "../bill-print-button/bill-print-button.component";
import BillReeportButtonComponent from "../bill-reexport-button/bill-reexport-button.component"; import BillReeportButtonComponent from "../bill-reexport-button/bill-reexport-button.component";
import JobDocumentsGallery from "../jobs-documents-gallery/jobs-documents-gallery.container"; import JobDocumentsGallery from "../jobs-documents-gallery/jobs-documents-gallery.container";
import JobsDocumentsLocalGallery from "../jobs-documents-local-gallery/jobs-documents-local-gallery.container"; import JobsDocumentsLocalGallery from "../jobs-documents-local-gallery/jobs-documents-local-gallery.container";
@@ -176,7 +177,7 @@ export function BillDetailEditcontainer({
extra={ extra={
<Space> <Space>
<BillDetailEditReturn data={data} /> <BillDetailEditReturn data={data} />
<BillPrintButton billid={search.billid} />
<Popconfirm <Popconfirm
visible={visible} visible={visible}
onConfirm={() => form.submit()} onConfirm={() => form.submit()}

View File

@@ -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}

View File

@@ -79,6 +79,20 @@ export function BillFormComponent({
}); });
}; };
const handleFederalTaxExemptSwitchToggle = (checked) => {
// Early gate
if (!checked) return;
const values = form.getFieldsValue("billlines");
// Gate bill lines
if (!values?.billlines?.length) return;
const billlines = values.billlines.map((b) => {
b.applicable_taxes.federal = false;
return b;
});
form.setFieldsValue({ billlines });
};
useEffect(() => { useEffect(() => {
if (job) form.validateFields(["is_credit_memo"]); if (job) form.validateFields(["is_credit_memo"]);
}, [job, form]); }, [job, form]);
@@ -366,15 +380,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,16 +394,23 @@ 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> {bodyshop.pbs_serialnumber || bodyshop.cdk_dealerid ? (
} <Form.Item
<Form.Item shouldUpdate span={15}> span={2}
label={t("bills.labels.federal_tax_exempt")}
name="federal_tax_exempt"
>
<Switch onChange={handleFederalTaxExemptSwitchToggle} />
</Form.Item>
) : null}
<Form.Item shouldUpdate span={13}>
{() => { {() => {
const values = form.getFieldsValue([ const values = form.getFieldsValue([
"billlines", "billlines",
@@ -409,32 +428,28 @@ export function BillFormComponent({
totals = CalculateBillTotal(values); totals = CalculateBillTotal(values);
if (!!totals) if (!!totals)
return ( return (
<div> <div align="right">
<Space wrap> <Space wrap>
<Statistic <Statistic
title={t("bills.labels.subtotal")} title={t("bills.labels.subtotal")}
value={totals.subtotal.toFormat()} value={totals.subtotal.toFormat()}
precision={2} precision={2}
/> />
{ <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()}

View File

@@ -2,7 +2,6 @@ import { DeleteFilled, DollarCircleFilled } from "@ant-design/icons";
import { useTreatments } from "@splitsoftware/splitio-react"; import { useTreatments } from "@splitsoftware/splitio-react";
import { import {
Button, Button,
Checkbox,
Form, Form,
Input, Input,
InputNumber, InputNumber,
@@ -47,13 +46,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 +94,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 +220,6 @@ export function BillEnterModalLinesComponent({
}} }}
/> />
), ),
additional: (record, index) => (
<Form.Item
dependencies={["billlines", record.name, "actual_price"]}
noStyle
>
{() => {
const billLine = getFieldValue(["billlines", record.name]);
const jobLine = lineData.find(
(line) => line.id === billLine?.joblineid
);
if (
!billEdit &&
billLine &&
jobLine &&
billLine?.actual_price !== jobLine?.act_price
) {
return (
<Space size="small">
<Form.Item
noStyle
label={t("joblines.fields.create_ppc")}
key={`${index}ppc`}
valuePropName="checked"
name={[record.name, "create_ppc"]}
>
<Checkbox />
</Form.Item>
{t("joblines.fields.create_ppc")}
</Space>
);
} else {
return null;
}
}}
</Form.Item>
),
}, },
{ {
title: t("billlines.fields.actual_cost"), title: t("billlines.fields.actual_cost"),
@@ -407,7 +361,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 +376,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 +435,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 +458,22 @@ 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:
// name: [field.name, "applicable_taxes", "federal"], form.getFieldValue("federal_tax_exempt") === true ? false : true,
// }; 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 +488,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 +626,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 +635,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)

View File

@@ -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));
} }
}); });

View File

@@ -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)}`

View File

@@ -0,0 +1,38 @@
import { Button, Space } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { GenerateDocument } from "../../utils/RenderTemplate";
import { TemplateList } from "../../utils/TemplateConstants";
export default function BillPrintButton({ billid }) {
const { t } = useTranslation();
const [loading, setLoading] = useState(false);
const Templates = TemplateList("job_special");
const submitHandler = async () => {
setLoading(true);
try {
await GenerateDocument(
{
name: Templates.parts_invoice_label_single.key,
variables: {
id: billid,
},
},
{},
"p"
);
} catch (e) {
console.warn("Warning: Error generating a document.");
}
setLoading(false);
};
return (
<Space wrap>
<Button loading={loading} onClick={submitHandler}>
{t("bills.labels.printlabels")}
</Button>
</Space>
);
}

View File

@@ -4,6 +4,7 @@ import PhoneNumberFormatter from "../../utils/PhoneFormatter";
import ChatArchiveButton from "../chat-archive-button/chat-archive-button.component"; import ChatArchiveButton from "../chat-archive-button/chat-archive-button.component";
import ChatConversationTitleTags from "../chat-conversation-title-tags/chat-conversation-title-tags.component"; import ChatConversationTitleTags from "../chat-conversation-title-tags/chat-conversation-title-tags.component";
import ChatLabelComponent from "../chat-label/chat-label.component"; import ChatLabelComponent from "../chat-label/chat-label.component";
import ChatPrintButton from "../chat-print-button/chat-print-button.component";
import ChatTagRoContainer from "../chat-tag-ro/chat-tag-ro.container"; import ChatTagRoContainer from "../chat-tag-ro/chat-tag-ro.container";
export default function ChatConversationTitle({ conversation }) { export default function ChatConversationTitle({ conversation }) {
@@ -13,6 +14,7 @@ export default function ChatConversationTitle({ conversation }) {
{conversation && conversation.phone_num} {conversation && conversation.phone_num}
</PhoneNumberFormatter> </PhoneNumberFormatter>
<ChatLabelComponent conversation={conversation} /> <ChatLabelComponent conversation={conversation} />
<ChatPrintButton conversation={conversation} />
<ChatConversationTitleTags <ChatConversationTitleTags
jobConversations={ jobConversations={
(conversation && conversation.job_conversations) || [] (conversation && conversation.job_conversations) || []

View File

@@ -0,0 +1,59 @@
import { MailOutlined, PrinterOutlined } from "@ant-design/icons";
import { Space, Spin } from "antd";
import React, { useState } from "react";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { setEmailOptions } from "../../redux/email/email.actions";
import { GenerateDocument } from "../../utils/RenderTemplate";
import { TemplateList } from "../../utils/TemplateConstants";
const mapStateToProps = createStructuredSelector({});
const mapDispatchToProps = (dispatch) => ({
setEmailOptions: (e) => dispatch(setEmailOptions(e)),
});
export function ChatPrintButton({ conversation }) {
const [loading, setLoading] = useState(false);
return (
<Space wrap>
<PrinterOutlined
onClick={() => {
setLoading(true);
GenerateDocument(
{
name: TemplateList("messaging").conversation_list.key,
variables: { id: conversation.id },
},
{
subject: TemplateList("messaging").conversation_list.subject,
},
"p",
conversation.id
);
setLoading(false);
}}
/>
<MailOutlined
onClick={() => {
setLoading(true);
GenerateDocument(
{
name: TemplateList("messaging").conversation_list.key,
variables: { id: conversation.id },
},
{
subject: TemplateList("messaging").conversation_list.subject,
},
"e",
conversation.id
);
setLoading(false);
}}
/>
{loading && <Spin />}
</Space>
);
}
export default connect(mapStateToProps, mapDispatchToProps)(ChatPrintButton);

View File

@@ -35,6 +35,15 @@ export default function ContractsCarsComponent({
state.sortedInfo.columnKey === "status" && state.sortedInfo.order, state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
render: (text, record) => <div>{t(record.status)}</div>, render: (text, record) => <div>{t(record.status)}</div>,
}, },
{
title: t("courtesycars.fields.readiness"),
dataIndex: "readiness",
key: "readiness",
sorter: (a, b) => alphaSort(a.readiness, b.readiness),
sortOrder:
state.sortedInfo.columnKey === "readiness" && state.sortedInfo.order,
render: (text, record) => t(record.readiness),
},
{ {
title: t("courtesycars.fields.year"), title: t("courtesycars.fields.year"),
dataIndex: "year", dataIndex: "year",

View File

@@ -7,6 +7,7 @@ import { useTranslation } from "react-i18next";
import { CHECK_CC_FLEET_NUMBER } from "../../graphql/courtesy-car.queries"; import { CHECK_CC_FLEET_NUMBER } from "../../graphql/courtesy-car.queries";
import { DateFormatter } from "../../utils/DateFormatter"; import { DateFormatter } from "../../utils/DateFormatter";
import CourtesyCarFuelSlider from "../courtesy-car-fuel-select/courtesy-car-fuel-select.component"; import CourtesyCarFuelSlider from "../courtesy-car-fuel-select/courtesy-car-fuel-select.component";
import CourtesyCarReadiness from "../courtesy-car-readiness-select/courtesy-car-readiness-select.component";
import CourtesyCarStatus from "../courtesy-car-status-select/courtesy-car-status-select.component"; import CourtesyCarStatus from "../courtesy-car-status-select/courtesy-car-status-select.component";
import FormDatePicker from "../form-date-picker/form-date-picker.component"; import FormDatePicker from "../form-date-picker/form-date-picker.component";
//import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component"; //import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
@@ -213,6 +214,12 @@ export default function CourtesyCarCreateFormComponent({ form, saveLoading }) {
> >
<CourtesyCarStatus /> <CourtesyCarStatus />
</Form.Item> </Form.Item>
<Form.Item
label={t("courtesycars.fields.readiness")}
name="readiness"
>
<CourtesyCarReadiness />
</Form.Item>
<div> <div>
<Form.Item <Form.Item
label={t("courtesycars.fields.nextservicekm")} label={t("courtesycars.fields.nextservicekm")}

View File

@@ -34,6 +34,32 @@ const CourtesyCarFuelComponent = (props, ref) => {
step={null} step={null}
style={{ marginLeft: "2rem", marginRight: "2rem" }} style={{ marginLeft: "2rem", marginRight: "2rem" }}
{...props} {...props}
tooltip={{
formatter: (value) => {
switch (value) {
case 0:
return t("courtesycars.labels.fuel.empty");
case 13:
return t("courtesycars.labels.fuel.18");
case 25:
return t("courtesycars.labels.fuel.14");
case 38:
return t("courtesycars.labels.fuel.38");
case 50:
return t("courtesycars.labels.fuel.12");
case 63:
return t("courtesycars.labels.fuel.58");
case 75:
return t("courtesycars.labels.fuel.34");
case 88:
return t("courtesycars.labels.fuel.78");
case 100:
return t("courtesycars.labels.fuel.full");
default:
return value;
}
},
}}
/> />
); );
}; };

View File

@@ -0,0 +1,35 @@
import { Select } from "antd";
import React, { forwardRef, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
const { Option } = Select;
const CourtesyCarReadinessComponent = ({ value, onChange }, ref) => {
const [option, setOption] = useState(value);
const { t } = useTranslation();
useEffect(() => {
if (value !== option && onChange) {
onChange(option);
}
}, [value, option, onChange]);
return (
<Select
allowClear
ref={ref}
value={option}
style={{
width: 100,
}}
onChange={setOption}
>
<Option value="courtesycars.readiness.ready">
{t("courtesycars.readiness.ready")}
</Option>
<Option value="courtesycars.readiness.notready">
{t("courtesycars.readiness.notready")}
</Option>
</Select>
);
};
export default forwardRef(CourtesyCarReadinessComponent);

View File

@@ -91,6 +91,26 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
); );
}, },
}, },
{
title: t("courtesycars.fields.readiness"),
dataIndex: "readiness",
key: "readiness",
sorter: (a, b) => alphaSort(a.readiness, b.readiness),
filters: [
{
text: t("courtesycars.readiness.ready"),
value: "courtesycars.readiness.ready",
},
{
text: t("courtesycars.readiness.notready"),
value: "courtesycars.readiness.notready",
},
],
onFilter: (value, record) => value.includes(record.readiness),
sortOrder:
state.sortedInfo.columnKey === "readiness" && state.sortedInfo.order,
render: (text, record) => t(record.readiness),
},
{ {
title: t("courtesycars.fields.year"), title: t("courtesycars.fields.year"),
dataIndex: "year", dataIndex: "year",
@@ -131,6 +151,36 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
sortOrder: sortOrder:
state.sortedInfo.columnKey === "plate" && state.sortedInfo.order, state.sortedInfo.columnKey === "plate" && state.sortedInfo.order,
}, },
{
title: t("courtesycars.fields.fuel"),
dataIndex: "fuel",
key: "fuel",
sorter: (a, b) => alphaSort(a.fuel, b.fuel),
sortOrder:
state.sortedInfo.columnKey === "fuel" && state.sortedInfo.order,
render: (text, record) => {
switch (record.fuel) {
case 100:
return t("courtesycars.labels.fuel.full");
case 88:
return t("courtesycars.labels.fuel.78");
case 63:
return t("courtesycars.labels.fuel.58");
case 50:
return t("courtesycars.labels.fuel.12");
case 38:
return t("courtesycars.labels.fuel.34");
case 25:
return t("courtesycars.labels.fuel.14");
case 13:
return t("courtesycars.labels.fuel.18");
case 0:
return t("courtesycars.labels.fuel.empty");
default:
return record.fuel;
}
},
},
{ {
title: t("courtesycars.labels.outwith"), title: t("courtesycars.labels.outwith"),
dataIndex: "outwith", dataIndex: "outwith",

View File

@@ -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);

View File

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

View File

@@ -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**
// ---- // ----

View File

@@ -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));

View File

@@ -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>

View File

@@ -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);

View File

@@ -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 (

View File

@@ -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}

View File

@@ -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>
); );

View File

@@ -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>
); );
} }

View File

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

View File

@@ -1,12 +1,12 @@
import { 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")}

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
import { useMutation } from "@apollo/client"; import { 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>
); );
} }

View File

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

View File

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

View File

@@ -19,8 +19,7 @@ export default function JobReconciliationModalComponent({ job, bills }) {
const jobLineData = job.joblines.filter( 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") ||

View File

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

View File

@@ -67,8 +67,7 @@ export function JobsTotalsTableComponent({ jobRO, currentUser, job }) {
<JobTotalsTableTotals job={job} /> <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} />

View File

@@ -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>

View File

@@ -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>
))}
</> </>
)} )}
/> />

View File

@@ -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 = [
{ {

View File

@@ -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.

View File

@@ -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,
};
});
} }

View File

@@ -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;
} }

View File

@@ -1,4 +1,4 @@
import { Collapse, Form, Input, Select, Switch } from "antd"; import { Collapse, Form, Input, InputNumber, Select, Switch } from "antd";
import React from "react"; import 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>
); );
} }

View File

@@ -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,
}) { }) {
@@ -111,6 +108,14 @@ export function JobsDetailHeaderActions({
}, },
}, },
}); });
insertAuditTrail({
jobid: job.id,
operation: AuditTrailMapping.alertToggle(
!!job.production_vars && !!job.production_vars.alert
? !job.production_vars.alert
: true
),
});
}; };
const handleSuspend = (e) => { const handleSuspend = (e) => {
@@ -271,24 +276,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}

View File

@@ -1,8 +1,8 @@
import { import {
BranchesOutlined,
ExclamationCircleFilled, ExclamationCircleFilled,
PauseCircleOutlined, PauseCircleOutlined,
WarningFilled, WarningFilled,
BranchesOutlined,
} from "@ant-design/icons"; } from "@ant-design/icons";
import { Card, Col, Row, Space, Tag, Tooltip } from "antd"; import { Card, Col, Row, Space, Tag, Tooltip } from "antd";
import React, { useState } from "react"; import React, { useState } from "react";
@@ -222,6 +222,9 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) {
{`${job.v_vin || t("general.labels.na")}`} {`${job.v_vin || t("general.labels.na")}`}
</VehicleVinDisplay> </VehicleVinDisplay>
</DataLabel> </DataLabel>
<DataLabel label={t("jobs.fields.regie_number")}>
{job.regie_number || t("general.labels.na")}
</DataLabel>
<DataLabel label={t("jobs.labels.relatedros")}> <DataLabel label={t("jobs.labels.relatedros")}>
<JobsRelatedRos jobid={job.id} job={job} /> <JobsRelatedRos jobid={job.id} job={job} />
</DataLabel> </DataLabel>

View File

@@ -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>
); );
} }

View File

@@ -6,14 +6,12 @@ import BillsListTable from "../bills-list-table/bills-list-table.component";
import JobBillsTotal from "../job-bills-total/job-bills-total.component"; import 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>
); );

View File

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

View File

@@ -1,21 +1,25 @@
import { Divider, Form, Input, Select, Space, Switch, Tooltip } from "antd"; import {
Divider,
Form,
Input,
InputNumber,
Select,
Space,
Switch,
Tooltip,
} from "antd";
import React from "react"; import 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>
); );
} }

View File

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

View File

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

View File

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

View File

@@ -29,7 +29,7 @@ export function JobsDetailRatesParts({
label={t("jobs.fields.parts_tax_rates.prt_discp")} 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>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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) =>

View File

@@ -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>
); );

View File

@@ -1,12 +1,23 @@
import { ExclamationCircleFilled } from "@ant-design/icons"; import { ExclamationCircleFilled } from "@ant-design/icons";
import { useMutation } from "@apollo/client";
import { Dropdown, Menu } from "antd"; import { Dropdown, Menu } from "antd";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useMutation } from "@apollo/client"; import { connect } from "react-redux";
import { UPDATE_JOB } from "../../graphql/jobs.queries"; import { createStructuredSelector } from "reselect";
import { logImEXEvent } from "../../firebase/firebase.utils"; import { logImEXEvent } from "../../firebase/firebase.utils";
import { UPDATE_JOB } from "../../graphql/jobs.queries";
import { insertAuditTrail } from "../../redux/application/application.actions";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
export default function ProductionListColumnAlert({ record }) { const mapStateToProps = createStructuredSelector({});
const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({ jobid, operation }) =>
dispatch(insertAuditTrail({ jobid, operation })),
});
export function ProductionListColumnAlert({ record, insertAuditTrail }) {
const { t } = useTranslation(); const { t } = useTranslation();
const [updateAlert] = useMutation(UPDATE_JOB); const [updateAlert] = useMutation(UPDATE_JOB);
@@ -27,6 +38,14 @@ export default function ProductionListColumnAlert({ record }) {
}, },
}, },
}, },
});
insertAuditTrail({
jobid: record.id,
operation: AuditTrailMapping.alertToggle(
!!record.production_vars && !!record.production_vars.alert
? !record.production_vars.alert
: true
),
}).then(() => { }).then(() => {
if (record.refetch) record.refetch(); if (record.refetch) record.refetch();
}); });
@@ -58,3 +77,8 @@ export default function ProductionListColumnAlert({ record }) {
</Dropdown> </Dropdown>
); );
} }
export default connect(
mapStateToProps,
mapDispatchToProps
)(ProductionListColumnAlert);

View File

@@ -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",

View File

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

View File

@@ -55,10 +55,11 @@ const ret = {
"shiftclock:view": 2, "shiftclock:view": 2,
"shop:config": 4, "shop:config": 4,
"shop:rbac": 5,
"shop:vendors": 2,
"shop:dashboard": 3, "shop:dashboard": 3,
"shop:rbac": 5,
"shop:reportcenter": 2,
"shop:templates": 4, "shop:templates": 4,
"shop:vendors": 2,
"temporarydocs:view": 2, "temporarydocs:view": 2,

View File

@@ -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 }] =

View File

@@ -5,6 +5,7 @@ import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { toggleModalVisible } from "../../redux/modals/modals.actions"; import { toggleModalVisible } from "../../redux/modals/modals.actions";
import { selectReportCenter } from "../../redux/modals/modals.selectors"; import { selectReportCenter } from "../../redux/modals/modals.selectors";
import RbacWrapperComponent from "../rbac-wrapper/rbac-wrapper.component";
import ReportCenterModalComponent from "./report-center-modal.component"; import ReportCenterModalComponent from "./report-center-modal.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
@@ -33,7 +34,9 @@ export function ReportCenterModalContainer({
destroyOnClose destroyOnClose
width="80%" width="80%"
> >
<ReportCenterModalComponent /> <RbacWrapperComponent action="shop:reportcenter">
<ReportCenterModalComponent />
</RbacWrapperComponent>
</Modal> </Modal>
); );
} }

View File

@@ -29,7 +29,7 @@ export default connect(
export function ScoreboardTimeTicketsStats({ bodyshop }) { export function ScoreboardTimeTicketsStats({ bodyshop }) {
const { t } = useTranslation(); const { t } = useTranslation();
const startDate = moment().startOf("month") const startDate = moment().startOf("month");
const endDate = moment().endOf("month"); const endDate = moment().endOf("month");
const fixedPeriods = useMemo(() => { const fixedPeriods = useMemo(() => {
@@ -84,6 +84,8 @@ export function ScoreboardTimeTicketsStats({ bodyshop }) {
end: endDate.format("YYYY-MM-DD"), end: endDate.format("YYYY-MM-DD"),
fixedStart: fixedPeriods.start.format("YYYY-MM-DD"), fixedStart: fixedPeriods.start.format("YYYY-MM-DD"),
fixedEnd: fixedPeriods.end.format("YYYY-MM-DD"), fixedEnd: fixedPeriods.end.format("YYYY-MM-DD"),
jobStart: startDate,
jobEnd: endDate,
}, },
fetchPolicy: "network-only", fetchPolicy: "network-only",
nextFetchPolicy: "network-only", nextFetchPolicy: "network-only",
@@ -340,11 +342,21 @@ export function ScoreboardTimeTicketsStats({ bodyshop }) {
larData.push({ ...r, ...lar }); larData.push({ ...r, ...lar });
}); });
const jobData = {};
data.jobs.forEach((job) => {
job.tthrs = job.joblines.reduce((acc, val) => acc + val.mod_lb_hrs, 0);
});
jobData.tthrs = data.jobs
.reduce((acc, val) => acc + val.tthrs, 0)
.toFixed(1);
jobData.count = data.jobs.length.toFixed(0);
return { return {
fixed: ret, fixed: ret,
combinedData: combinedData, combinedData: combinedData,
labData: labData, labData: labData,
larData: larData, larData: larData,
jobData: jobData,
}; };
}, [fixedPeriods, data, bodyshop]); }, [fixedPeriods, data, bodyshop]);
@@ -356,7 +368,10 @@ export function ScoreboardTimeTicketsStats({ bodyshop }) {
<ScoreboardTimeticketsTargetsTable /> <ScoreboardTimeticketsTargetsTable />
</Col> </Col>
<Col span={24}> <Col span={24}>
<ScoreboardTicketsStats data={calculatedData.fixed} /> <ScoreboardTicketsStats
data={calculatedData.fixed}
jobData={calculatedData.jobData}
/>
</Col> </Col>
<Col span={24}> <Col span={24}>
<ScoreboardTimeTicketsChart <ScoreboardTimeTicketsChart

View File

@@ -41,7 +41,7 @@ function useLocalStorage(key, initialValue) {
return [storedValue, setStoredValue]; return [storedValue, setStoredValue];
} }
export function ScoreboardTicketsStats({ data, bodyshop }) { export function ScoreboardTicketsStats({ data, jobData, bodyshop }) {
const { t } = useTranslation(); const { t } = useTranslation();
const [isLarge, setIsLarge] = useLocalStorage("isLargeStatistic", false); const [isLarge, setIsLarge] = useLocalStorage("isLargeStatistic", false);
@@ -408,7 +408,7 @@ export function ScoreboardTicketsStats({ data, bodyshop }) {
{/* Monthly Stats */} {/* Monthly Stats */}
<Row gutter={[16, 16]}> <Row gutter={[16, 16]}>
{/* This Month */} {/* This Month */}
<Col span={8} align="center"> <Col span={7} align="center">
<Card size="small" title={t("scoreboard.labels.thismonth")}> <Card size="small" title={t("scoreboard.labels.thismonth")}>
<Row gutter={[16, 16]}> <Row gutter={[16, 16]}>
<Col span={24}> <Col span={24}>
@@ -482,7 +482,7 @@ export function ScoreboardTicketsStats({ data, bodyshop }) {
</Card> </Card>
</Col> </Col>
{/* Last Month */} {/* Last Month */}
<Col span={8} align="center"> <Col span={7} align="center">
<Card size="small" title={t("scoreboard.labels.lastmonth")}> <Card size="small" title={t("scoreboard.labels.lastmonth")}>
<Row gutter={[16, 16]}> <Row gutter={[16, 16]}>
<Col span={24}> <Col span={24}>
@@ -556,7 +556,7 @@ export function ScoreboardTicketsStats({ data, bodyshop }) {
</Card> </Card>
</Col> </Col>
{/* Efficiency Over Period */} {/* Efficiency Over Period */}
<Col span={8} align="center"> <Col span={7} align="center">
<Card <Card
size="small" size="small"
title={t("scoreboard.labels.efficiencyoverperiod")} title={t("scoreboard.labels.efficiencyoverperiod")}
@@ -604,6 +604,40 @@ export function ScoreboardTicketsStats({ data, bodyshop }) {
</Row> </Row>
</Card> </Card>
</Col> </Col>
<Col span={3} align="center">
<Card
size="small"
title={t("scoreboard.labels.jobscompletednotinvoiced")}
>
<Row gutter={[16, 16]}>
<Col span={24}>
<Statistic
value={jobData.count}
valueStyle={{
fontSize: statisticSize,
fontWeight: statisticWeight,
}}
/>
</Col>
</Row>
<Row gutter={[16, 16]}>
<Col span={24}>
<Statistic
title={
<Typography.Text strong>
{t("scoreboard.labels.totalhrs")}
</Typography.Text>
}
value={jobData.tthrs}
valueStyle={{
fontSize: statisticSize,
fontWeight: statisticWeight,
}}
/>
</Col>
</Row>
</Card>
</Col>
</Row> </Row>
</Space> </Space>
{/* Disclaimer */} {/* Disclaimer */}

View File

@@ -65,6 +65,8 @@ export default function ScoreboardTimeTickets() {
end: endDate.format("YYYY-MM-DD"), end: endDate.format("YYYY-MM-DD"),
fixedStart: fixedPeriods.start.format("YYYY-MM-DD"), fixedStart: fixedPeriods.start.format("YYYY-MM-DD"),
fixedEnd: fixedPeriods.end.format("YYYY-MM-DD"), fixedEnd: fixedPeriods.end.format("YYYY-MM-DD"),
jobStart: startDate,
jobEnd: endDate,
}, },
fetchPolicy: "network-only", fetchPolicy: "network-only",
nextFetchPolicy: "network-only", nextFetchPolicy: "network-only",

View File

@@ -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) => (

View File

@@ -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>
); );

View File

@@ -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"]}

View File

@@ -28,18 +28,6 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
return ( return (
<RbacWrapper action="shop:rbac"> <RbacWrapper action="shop:rbac">
<LayoutFormRow> <LayoutFormRow>
<Form.Item
label={t("bodyshop.fields.rbac.accounting.payables")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "accounting:payables"]}
>
<InputNumber />
</Form.Item>
<Form.Item <Form.Item
label={t("bodyshop.fields.rbac.accounting.exportlog")} label={t("bodyshop.fields.rbac.accounting.exportlog")}
rules={[ rules={[
@@ -52,6 +40,18 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
> >
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.accounting.payables")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "accounting:payables"]}
>
<InputNumber />
</Form.Item>
<Form.Item <Form.Item
label={t("bodyshop.fields.rbac.accounting.payments")} label={t("bodyshop.fields.rbac.accounting.payments")}
rules={[ rules={[
@@ -77,26 +77,62 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t("bodyshop.fields.rbac.csi.page")} label={t("bodyshop.fields.rbac.bills.delete")}
rules={[ rules={[
{ {
required: true, required: true,
//message: t("general.validation.required"), //message: t("general.validation.required"),
}, },
]} ]}
name={["md_rbac", "csi:page"]} name={["md_rbac", "bills:delete"]}
> >
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t("bodyshop.fields.rbac.csi.export")} label={t("bodyshop.fields.rbac.bills.enter")}
rules={[ rules={[
{ {
required: true, required: true,
//message: t("general.validation.required"), //message: t("general.validation.required"),
}, },
]} ]}
name={["md_rbac", "csi:export"]} name={["md_rbac", "bills:enter"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.bills.list")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "bills:list"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.bills.reexport")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "bills:reexport"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.bills.view")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "bills:view"]}
> >
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
@@ -173,26 +209,38 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t("bodyshop.fields.rbac.jobs.list-active")} label={t("bodyshop.fields.rbac.csi.export")}
rules={[ rules={[
{ {
required: true, required: true,
//message: t("general.validation.required"), //message: t("general.validation.required"),
}, },
]} ]}
name={["md_rbac", "jobs:list-active"]} name={["md_rbac", "csi:export"]}
> >
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t("bodyshop.fields.rbac.jobs.list-ready")} label={t("bodyshop.fields.rbac.csi.page")}
rules={[ rules={[
{ {
required: true, required: true,
//message: t("general.validation.required"), //message: t("general.validation.required"),
}, },
]} ]}
name={["md_rbac", "jobs:list-ready"]} name={["md_rbac", "csi:page"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.employees.page")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "employees:page"]}
> >
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
@@ -208,30 +256,6 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
> >
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.jobs.partsqueue")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "jobs:partsqueue"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.jobs.list-all")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "jobs:list-all"]}
>
<InputNumber />
</Form.Item>
<Form.Item <Form.Item
label={t("bodyshop.fields.rbac.jobs.available-list")} label={t("bodyshop.fields.rbac.jobs.available-list")}
rules={[ rules={[
@@ -245,26 +269,14 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t("bodyshop.fields.rbac.jobs.create")} label={t("bodyshop.fields.rbac.jobs.checklist-view")}
rules={[ rules={[
{ {
required: true, required: true,
//message: t("general.validation.required"), //message: t("general.validation.required"),
}, },
]} ]}
name={["md_rbac", "jobs:create"]} name={["md_rbac", "jobs:checklist-view"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.jobs.intake")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "jobs:intake"]}
> >
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
@@ -280,6 +292,18 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
> >
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.jobs.create")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "jobs:create"]}
>
<InputNumber />
</Form.Item>
<Form.Item <Form.Item
label={t("bodyshop.fields.rbac.jobs.deliver")} label={t("bodyshop.fields.rbac.jobs.deliver")}
rules={[ rules={[
@@ -305,14 +329,62 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t("bodyshop.fields.rbac.jobs.checklist-view")} label={t("bodyshop.fields.rbac.jobs.intake")}
rules={[ rules={[
{ {
required: true, required: true,
//message: t("general.validation.required"), //message: t("general.validation.required"),
}, },
]} ]}
name={["md_rbac", "jobs:checklist-view"]} name={["md_rbac", "jobs:intake"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.jobs.list-active")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "jobs:list-active"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.jobs.list-all")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "jobs:list-all"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.jobs.list-ready")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "jobs:list-ready"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.jobs.partsqueue")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "jobs:partsqueue"]}
> >
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
@@ -329,86 +401,14 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t("bodyshop.fields.rbac.bills.enter")} label={t("bodyshop.fields.rbac.owners.detail")}
rules={[ rules={[
{ {
required: true, required: true,
//message: t("general.validation.required"), //message: t("general.validation.required"),
}, },
]} ]}
name={["md_rbac", "bills:enter"]} name={["md_rbac", "owners:detail"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.bills.delete")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "bills:delete"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.bills.reexport")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "bills:reexport"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.bills.view")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "bills:view"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.bills.list")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "bills:list"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.employees.page")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "employees:page"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.employee_teams.page")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "employee_teams:page"]}
> >
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
@@ -424,18 +424,6 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
> >
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.owners.detail")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "owners:detail"]}
>
<InputNumber />
</Form.Item>
<Form.Item <Form.Item
label={t("bodyshop.fields.rbac.payments.enter")} label={t("bodyshop.fields.rbac.payments.enter")}
rules={[ rules={[
@@ -460,6 +448,30 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
> >
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.phonebook.edit")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "phonebook:edit"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.phonebook.view")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "phonebook:view"]}
>
<InputNumber />
</Form.Item>
<Form.Item <Form.Item
label={t("bodyshop.fields.rbac.production.board")} label={t("bodyshop.fields.rbac.production.board")}
rules={[ rules={[
@@ -521,74 +533,14 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t("bodyshop.fields.rbac.timetickets.edit")} label={t("bodyshop.fields.rbac.shop.config")}
rules={[ rules={[
{ {
required: true, required: true,
//message: t("general.validation.required"), //message: t("general.validation.required"),
}, },
]} ]}
name={["md_rbac", "timetickets:edit"]} name={["md_rbac", "shop:config"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.timetickets.shiftedit")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "timetickets:shiftedit"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.timetickets.editcommitted")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "timetickets:editcommitted"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.ttapprovals.view")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "ttapprovals:view"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.ttapprovals.approve")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "ttapprovals:approve"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.shop.vendors")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "shop:vendors"]}
> >
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
@@ -604,18 +556,6 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
> >
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.shop.config")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "shop:config"]}
>
<InputNumber />
</Form.Item>
<Form.Item <Form.Item
label={t("bodyshop.fields.rbac.shop.rbac")} label={t("bodyshop.fields.rbac.shop.rbac")}
rules={[ rules={[
@@ -628,6 +568,18 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
> >
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.shop.reportcenter")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "shop:reportcenter"]}
>
<InputNumber />
</Form.Item>
<Form.Item <Form.Item
label={t("bodyshop.fields.rbac.shop.templates")} label={t("bodyshop.fields.rbac.shop.templates")}
rules={[ rules={[
@@ -640,6 +592,42 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
> >
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.shop.vendors")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "shop:vendors"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.temporarydocs.view")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "temporarydocs:view"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.timetickets.edit")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "timetickets:edit"]}
>
<InputNumber />
</Form.Item>
<Form.Item <Form.Item
label={t("bodyshop.fields.rbac.timetickets.enter")} label={t("bodyshop.fields.rbac.timetickets.enter")}
rules={[ rules={[
@@ -664,6 +652,18 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
> >
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.timetickets.shiftedit")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "timetickets:shiftedit"]}
>
<InputNumber />
</Form.Item>
<Form.Item <Form.Item
label={t("bodyshop.fields.rbac.users.editaccess")} label={t("bodyshop.fields.rbac.users.editaccess")}
rules={[ rules={[
@@ -676,42 +676,6 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
> >
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.temporarydocs.view")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "temporarydocs:view"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.phonebook.view")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "phonebook:view"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.phonebook.edit")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_rbac", "phonebook:edit"]}
>
<InputNumber />
</Form.Item>
{Simple_Inventory.treatment === "on" && ( {Simple_Inventory.treatment === "on" && (
<> <>
<Form.Item <Form.Item

View File

@@ -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")}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,12 +1,12 @@
import { LockOutlined, UserOutlined } from "@ant-design/icons"; import { 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

View File

@@ -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()}`
) )

View File

@@ -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

View File

@@ -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

View File

@@ -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}

View File

@@ -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>
);
}

View File

@@ -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,
},
},
],
},
];

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