+ {t("jobs.labels.reconciliation.removedpartsstrikethrough")}
+
+
+ );
}
diff --git a/client/src/components/job-reconciliation-totals/job-reconciliation-totals.component.jsx b/client/src/components/job-reconciliation-totals/job-reconciliation-totals.component.jsx
index 11330c5b9..1a6aeabfe 100644
--- a/client/src/components/job-reconciliation-totals/job-reconciliation-totals.component.jsx
+++ b/client/src/components/job-reconciliation-totals/job-reconciliation-totals.component.jsx
@@ -1,121 +1,118 @@
-import { Button, Space, Statistic } from "antd";
+import {Button, Space, Statistic} from "antd";
import Dinero from "dinero.js";
import _ from "lodash";
-import React, { useMemo, useState } from "react";
-import { useTranslation } from "react-i18next";
-import {
- reconcileByAssocLine,
- reconcileByPrice,
-} from "./job-reconciliation-totals.utility";
+import React, {useMemo, useState} from "react";
+import {useTranslation} from "react-i18next";
+import {reconcileByAssocLine, reconcileByPrice,} from "./job-reconciliation-totals.utility";
export default function JobReconciliationTotals({
- billLines,
- jobLines,
- jobLineState,
- billLineState,
-}) {
- const [errors, setErrors] = useState([]);
- const { t } = useTranslation();
- const selectedBillLines = billLineState[0];
- const selectedJobLines = jobLineState[0];
+ billLines,
+ jobLines,
+ jobLineState,
+ billLineState,
+ }) {
+ const [errors, setErrors] = useState([]);
+ const {t} = useTranslation();
+ const selectedBillLines = billLineState[0];
+ const selectedJobLines = jobLineState[0];
- const totals = useMemo(() => {
- const jlLookup = _.keyBy(selectedJobLines, (i) => i);
- const billLookup = _.keyBy(selectedBillLines, (i) => i);
+ const totals = useMemo(() => {
+ const jlLookup = _.keyBy(selectedJobLines, (i) => i);
+ const billLookup = _.keyBy(selectedBillLines, (i) => i);
- return {
- joblinesTotal: jobLines
- .filter((jl) => !!jlLookup[jl.id])
- .reduce((acc, val) => {
- return acc.add(
- Dinero({ amount: Math.round((val.act_price || 0) * 100) }).multiply(
- val.part_qty || 1
- )
- );
- }, Dinero()),
- billLinesTotal: billLines
- .filter((bl) => !!billLookup[bl.id])
- .reduce((acc, val) => {
- return acc.add(
- Dinero({
- amount: Math.round((val.actual_price || 0) * 100),
- })
- .multiply(val.quantity || 1)
- .multiply(val.bill.is_credit_memo ? -1 : 1)
- );
- }, Dinero()),
- };
- }, [billLines, jobLines, selectedBillLines, selectedJobLines]);
+ return {
+ joblinesTotal: jobLines
+ .filter((jl) => !!jlLookup[jl.id])
+ .reduce((acc, val) => {
+ return acc.add(
+ Dinero({amount: Math.round((val.act_price || 0) * 100)}).multiply(
+ val.part_qty || 1
+ )
+ );
+ }, Dinero()),
+ billLinesTotal: billLines
+ .filter((bl) => !!billLookup[bl.id])
+ .reduce((acc, val) => {
+ return acc.add(
+ Dinero({
+ amount: Math.round((val.actual_price || 0) * 100),
+ })
+ .multiply(val.quantity || 1)
+ .multiply(val.bill.is_credit_memo ? -1 : 1)
+ );
+ }, Dinero()),
+ };
+ }, [billLines, jobLines, selectedBillLines, selectedJobLines]);
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {errors.length > 0 && (
-
- {t("general.labels.errors")}
-
- {errors.map((error, idx) => (
- - {error}
- ))}
-
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {errors.length > 0 && (
+
+ {t("general.labels.errors")}
+
+ {errors.map((error, idx) => (
+ - {error}
+ ))}
+
+
+ )}
- )}
-
- );
+ );
}
diff --git a/client/src/components/job-reconciliation-totals/job-reconciliation-totals.utility.js b/client/src/components/job-reconciliation-totals/job-reconciliation-totals.utility.js
index 6a6e1a0f6..129188996 100644
--- a/client/src/components/job-reconciliation-totals/job-reconciliation-totals.utility.js
+++ b/client/src/components/job-reconciliation-totals/job-reconciliation-totals.utility.js
@@ -2,111 +2,111 @@ import i18next from "i18next";
import _ from "lodash";
export const reconcileByAssocLine = (
- jobLines,
- jobLineState,
- billLines,
- billLineState,
- setErrors
+ jobLines,
+ jobLineState,
+ billLines,
+ billLineState,
+ setErrors
) => {
- const [selectedBillLines, setSelectedBillLines] = billLineState;
- const [selectedJobLines, setSelectedJobLines] = jobLineState;
+ const [selectedBillLines, setSelectedBillLines] = billLineState;
+ const [selectedJobLines, setSelectedJobLines] = jobLineState;
- const allJoblinesFromBills = billLines
- .filter((bl) => bl.joblineid && bl.jobline && !bl.jobline.removed)
- .map((bl) => bl.joblineid);
+ const allJoblinesFromBills = billLines
+ .filter((bl) => bl.joblineid && bl.jobline && !bl.jobline.removed)
+ .map((bl) => bl.joblineid);
- const duplicatedJobLinesbyInvoiceId = _.filter(
- allJoblinesFromBills,
- (val, i, iteratee) => _.includes(iteratee, val, i + 1)
- );
+ const duplicatedJobLinesbyInvoiceId = _.filter(
+ allJoblinesFromBills,
+ (val, i, iteratee) => _.includes(iteratee, val, i + 1)
+ );
- if (duplicatedJobLinesbyInvoiceId.length > 0)
- setErrors((errors) => [
- ...errors,
- ..._.uniqBy(duplicatedJobLinesbyInvoiceId).map((dupedId) => {
- return i18next.t("jobs.labels.reconciliation.multiplebilllines", {
- line_desc: jobLines.find((j) => j.id === dupedId)?.line_desc,
- });
- }),
- ]);
+ if (duplicatedJobLinesbyInvoiceId.length > 0)
+ setErrors((errors) => [
+ ...errors,
+ ..._.uniqBy(duplicatedJobLinesbyInvoiceId).map((dupedId) => {
+ return i18next.t("jobs.labels.reconciliation.multiplebilllines", {
+ line_desc: jobLines.find((j) => j.id === dupedId)?.line_desc,
+ });
+ }),
+ ]);
- setSelectedBillLines(
- _.union(
- selectedBillLines,
- billLines.filter((bl) => !!bl.joblineid).map((bl) => bl.id)
- )
- );
+ setSelectedBillLines(
+ _.union(
+ selectedBillLines,
+ billLines.filter((bl) => !!bl.joblineid).map((bl) => bl.id)
+ )
+ );
- setSelectedJobLines(
- _.union(selectedJobLines, _.uniqBy(allJoblinesFromBills))
- );
+ setSelectedJobLines(
+ _.union(selectedJobLines, _.uniqBy(allJoblinesFromBills))
+ );
};
export const reconcileByPrice = (
- jobLines,
- jobLineState,
- billLines,
- billLineState,
- setErrors
+ jobLines,
+ jobLineState,
+ billLines,
+ billLineState,
+ setErrors
) => {
- const [selectedBillLines, setSelectedBillLines] = billLineState;
- const [selectedJobLines, setSelectedJobLines] = jobLineState;
+ const [selectedBillLines, setSelectedBillLines] = billLineState;
+ const [selectedJobLines, setSelectedJobLines] = jobLineState;
- const allActPricesFromJobs = jobLines.map((jl) => jl.act_price);
- const duplicateActPrices = _.filter(
- allActPricesFromJobs,
- (val, i, iteratee) => _.includes(iteratee, val, i + 1)
- );
+ const allActPricesFromJobs = jobLines.map((jl) => jl.act_price);
+ const duplicateActPrices = _.filter(
+ allActPricesFromJobs,
+ (val, i, iteratee) => _.includes(iteratee, val, i + 1)
+ );
+
+ if (duplicateActPrices.length > 0)
+ setErrors((errors) => [
+ ...errors,
+ ..._.uniqBy(duplicateActPrices).map((dupeAp) =>
+ i18next.t("jobs.labels.reconciliation.multipleactprices", {
+ act_price: dupeAp,
+ })
+ ),
+ ]);
+
+ const foundJobLines = [];
+ var foundBillLines = [];
+ const actPricesWithMoreThan1MatchingBill = [];
+
+ jobLines.forEach((jl) => {
+ const matchingBillLineIds = billLines
+ .filter(
+ (bl) =>
+ bl.actual_price === jl.act_price &&
+ bl.quantity === jl.part_qty &&
+ !jl.removed
+ )
+ .map((bl) => bl.id);
+
+ if (matchingBillLineIds.length > 1) {
+ actPricesWithMoreThan1MatchingBill.push(jl.act_price);
+ }
+
+ foundBillLines = [...foundBillLines, ...matchingBillLineIds];
+ if (matchingBillLineIds.length > 0) {
+ foundJobLines.push(jl.id);
+ }
+ });
- if (duplicateActPrices.length > 0)
setErrors((errors) => [
- ...errors,
- ..._.uniqBy(duplicateActPrices).map((dupeAp) =>
- i18next.t("jobs.labels.reconciliation.multipleactprices", {
- act_price: dupeAp,
- })
- ),
+ ...errors,
+ ..._.uniqBy(duplicateActPrices).map((dupeAp) =>
+ i18next.t("jobs.labels.reconciliation.multipleactprices", {
+ act_price: dupeAp,
+ })
+ ),
+ ..._.uniqBy(actPricesWithMoreThan1MatchingBill).map((act_price) =>
+ i18next.t("jobs.labels.reconciliation.multiplebillsforactprice", {
+ act_price: act_price,
+ })
+ ),
]);
- const foundJobLines = [];
- var foundBillLines = [];
- const actPricesWithMoreThan1MatchingBill = [];
+ setSelectedBillLines(_.union(selectedBillLines, _.uniqBy(foundBillLines)));
- jobLines.forEach((jl) => {
- const matchingBillLineIds = billLines
- .filter(
- (bl) =>
- bl.actual_price === jl.act_price &&
- bl.quantity === jl.part_qty &&
- !jl.removed
- )
- .map((bl) => bl.id);
-
- if (matchingBillLineIds.length > 1) {
- actPricesWithMoreThan1MatchingBill.push(jl.act_price);
- }
-
- foundBillLines = [...foundBillLines, ...matchingBillLineIds];
- if (matchingBillLineIds.length > 0) {
- foundJobLines.push(jl.id);
- }
- });
-
- setErrors((errors) => [
- ...errors,
- ..._.uniqBy(duplicateActPrices).map((dupeAp) =>
- i18next.t("jobs.labels.reconciliation.multipleactprices", {
- act_price: dupeAp,
- })
- ),
- ..._.uniqBy(actPricesWithMoreThan1MatchingBill).map((act_price) =>
- i18next.t("jobs.labels.reconciliation.multiplebillsforactprice", {
- act_price: act_price,
- })
- ),
- ]);
-
- setSelectedBillLines(_.union(selectedBillLines, _.uniqBy(foundBillLines)));
-
- setSelectedJobLines(_.union(selectedJobLines, _.uniqBy(foundJobLines)));
+ setSelectedJobLines(_.union(selectedJobLines, _.uniqBy(foundJobLines)));
};
diff --git a/client/src/components/job-remove-from-parst-queue/job-remove-from-parts-queue.component.jsx b/client/src/components/job-remove-from-parst-queue/job-remove-from-parts-queue.component.jsx
index a0c95fad8..f7dd7b00b 100644
--- a/client/src/components/job-remove-from-parst-queue/job-remove-from-parts-queue.component.jsx
+++ b/client/src/components/job-remove-from-parst-queue/job-remove-from-parts-queue.component.jsx
@@ -1,37 +1,37 @@
-import { useMutation } from "@apollo/client";
-import { Checkbox, notification, Space, Spin } from "antd";
-import React, { useState } from "react";
-import { useTranslation } from "react-i18next";
-import { UPDATE_JOB } from "../../graphql/jobs.queries";
+import {useMutation} from "@apollo/client";
+import {Checkbox, notification, Space, Spin} from "antd";
+import React, {useState} from "react";
+import {useTranslation} from "react-i18next";
+import {UPDATE_JOB} from "../../graphql/jobs.queries";
-export default function JobRemoveFromPartsQueue({ checked, jobId }) {
- const [updateJob] = useMutation(UPDATE_JOB);
- const { t } = useTranslation();
+export default function JobRemoveFromPartsQueue({checked, jobId}) {
+ const [updateJob] = useMutation(UPDATE_JOB);
+ const {t} = useTranslation();
- const [loading, setLoading] = useState(false);
+ const [loading, setLoading] = useState(false);
- const handleChange = async (e) => {
- setLoading(true);
- const result = await updateJob({
- variables: { jobId: jobId, job: { queued_for_parts: e.target.checked } },
- });
+ const handleChange = async (e) => {
+ setLoading(true);
+ const result = await updateJob({
+ variables: {jobId: jobId, job: {queued_for_parts: e.target.checked}},
+ });
- if (!!!result.errors) {
- notification["success"]({ message: t("jobs.successes.save") });
- } else {
- notification["error"]({
- message: t("jobs.errors.saving", {
- error: JSON.stringify(result.errors),
- }),
- });
- }
- setLoading(false);
- };
+ if (!!!result.errors) {
+ notification["success"]({message: t("jobs.successes.save")});
+ } else {
+ notification["error"]({
+ message: t("jobs.errors.saving", {
+ error: JSON.stringify(result.errors),
+ }),
+ });
+ }
+ setLoading(false);
+ };
- return (
-
-
- {loading && }
-
- );
+ return (
+
+
+ {loading && }
+
+ );
}
diff --git a/client/src/components/job-scoreboard-add-button/job-scoreboard-add-button.component.jsx b/client/src/components/job-scoreboard-add-button/job-scoreboard-add-button.component.jsx
index 0e1343438..5287c3271 100644
--- a/client/src/components/job-scoreboard-add-button/job-scoreboard-add-button.component.jsx
+++ b/client/src/components/job-scoreboard-add-button/job-scoreboard-add-button.component.jsx
@@ -1,200 +1,192 @@
-import { useMutation, useLazyQuery } from "@apollo/client";
-import { CheckCircleOutlined } from "@ant-design/icons";
+import {useLazyQuery, useMutation} from "@apollo/client";
+import {CheckCircleOutlined} from "@ant-design/icons";
+import {Button, Card, Form, InputNumber, notification, Popover, Space,} from "antd";
+import dayjs from "../../utils/day";
+import React, {useEffect, useState} from "react";
+import {useTranslation} from "react-i18next";
+import {logImEXEvent} from "../../firebase/firebase.utils";
import {
- Button,
- Card,
- Form,
- InputNumber,
- notification,
- Popover,
- Space,
-} from "antd";
-import moment from "moment";
-import React, { useState, useEffect } from "react";
-import { useTranslation } from "react-i18next";
-import { logImEXEvent } from "../../firebase/firebase.utils";
-import {
- INSERT_SCOREBOARD_ENTRY,
- QUERY_SCOREBOARD_ENTRY,
- UPDATE_SCOREBOARD_ENTRY,
+ INSERT_SCOREBOARD_ENTRY,
+ QUERY_SCOREBOARD_ENTRY,
+ UPDATE_SCOREBOARD_ENTRY,
} from "../../graphql/scoreboard.queries";
import FormDatePicker from "../form-date-picker/form-date-picker.component";
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
export default function ScoreboardAddButton({
- job,
- disabled,
- ...otherBtnProps
-}) {
- const { t } = useTranslation();
- const [insertScoreboardEntry] = useMutation(INSERT_SCOREBOARD_ENTRY);
- const [updateScoreboardEntry] = useMutation(UPDATE_SCOREBOARD_ENTRY);
- const [loading, setLoading] = useState(false);
- const [form] = Form.useForm();
- const [visibility, setVisibility] = useState(false);
- const [callQuery, { loading: entryLoading, data: entryData }] = useLazyQuery(
- QUERY_SCOREBOARD_ENTRY
- );
-
- useEffect(() => {
- if (visibility) {
- callQuery({ variables: { jobid: job.id } });
- }
- }, [visibility, job.id, callQuery]);
-
- useEffect(() => {
- if (entryData && entryData.scoreboard && entryData.scoreboard[0]) {
- form.setFieldsValue(entryData.scoreboard[0]);
- }
- }, [entryData, form]);
-
- const handleFinish = async (values) => {
- logImEXEvent("job_close_add_to_scoreboard");
-
- setLoading(true);
- let result;
-
- if (entryData && entryData.scoreboard && entryData.scoreboard[0]) {
- result = await updateScoreboardEntry({
- variables: {
- sbId: entryData.scoreboard[0].id,
- sbInput: values,
- },
- });
- } else {
- result = await insertScoreboardEntry({
- variables: { sbInput: [{ jobid: job.id, ...values }] },
- });
- }
-
- if (!!result.errors) {
- notification["error"]({
- message: t("scoreboard.errors.adding", {
- message: JSON.stringify(result.errors),
- }),
- });
- } else {
- notification["success"]({
- message: t("scoreboard.successes.added"),
- });
- }
- setLoading(false);
- setVisibility(false);
- };
-
- const overlay = (
-
-
- {entryLoading ? (
-
- ) : (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- )}
-
- {entryData && entryData.scoreboard && entryData.scoreboard[0] && (
-
-
- {t("jobs.labels.alreadyaddedtoscoreboard")}
-
- )}
-
- );
-
- const handleClick = (e) => {
- setLoading(true);
- const v = job.joblines.reduce(
- (acc, val) => {
- if (val.mod_lbr_ty !== "LAR")
- acc = { ...acc, bodyhrs: acc.bodyhrs + val.mod_lb_hrs };
- if (val.mod_lbr_ty === "LAR")
- acc = { ...acc, painthrs: acc.painthrs + val.mod_lb_hrs };
- return acc;
- },
- {
- bodyhrs: 0,
- painthrs: 0,
- }
+ job,
+ disabled,
+ ...otherBtnProps
+ }) {
+ const {t} = useTranslation();
+ const [insertScoreboardEntry] = useMutation(INSERT_SCOREBOARD_ENTRY);
+ const [updateScoreboardEntry] = useMutation(UPDATE_SCOREBOARD_ENTRY);
+ const [loading, setLoading] = useState(false);
+ const [form] = Form.useForm();
+ const [visibility, setVisibility] = useState(false);
+ const [callQuery, {loading: entryLoading, data: entryData}] = useLazyQuery(
+ QUERY_SCOREBOARD_ENTRY
);
- //Add Labor Adjustments
- v.painthrs = v.painthrs + (job.lbr_adjustments.LAR || 0);
- v.bodyhrs =
- v.bodyhrs +
- Object.keys(job.lbr_adjustments)
- .filter((key) => key !== "LAR")
- .reduce((acc, val) => {
- return acc + job.lbr_adjustments[val];
- }, 0);
- form.setFieldsValue({
- date: new moment(),
- bodyhrs: Math.round(v.bodyhrs * 10) / 10,
- painthrs: Math.round(v.painthrs * 10) / 10,
- });
- setVisibility(true);
- setLoading(false);
- };
+ useEffect(() => {
+ if (visibility) {
+ callQuery({variables: {jobid: job.id}});
+ }
+ }, [visibility, job.id, callQuery]);
- return (
-
-
-
- );
+ useEffect(() => {
+ if (entryData && entryData.scoreboard && entryData.scoreboard[0]) {
+ form.setFieldsValue(entryData.scoreboard[0]);
+ }
+ }, [entryData, form]);
+
+ const handleFinish = async (values) => {
+ logImEXEvent("job_close_add_to_scoreboard");
+
+ setLoading(true);
+ let result;
+
+ if (entryData && entryData.scoreboard && entryData.scoreboard[0]) {
+ result = await updateScoreboardEntry({
+ variables: {
+ sbId: entryData.scoreboard[0].id,
+ sbInput: values,
+ },
+ });
+ } else {
+ result = await insertScoreboardEntry({
+ variables: {sbInput: [{jobid: job.id, ...values}]},
+ });
+ }
+
+ if (!!result.errors) {
+ notification["error"]({
+ message: t("scoreboard.errors.adding", {
+ message: JSON.stringify(result.errors),
+ }),
+ });
+ } else {
+ notification["success"]({
+ message: t("scoreboard.successes.added"),
+ });
+ }
+ setLoading(false);
+ setVisibility(false);
+ };
+
+ const overlay = (
+
+
+ {entryLoading ? (
+
+ ) : (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )}
+
+ {entryData && entryData.scoreboard && entryData.scoreboard[0] && (
+
+
+ {t("jobs.labels.alreadyaddedtoscoreboard")}
+
+ )}
+
+ );
+
+ const handleClick = (e) => {
+ setLoading(true);
+ const v = job.joblines.reduce(
+ (acc, val) => {
+ if (val.mod_lbr_ty !== "LAR")
+ acc = {...acc, bodyhrs: acc.bodyhrs + val.mod_lb_hrs};
+ if (val.mod_lbr_ty === "LAR")
+ acc = {...acc, painthrs: acc.painthrs + val.mod_lb_hrs};
+ return acc;
+ },
+ {
+ bodyhrs: 0,
+ painthrs: 0,
+ }
+ );
+
+ //Add Labor Adjustments
+ v.painthrs = v.painthrs + (job.lbr_adjustments.LAR || 0);
+ v.bodyhrs =
+ v.bodyhrs +
+ Object.keys(job.lbr_adjustments)
+ .filter((key) => key !== "LAR")
+ .reduce((acc, val) => {
+ return acc + job.lbr_adjustments[val];
+ }, 0);
+ form.setFieldsValue({
+ date: new dayjs(),
+ bodyhrs: Math.round(v.bodyhrs * 10) / 10,
+ painthrs: Math.round(v.painthrs * 10) / 10,
+ });
+ setVisibility(true);
+ setLoading(false);
+ };
+
+ return (
+
+
+
+ );
}
diff --git a/client/src/components/job-search-select/job-search-select.component.jsx b/client/src/components/job-search-select/job-search-select.component.jsx
index 0ec418bca..59f96d7a3 100644
--- a/client/src/components/job-search-select/job-search-select.component.jsx
+++ b/client/src/components/job-search-select/job-search-select.component.jsx
@@ -1,118 +1,116 @@
-import { useLazyQuery } from "@apollo/client";
-import { Select, Space, Tag } from "antd";
+import {useLazyQuery} from "@apollo/client";
+import {Select, Space, Tag} from "antd";
import _ from "lodash";
-import React, { forwardRef, useState, useEffect } from "react";
-import { useTranslation } from "react-i18next";
-import {
- SEARCH_JOBS_BY_ID_FOR_AUTOCOMPLETE,
- SEARCH_JOBS_FOR_AUTOCOMPLETE,
-} from "../../graphql/jobs.queries";
+import React, {forwardRef, useEffect, useState} from "react";
+import {useTranslation} from "react-i18next";
+import {SEARCH_JOBS_BY_ID_FOR_AUTOCOMPLETE, SEARCH_JOBS_FOR_AUTOCOMPLETE,} from "../../graphql/jobs.queries";
import AlertComponent from "../alert/alert.component";
-import { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
-const { Option } = Select;
+import {OwnerNameDisplayFunction} from "../owner-name-display/owner-name-display.component";
+
+const {Option} = Select;
const JobSearchSelect = (
- {
- disabled,
- convertedOnly = false,
- notInvoiced = false,
- notExported = true,
- clm_no = false,
- ...restProps
- },
- ref
+ {
+ disabled,
+ convertedOnly = false,
+ notInvoiced = false,
+ notExported = true,
+ clm_no = false,
+ ...restProps
+ },
+ ref
) => {
- const { t } = useTranslation();
- const [theOptions, setTheOptions] = useState([]);
- const [callSearch, { loading, error, data }] = useLazyQuery(
- SEARCH_JOBS_FOR_AUTOCOMPLETE,
- {}
- );
-
- const [callIdSearch, { loading: idLoading, error: idError, data: idData }] =
- useLazyQuery(SEARCH_JOBS_BY_ID_FOR_AUTOCOMPLETE);
-
- const executeSearch = (v) => {
- console.log(v);
- if (v && v.variables?.search !== "" && v.variables.search.length >= 2)
- callSearch(v);
- };
- const debouncedExecuteSearch = _.debounce(executeSearch, 500);
-
- const handleSearch = (value) => {
- debouncedExecuteSearch({
- variables: {
- search: value,
- ...(convertedOnly || notExported
- ? {
- ...(convertedOnly ? { isConverted: true } : {}),
- ...(notExported ? { notExported: true } : {}),
- ...(notInvoiced ? { notInvoiced: true } : {}),
- }
- : {}),
- },
- });
- };
-
- useEffect(() => {
- if (restProps.value) {
- callIdSearch({ variables: { id: restProps.value } }); // Sometimes results in a no-op. Not sure how to fix.
- }
- }, [restProps.value, callIdSearch]);
-
- useEffect(() => {
- setTheOptions(
- _.uniqBy(
- [
- ...(idData && idData.jobs_by_pk ? [idData.jobs_by_pk] : []),
- ...(data && data.search_jobs ? data.search_jobs : []),
- ],
- "id"
- )
+ const {t} = useTranslation();
+ const [theOptions, setTheOptions] = useState([]);
+ const [callSearch, {loading, error, data}] = useLazyQuery(
+ SEARCH_JOBS_FOR_AUTOCOMPLETE,
+ {}
);
- }, [data, idData]);
- return (
-
-
:
}
- {...restProps}
- >
- {theOptions
- ? theOptions.map((o) => (
-
+ ))
+ : null}
+
+ {error ?
: null}
+ {idError ? (
+
+ ) : null}
+
+ );
};
export default forwardRef(JobSearchSelect);
diff --git a/client/src/components/job-send-parts-price-change/job-send-parts-price-change.component.jsx b/client/src/components/job-send-parts-price-change/job-send-parts-price-change.component.jsx
index 04609f98b..7f218520c 100644
--- a/client/src/components/job-send-parts-price-change/job-send-parts-price-change.component.jsx
+++ b/client/src/components/job-send-parts-price-change/job-send-parts-price-change.component.jsx
@@ -1,31 +1,31 @@
-import { Button, notification } from "antd";
+import {Button, notification} from "antd";
import axios from "axios";
-import React, { useState } from "react";
-import { useTranslation } from "react-i18next";
+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);
- }
- };
+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 (
-
- );
+ return (
+
+ );
}
diff --git a/client/src/components/job-sync-button/job-sync-button.component.jsx b/client/src/components/job-sync-button/job-sync-button.component.jsx
index 042664c49..08c294b1f 100644
--- a/client/src/components/job-sync-button/job-sync-button.component.jsx
+++ b/client/src/components/job-sync-button/job-sync-button.component.jsx
@@ -1,23 +1,23 @@
-import { Button } from "antd";
+import {Button} from "antd";
import React from "react";
-import { useTranslation } from "react-i18next";
-import { SyncOutlined } from "@ant-design/icons";
-import { useHistory } from "react-router-dom";
+import {useTranslation} from "react-i18next";
+import {SyncOutlined} from "@ant-design/icons";
+import {useNavigate} from "react-router-dom";
-export default function JobSyncButton({ job }) {
- const { t } = useTranslation();
- const history = useHistory();
- const handleClick = () => {
- history.push(
- `/manage/available?availableJobId=${job.available_jobs[0].id}&clm_no=${job.clm_no}`
- );
- };
- if (job && job.available_jobs && job.available_jobs.length > 0)
- return (
-
- );
- else return null;
+export default function JobSyncButton({job}) {
+ const {t} = useTranslation();
+ const history = useNavigate();
+ const handleClick = () => {
+ history(
+ `/manage/available?availableJobId=${job.available_jobs[0].id}&clm_no=${job.clm_no}`
+ );
+ };
+ if (job && job.available_jobs && job.available_jobs.length > 0)
+ return (
+
+ );
+ else return null;
}
diff --git a/client/src/components/job-totals-table/job-totals-table.component.jsx b/client/src/components/job-totals-table/job-totals-table.component.jsx
index 49536ce22..f56322c75 100644
--- a/client/src/components/job-totals-table/job-totals-table.component.jsx
+++ b/client/src/components/job-totals-table/job-totals-table.component.jsx
@@ -1,12 +1,12 @@
-import { Card, Col, Collapse, Result, Row } from "antd";
+import {Card, Col, Collapse, Result, Row} from "antd";
//import { JsonEditor as Editor } from "jsoneditor-react";
//import "jsoneditor-react/es/editor.min.css";
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 { selectCurrentUser } from "../../redux/user/user.selectors";
+import {useTranslation} from "react-i18next";
+import {connect} from "react-redux";
+import {createStructuredSelector} from "reselect";
+import {selectJobReadOnly} from "../../redux/application/application.selectors";
+import {selectCurrentUser} from "../../redux/user/user.selectors";
import JobCalculateTotals from "../job-calculate-totals/job-calculate-totals.component";
import "./job-totals-table.styles.scss";
import JobTotalsTableLabor from "./job-totals.table.labor.component";
@@ -15,87 +15,88 @@ import JobTotalsTableParts from "./job-totals.table.parts.component";
import JobTotalsTableTotals from "./job-totals.table.totals.component";
const mapStateToProps = createStructuredSelector({
- currentUser: selectCurrentUser,
- jobRO: selectJobReadOnly,
+ currentUser: selectCurrentUser,
+ jobRO: selectJobReadOnly,
});
const colSpan = {
- md: { span: 24 },
- lg: { span: 12 },
+ md: {span: 24},
+ lg: {span: 12},
};
-export function JobsTotalsTableComponent({ jobRO, currentUser, job }) {
- const { t } = useTranslation();
+export function JobsTotalsTableComponent({jobRO, currentUser, job}) {
+ const {t} = useTranslation();
+
+ if (!!!job.job_totals) {
+ return (
+
+ }
+ />
+
+ );
+ }
- if (!!!job.job_totals) {
return (
-
- }
- />
-
- );
- }
-
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
- {(currentUser.email.includes("@imex.") ||
- currentUser.email.includes("@rome.")) && (
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {(currentUser.email.includes("@imex.") ||
+ currentUser.email.includes("@rome.")) && (
+
+
+
+
+
+
{JSON.stringify(
- {
- CIECA: job.cieca_ttl && job.cieca_ttl.data,
- CIECASTL: job.cieca_stl && job.cieca_stl.data,
- ImEXCalc: job.job_totals,
- },
- null,
- 2
+ {
+ CIECA: job.cieca_ttl && job.cieca_ttl.data,
+ CIECASTL: job.cieca_stl && job.cieca_stl.data,
+ ImEXCalc: job.job_totals,
+ },
+ null,
+ 2
)}
-
-
-
-
-
- )}
-
-
-
-
- );
+
+
+
+
+
+ )}
+
+
+
+
+ );
}
+
export default connect(mapStateToProps, null)(JobsTotalsTableComponent);
diff --git a/client/src/components/job-totals-table/job-totals.table.labor.component.jsx b/client/src/components/job-totals-table/job-totals.table.labor.component.jsx
index 42cfe7c66..bb92988a7 100644
--- a/client/src/components/job-totals-table/job-totals.table.labor.component.jsx
+++ b/client/src/components/job-totals-table/job-totals.table.labor.component.jsx
@@ -1,185 +1,185 @@
-import { Space, Table } from "antd";
+import {Space, Table} from "antd";
import Dinero from "dinero.js";
-import React, { useMemo, useState } from "react";
-import { useTranslation } from "react-i18next";
+import React, {useMemo, useState} from "react";
+import {useTranslation} from "react-i18next";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
-import { alphaSort } from "../../utils/sorters";
+import {alphaSort} from "../../utils/sorters";
-export default function JobTotalsTableLabor({ job }) {
- const { t } = useTranslation();
- const [state, setState] = useState({
- sortedInfo: {
- columnKey: "profitcenter_labor",
- field: "profitcenter_labor",
- order: "ascend",
- },
- filteredInfo: {},
- });
+export default function JobTotalsTableLabor({job}) {
+ const {t} = useTranslation();
+ const [state, setState] = useState({
+ sortedInfo: {
+ columnKey: "profitcenter_labor",
+ field: "profitcenter_labor",
+ order: "ascend",
+ },
+ filteredInfo: {},
+ });
- const data = useMemo(() => {
- return Object.keys(job.job_totals.rates)
- .filter(
- (key) =>
- key !== "mapa" &&
- key !== "mash" &&
- key !== "subtotal" &&
- key !== "rates_subtotal"
- )
- .map((key) => {
- return {
- id: key,
- ...job.job_totals.rates[key],
- };
- });
- }, [job.job_totals.rates]);
+ const data = useMemo(() => {
+ return Object.keys(job.job_totals.rates)
+ .filter(
+ (key) =>
+ key !== "mapa" &&
+ key !== "mash" &&
+ key !== "subtotal" &&
+ key !== "rates_subtotal"
+ )
+ .map((key) => {
+ return {
+ id: key,
+ ...job.job_totals.rates[key],
+ };
+ });
+ }, [job.job_totals.rates]);
- const columns = [
- {
- title: t("joblines.fields.profitcenter_labor"),
- dataIndex: "profitcenter_labor",
- key: "profitcenter_labor",
- defaultSortOrder: "ascend",
- sorter: (a, b) =>
- alphaSort(
- t(`jobs.fields.rate_${a.id.toLowerCase()}`),
- t(`jobs.fields.rate_${b.id.toLowerCase()}`)
- ),
- sortOrder:
- state.sortedInfo.columnKey === "profitcenter_labor" &&
- state.sortedInfo.order,
- render: (text, record) =>
- t(`jobs.fields.rate_${record.id.toLowerCase()}`),
- },
- {
- title: t("jobs.labels.rates"),
- dataIndex: "rate",
- key: "rate",
- align: "right",
- sorter: (a, b) => a.rate - b.rate,
- sortOrder:
- state.sortedInfo.columnKey === "rate" && state.sortedInfo.order,
- render: (text, record) => (
-
{record.rate}
- ),
- },
- {
- title: t("joblines.fields.mod_lb_hrs"),
- dataIndex: "mod_lb_hrs",
+ const columns = [
+ {
+ title: t("joblines.fields.profitcenter_labor"),
+ dataIndex: "profitcenter_labor",
+ key: "profitcenter_labor",
+ defaultSortOrder: "ascend",
+ sorter: (a, b) =>
+ alphaSort(
+ t(`jobs.fields.rate_${a.id.toLowerCase()}`),
+ t(`jobs.fields.rate_${b.id.toLowerCase()}`)
+ ),
+ sortOrder:
+ state.sortedInfo.columnKey === "profitcenter_labor" &&
+ state.sortedInfo.order,
+ render: (text, record) =>
+ t(`jobs.fields.rate_${record.id.toLowerCase()}`),
+ },
+ {
+ title: t("jobs.labels.rates"),
+ dataIndex: "rate",
+ key: "rate",
+ align: "right",
+ sorter: (a, b) => a.rate - b.rate,
+ sortOrder:
+ state.sortedInfo.columnKey === "rate" && state.sortedInfo.order,
+ render: (text, record) => (
+
{record.rate}
+ ),
+ },
+ {
+ title: t("joblines.fields.mod_lb_hrs"),
+ dataIndex: "mod_lb_hrs",
- key: "mod_lb_hrs",
- sorter: (a, b) => a.mod_lb_hrs - b.mod_lb_hrs,
- sortOrder:
- state.sortedInfo.columnKey === "mod_lb_hrs" && state.sortedInfo.order,
+ key: "mod_lb_hrs",
+ sorter: (a, b) => a.mod_lb_hrs - b.mod_lb_hrs,
+ sortOrder:
+ state.sortedInfo.columnKey === "mod_lb_hrs" && state.sortedInfo.order,
- render: (text, record) => record.hours.toFixed(1),
- },
- {
- title: t("joblines.fields.total"),
- dataIndex: "total",
- key: "total",
- align: "right",
- sorter: (a, b) => a.total.amount - b.total.amount,
- sortOrder:
- state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
+ render: (text, record) => record.hours.toFixed(1),
+ },
+ {
+ title: t("joblines.fields.total"),
+ dataIndex: "total",
+ key: "total",
+ align: "right",
+ sorter: (a, b) => a.total.amount - b.total.amount,
+ sortOrder:
+ state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
- render: (text, record) => Dinero(record.total).toFormat(),
- },
- ];
+ render: (text, record) => Dinero(record.total).toFormat(),
+ },
+ ];
- const handleTableChange = (pagination, filters, sorter) => {
- setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
- };
- return (
-
(
- <>
-
-
- {t("jobs.labels.labor_rates_subtotal")}
-
-
-
- {(
- job.job_totals.rates.mapa.hours +
- job.job_totals.rates.mash.hours
- ).toFixed(1)}
-
-
-
- {Dinero(job.job_totals.rates.rates_subtotal).toFormat()}
-
-
-
-
-
-
- {t("jobs.labels.mapa")}
- {job.materials &&
- job.materials.MAPA &&
- job.materials.MAPA.cal_maxdlr !== undefined &&
- t("jobs.labels.threshhold", {
- amount: job.materials.MAPA.cal_maxdlr,
- })}
-
-
-
-
- {job.job_totals.rates.mapa.rate}
-
-
-
- {job.job_totals.rates.mapa.hours.toFixed(1)}
-
-
- {Dinero(job.job_totals.rates.mapa.total).toFormat()}
-
-
-
-
-
- {t("jobs.labels.mash")}
- {job.materials &&
- job.materials.MASH &&
- job.materials.MASH.cal_maxdlr !== undefined &&
- t("jobs.labels.threshhold", {
- amount: job.materials.MASH.cal_maxdlr,
- })}
-
-
-
-
- {job.job_totals.rates.mash.rate}
-
-
-
- {job.job_totals.rates.mash.hours.toFixed(1)}
-
-
- {Dinero(job.job_totals.rates.mash.total).toFormat()}
-
-
-
-
- {t("jobs.labels.rates_subtotal")}
-
-
-
-
-
- {Dinero(job.job_totals.rates.subtotal).toFormat()}
-
-
-
- >
- )}
- />
- );
+ const handleTableChange = (pagination, filters, sorter) => {
+ setState({...state, filteredInfo: filters, sortedInfo: sorter});
+ };
+ return (
+ (
+ <>
+
+
+ {t("jobs.labels.labor_rates_subtotal")}
+
+
+
+ {(
+ job.job_totals.rates.mapa.hours +
+ job.job_totals.rates.mash.hours
+ ).toFixed(1)}
+
+
+
+ {Dinero(job.job_totals.rates.rates_subtotal).toFormat()}
+
+
+
+
+
+
+ {t("jobs.labels.mapa")}
+ {job.materials &&
+ job.materials.MAPA &&
+ job.materials.MAPA.cal_maxdlr !== undefined &&
+ t("jobs.labels.threshhold", {
+ amount: job.materials.MAPA.cal_maxdlr,
+ })}
+
+
+
+
+ {job.job_totals.rates.mapa.rate}
+
+
+
+ {job.job_totals.rates.mapa.hours.toFixed(1)}
+
+
+ {Dinero(job.job_totals.rates.mapa.total).toFormat()}
+
+
+
+
+
+ {t("jobs.labels.mash")}
+ {job.materials &&
+ job.materials.MASH &&
+ job.materials.MASH.cal_maxdlr !== undefined &&
+ t("jobs.labels.threshhold", {
+ amount: job.materials.MASH.cal_maxdlr,
+ })}
+
+
+
+
+ {job.job_totals.rates.mash.rate}
+
+
+
+ {job.job_totals.rates.mash.hours.toFixed(1)}
+
+
+ {Dinero(job.job_totals.rates.mash.total).toFormat()}
+
+
+
+
+ {t("jobs.labels.rates_subtotal")}
+
+
+
+
+
+ {Dinero(job.job_totals.rates.subtotal).toFormat()}
+
+
+
+ >
+ )}
+ />
+ );
}
diff --git a/client/src/components/job-totals-table/job-totals.table.other.component.jsx b/client/src/components/job-totals-table/job-totals.table.other.component.jsx
index ac132f1a6..3fed60af3 100644
--- a/client/src/components/job-totals-table/job-totals.table.other.component.jsx
+++ b/client/src/components/job-totals-table/job-totals.table.other.component.jsx
@@ -1,106 +1,106 @@
-import { Table } from "antd";
+import {Table} from "antd";
import Dinero from "dinero.js";
-import React, { useMemo, useState } from "react";
-import { useTranslation } from "react-i18next";
-import { alphaSort } from "../../utils/sorters";
+import React, {useMemo, useState} from "react";
+import {useTranslation} from "react-i18next";
+import {alphaSort} from "../../utils/sorters";
-export default function JobTotalsTableOther({ job }) {
- const { t } = useTranslation();
- const [state, setState] = useState({
- sortedInfo: {},
- filteredInfo: {},
- });
+export default function JobTotalsTableOther({job}) {
+ const {t} = useTranslation();
+ const [state, setState] = useState({
+ sortedInfo: {},
+ filteredInfo: {},
+ });
- const data = useMemo(() => {
- return [
- ...((job.job_totals.additional.additionalCostItems &&
- job.job_totals.additional.additionalCostItems.map((i) => {
- return {
- key: i.key,
- total: i.total,
- };
- })) ||
- []),
- {
- key: t("jobs.fields.adjustment_bottom_line"),
- total: job.job_totals.additional.adjustments,
- },
- {
- key: t("jobs.fields.towing_payable"),
- total: job.job_totals.additional.towing,
- },
- {
- key: t("jobs.fields.storage_payable"),
- total: job.job_totals.additional.storage,
- },
- // {
- // key: t("jobs.fields.ca_bc_pvrt"),
- // total: job.job_totals.additional.pvrt,
- // },
+ const data = useMemo(() => {
+ return [
+ ...((job.job_totals.additional.additionalCostItems &&
+ job.job_totals.additional.additionalCostItems.map((i) => {
+ return {
+ key: i.key,
+ total: i.total,
+ };
+ })) ||
+ []),
+ {
+ key: t("jobs.fields.adjustment_bottom_line"),
+ total: job.job_totals.additional.adjustments,
+ },
+ {
+ key: t("jobs.fields.towing_payable"),
+ total: job.job_totals.additional.towing,
+ },
+ {
+ key: t("jobs.fields.storage_payable"),
+ total: job.job_totals.additional.storage,
+ },
+ // {
+ // key: t("jobs.fields.ca_bc_pvrt"),
+ // total: job.job_totals.additional.pvrt,
+ // },
+ ];
+ }, [job.job_totals, t]);
+
+ const columns = [
+ {
+ title: t("general.labels.item"),
+ dataIndex: "key",
+ key: "key",
+ sorter: (a, b) => alphaSort(a.key, b.key),
+ sortOrder: state.sortedInfo.columnKey === "key" && state.sortedInfo.order,
+ width: "0%",
+ },
+ {
+ title: t("joblines.fields.total"),
+ dataIndex: "total",
+ key: "total",
+ sorter: (a, b) => a.total.amount - b.total.amount,
+ sortOrder:
+ state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
+ width: "20%",
+ align: "right",
+ render: (text, record) => Dinero(record.total).toFormat(),
+ },
];
- }, [job.job_totals, t]);
- const columns = [
- {
- title: t("general.labels.item"),
- dataIndex: "key",
- key: "key",
- sorter: (a, b) => alphaSort(a.key, b.key),
- sortOrder: state.sortedInfo.columnKey === "key" && state.sortedInfo.order,
- width: "0%",
- },
- {
- title: t("joblines.fields.total"),
- dataIndex: "total",
- key: "total",
- sorter: (a, b) => a.total.amount - b.total.amount,
- sortOrder:
- state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
- width: "20%",
- align: "right",
- render: (text, record) => Dinero(record.total).toFormat(),
- },
- ];
+ const handleTableChange = (pagination, filters, sorter) => {
+ setState({...state, filteredInfo: filters, sortedInfo: sorter});
+ };
+ return (
+ (
+ <>
+
+
+ {t("jobs.labels.additionaltotal")}
+
- const handleTableChange = (pagination, filters, sorter) => {
- setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
- };
- return (
- (
- <>
-
-
- {t("jobs.labels.additionaltotal")}
-
+
+
+ {Dinero(job.job_totals.additional.total).toFormat()}
+
+
+
+
+
+ {t("jobs.labels.subletstotal")}
+
-
-
- {Dinero(job.job_totals.additional.total).toFormat()}
-
-
-
-
-
- {t("jobs.labels.subletstotal")}
-
-
-
-
- {Dinero(job.job_totals.parts.sublets.total).toFormat()}
-
-
-
- >
- )}
- />
- );
+
+
+ {Dinero(job.job_totals.parts.sublets.total).toFormat()}
+
+
+
+ >
+ )}
+ />
+ );
}
diff --git a/client/src/components/job-totals-table/job-totals.table.parts.component.jsx b/client/src/components/job-totals-table/job-totals.table.parts.component.jsx
index afcf9e14a..313de9e61 100644
--- a/client/src/components/job-totals-table/job-totals.table.parts.component.jsx
+++ b/client/src/components/job-totals-table/job-totals.table.parts.component.jsx
@@ -1,131 +1,131 @@
-import { Table } from "antd";
+import {Table} from "antd";
import Dinero from "dinero.js";
-import React, { useMemo, useState } from "react";
-import { useTranslation } from "react-i18next";
-import { alphaSort } from "../../utils/sorters";
+import React, {useMemo, useState} from "react";
+import {useTranslation} from "react-i18next";
+import {alphaSort} from "../../utils/sorters";
-export default function JobTotalsTableParts({ job }) {
- const { t } = useTranslation();
- const [state, setState] = useState({
- sortedInfo: {},
- 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]),
- });
- }
+export default function JobTotalsTableParts({job}) {
+ const {t} = useTranslation();
+ const [state, setState] = useState({
+ sortedInfo: {},
+ filteredInfo: {},
});
- return adjs;
- }, [job.job_totals]);
+ 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]),
+ });
+ }
+ });
- const data = useMemo(() => {
- return Object.keys(job.job_totals.parts.parts.list)
- .filter(
- (key) =>
- key !== "mapa" &&
- key !== "mash" &&
- key !== "subtotal" &&
- key !== "rates_subtotal"
- )
- .map((key) => {
- return {
- id: key,
- ...job.job_totals.parts.parts.list[key],
- };
- });
- }, [job.job_totals.parts.parts.list]);
+ return adjs;
+ }, [job.job_totals]);
- const columns = [
- {
- title: t("joblines.fields.part_type"),
- dataIndex: "id",
- key: "id",
- sorter: (a, b) =>
- alphaSort(
- t(`jobs.fields.${a.id.toLowerCase()}`),
- t(`jobs.fields.${b.id.toLowerCase()}`)
- ),
- width: "80%",
- sortOrder: state.sortedInfo.columnKey === "id" && state.sortedInfo.order,
- render: (text, record) => t(`jobs.fields.${record.id.toLowerCase()}`),
- },
- {
- title: t("joblines.fields.total"),
- dataIndex: "total",
- key: "total",
- sorter: (a, b) => a.total.amount - b.total.amount,
- sortOrder:
- state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
- width: "20%",
- align: "right",
- render: (text, record) => Dinero(record.total).toFormat(),
- },
- ];
+ const data = useMemo(() => {
+ return Object.keys(job.job_totals.parts.parts.list)
+ .filter(
+ (key) =>
+ key !== "mapa" &&
+ key !== "mash" &&
+ key !== "subtotal" &&
+ key !== "rates_subtotal"
+ )
+ .map((key) => {
+ return {
+ id: key,
+ ...job.job_totals.parts.parts.list[key],
+ };
+ });
+ }, [job.job_totals.parts.parts.list]);
- const handleTableChange = (pagination, filters, sorter) => {
- setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
- };
- return (
- (
- <>
-
-
- {t("jobs.labels.prt_dsmk_total")}
-
-
- {Dinero(job.job_totals.parts.parts.prt_dsmk_total).toFormat()}
-
-
+ const columns = [
+ {
+ title: t("joblines.fields.part_type"),
+ dataIndex: "id",
+ key: "id",
+ sorter: (a, b) =>
+ alphaSort(
+ t(`jobs.fields.${a.id.toLowerCase()}`),
+ t(`jobs.fields.${b.id.toLowerCase()}`)
+ ),
+ width: "80%",
+ sortOrder: state.sortedInfo.columnKey === "id" && state.sortedInfo.order,
+ render: (text, record) => t(`jobs.fields.${record.id.toLowerCase()}`),
+ },
+ {
+ title: t("joblines.fields.total"),
+ dataIndex: "total",
+ key: "total",
+ sorter: (a, b) => a.total.amount - b.total.amount,
+ sortOrder:
+ state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
+ width: "20%",
+ align: "right",
+ render: (text, record) => Dinero(record.total).toFormat(),
+ },
+ ];
-
-
- {t("jobs.labels.partstotal")}
-
+ const handleTableChange = (pagination, filters, sorter) => {
+ setState({...state, filteredInfo: filters, sortedInfo: sorter});
+ };
+ return (
+ (
+ <>
+
+
+ {t("jobs.labels.prt_dsmk_total")}
+
+
+ {Dinero(job.job_totals.parts.parts.prt_dsmk_total).toFormat()}
+
+
-
-
- {Dinero(job.job_totals.parts.parts.total).toFormat()}
-
-
-
- {insuranceAdjustments.length > 0 && (
-
-
- {t("jobs.labels.profileadjustments")}
-
-
- )}
- {insuranceAdjustments.map((adj, idx) => (
-
-
- {t(`jobs.fields.${adj.id.toLowerCase()}`)}
-
+
+
+ {t("jobs.labels.partstotal")}
+
-
- {adj.amount.toFormat()}
-
-
- ))}
- >
- )}
- />
- );
+
+
+ {Dinero(job.job_totals.parts.parts.total).toFormat()}
+
+
+
+ {insuranceAdjustments.length > 0 && (
+
+
+ {t("jobs.labels.profileadjustments")}
+
+
+ )}
+ {insuranceAdjustments.map((adj, idx) => (
+
+
+ {t(`jobs.fields.${adj.id.toLowerCase()}`)}
+
+
+
+ {adj.amount.toFormat()}
+
+
+ ))}
+ >
+ )}
+ />
+ );
}
diff --git a/client/src/components/job-totals-table/job-totals.table.totals.component.jsx b/client/src/components/job-totals-table/job-totals.table.totals.component.jsx
index ee9645bc5..415df9695 100644
--- a/client/src/components/job-totals-table/job-totals.table.totals.component.jsx
+++ b/client/src/components/job-totals-table/job-totals.table.totals.component.jsx
@@ -1,204 +1,205 @@
-import { Table } from "antd";
+import {Table} from "antd";
import Dinero from "dinero.js";
-import React, { useMemo } from "react";
-import { useTranslation } from "react-i18next";
+import React, {useMemo} from "react";
+import {useTranslation} from "react-i18next";
+
+import {connect} from "react-redux";
+import {createStructuredSelector} from "reselect";
+import {selectBodyshop} from "../../redux/user/user.selectors";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { selectBodyshop } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
- //currentUser: selectCurrentUser
- bodyshop: selectBodyshop,
+ //currentUser: selectCurrentUser
+ bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
- //setUserLanguage: language => dispatch(setUserLanguage(language))
+ //setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(
- mapStateToProps,
- mapDispatchToProps
+ mapStateToProps,
+ mapDispatchToProps
)(JobTotalsTableTotals);
-export function JobTotalsTableTotals({ bodyshop, job }) {
- const { t } = useTranslation();
+export function JobTotalsTableTotals({bodyshop, job}) {
+ const {t} = useTranslation();
- const data = useMemo(() => {
- return [
- {
- key: t("jobs.labels.subtotal"),
- total: job.job_totals.totals.subtotal,
- bold: true,
- },
+ const data = useMemo(() => {
+ return [
+ {
+ key: t("jobs.labels.subtotal"),
+ total: job.job_totals.totals.subtotal,
+ bold: true,
+ },
- ...(job.job_totals.totals.us_sales_tax_breakdown
- ? [
- {
- key: `${
- bodyshop.md_responsibility_centers.taxes.tax_ty1?.tax_type1 ||
- "T1"
- } - ${[
- job.cieca_pft.ty1_rate1,
- job.cieca_pft.ty1_rate2,
- job.cieca_pft.ty1_rate3,
- job.cieca_pft.ty1_rate4,
- job.cieca_pft.ty1_rate5,
- ]
- .filter((i) => i > 0)
- .join(", ")}%`,
- total: job.job_totals.totals.us_sales_tax_breakdown.ty1Tax,
- },
- {
- key: `${
- bodyshop.md_responsibility_centers.taxes.tax_ty2?.tax_type2 ||
- "T2"
- } - ${[
- job.cieca_pft.ty2_rate1,
- job.cieca_pft.ty2_rate2,
- job.cieca_pft.ty2_rate3,
- job.cieca_pft.ty2_rate4,
- job.cieca_pft.ty2_rate5,
- ]
- .filter((i) => i > 0)
- .join(", ")}%`,
- total: job.job_totals.totals.us_sales_tax_breakdown.ty2Tax,
- },
- {
- key: `${
- bodyshop.md_responsibility_centers.taxes.tax_ty3?.tax_type3 ||
- "T3"
- } - ${[
- job.cieca_pft.ty3_rate1,
- job.cieca_pft.ty3_rate2,
- job.cieca_pft.ty3_rate3,
- job.cieca_pft.ty3_rate4,
- job.cieca_pft.ty3_rate5,
- ]
- .filter((i) => i > 0)
- .join(", ")}%`,
- total: job.job_totals.totals.us_sales_tax_breakdown.ty3Tax,
- },
- {
- key: `${
- bodyshop.md_responsibility_centers.taxes.tax_ty4?.tax_type4 ||
- "T4"
- } - ${[
- job.cieca_pft.ty4_rate1,
- job.cieca_pft.ty4_rate2,
- job.cieca_pft.ty4_rate3,
- job.cieca_pft.ty4_rate4,
- job.cieca_pft.ty4_rate5,
- ]
- .filter((i) => i > 0)
- .join(", ")}%`,
- total: job.job_totals.totals.us_sales_tax_breakdown.ty4Tax,
- },
- {
- key: `${
- bodyshop.md_responsibility_centers.taxes.tax_ty5?.tax_type5 ||
- "TT"
- } - ${[
- job.cieca_pft.ty5_rate1,
- job.cieca_pft.ty5_rate2,
- job.cieca_pft.ty5_rate3,
- job.cieca_pft.ty5_rate4,
- job.cieca_pft.ty5_rate5,
- ]
- .filter((i) => i > 0)
- .join(", ")}%`,
- total: job.job_totals.totals.us_sales_tax_breakdown.ty5Tax,
- },
- {
- key: t("jobs.labels.total_sales_tax"),
- bold: true,
- total: Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty1Tax)
- .add(
- Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty2Tax)
- )
- .add(
- Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty3Tax)
- )
- .add(
- Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty4Tax)
- )
- .add(
- Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty5Tax)
- ).toJSON(),
- },
- ].filter((item) => item.total.amount !== 0)
- : [
- {
- key: t("jobs.labels.state_tax_amt"),
- total: job.job_totals.totals.state_tax,
- },
- ]),
+ ...(job.job_totals.totals.us_sales_tax_breakdown
+ ? [
+ {
+ key: `${
+ bodyshop.md_responsibility_centers.taxes.tax_ty1?.tax_type1 ||
+ "T1"
+ } - ${[
+ job.cieca_pft.ty1_rate1,
+ job.cieca_pft.ty1_rate2,
+ job.cieca_pft.ty1_rate3,
+ job.cieca_pft.ty1_rate4,
+ job.cieca_pft.ty1_rate5,
+ ]
+ .filter((i) => i > 0)
+ .join(", ")}%`,
+ total: job.job_totals.totals.us_sales_tax_breakdown.ty1Tax,
+ },
+ {
+ key: `${
+ bodyshop.md_responsibility_centers.taxes.tax_ty2?.tax_type2 ||
+ "T2"
+ } - ${[
+ job.cieca_pft.ty2_rate1,
+ job.cieca_pft.ty2_rate2,
+ job.cieca_pft.ty2_rate3,
+ job.cieca_pft.ty2_rate4,
+ job.cieca_pft.ty2_rate5,
+ ]
+ .filter((i) => i > 0)
+ .join(", ")}%`,
+ total: job.job_totals.totals.us_sales_tax_breakdown.ty2Tax,
+ },
+ {
+ key: `${
+ bodyshop.md_responsibility_centers.taxes.tax_ty3?.tax_type3 ||
+ "T3"
+ } - ${[
+ job.cieca_pft.ty3_rate1,
+ job.cieca_pft.ty3_rate2,
+ job.cieca_pft.ty3_rate3,
+ job.cieca_pft.ty3_rate4,
+ job.cieca_pft.ty3_rate5,
+ ]
+ .filter((i) => i > 0)
+ .join(", ")}%`,
+ total: job.job_totals.totals.us_sales_tax_breakdown.ty3Tax,
+ },
+ {
+ key: `${
+ bodyshop.md_responsibility_centers.taxes.tax_ty4?.tax_type4 ||
+ "T4"
+ } - ${[
+ job.cieca_pft.ty4_rate1,
+ job.cieca_pft.ty4_rate2,
+ job.cieca_pft.ty4_rate3,
+ job.cieca_pft.ty4_rate4,
+ job.cieca_pft.ty4_rate5,
+ ]
+ .filter((i) => i > 0)
+ .join(", ")}%`,
+ total: job.job_totals.totals.us_sales_tax_breakdown.ty4Tax,
+ },
+ {
+ key: `${
+ bodyshop.md_responsibility_centers.taxes.tax_ty5?.tax_type5 ||
+ "TT"
+ } - ${[
+ job.cieca_pft.ty5_rate1,
+ job.cieca_pft.ty5_rate2,
+ job.cieca_pft.ty5_rate3,
+ job.cieca_pft.ty5_rate4,
+ job.cieca_pft.ty5_rate5,
+ ]
+ .filter((i) => i > 0)
+ .join(", ")}%`,
+ total: job.job_totals.totals.us_sales_tax_breakdown.ty5Tax,
+ },
+ {
+ key: t("jobs.labels.total_sales_tax"),
+ bold: true,
+ total: Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty1Tax)
+ .add(
+ Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty2Tax)
+ )
+ .add(
+ Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty3Tax)
+ )
+ .add(
+ Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty4Tax)
+ )
+ .add(
+ Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty5Tax)
+ ).toJSON(),
+ },
+ ].filter((item) => item.total.amount !== 0)
+ : [
+ {
+ key: t("jobs.labels.state_tax_amt"),
+ total: job.job_totals.totals.state_tax,
+ },
+ ]),
- {
- key: t("jobs.labels.total_repairs"),
- total: job.job_totals.totals.total_repairs,
- bold: true,
- },
- {
- key: t("jobs.fields.ded_amt"),
- total: job.job_totals.totals.custPayable.deductible,
- },
- // {
- // key: t("jobs.fields.federal_tax_payable"),
- // total: job.job_totals.totals.custPayable.federal_tax,
- // },
- {
- key: t("jobs.fields.other_amount_payable"),
- total: job.job_totals.totals.custPayable.other_customer_amount,
- },
- {
- key: t("jobs.fields.depreciation_taxes"),
- total: job.job_totals.totals.custPayable.dep_taxes,
- },
+ {
+ key: t("jobs.labels.total_repairs"),
+ total: job.job_totals.totals.total_repairs,
+ bold: true,
+ },
+ {
+ key: t("jobs.fields.ded_amt"),
+ total: job.job_totals.totals.custPayable.deductible,
+ },
+ // {
+ // key: t("jobs.fields.federal_tax_payable"),
+ // total: job.job_totals.totals.custPayable.federal_tax,
+ // },
+ {
+ key: t("jobs.fields.other_amount_payable"),
+ total: job.job_totals.totals.custPayable.other_customer_amount,
+ },
+ {
+ key: t("jobs.fields.depreciation_taxes"),
+ total: job.job_totals.totals.custPayable.dep_taxes,
+ },
- {
- key: t("jobs.labels.total_cust_payable"),
- total: job.job_totals.totals.custPayable.total,
- bold: true,
- },
- {
- key: t("jobs.labels.net_repairs"),
- total: job.job_totals.totals.net_repairs,
- bold: true,
- },
+ {
+ key: t("jobs.labels.total_cust_payable"),
+ total: job.job_totals.totals.custPayable.total,
+ bold: true,
+ },
+ {
+ key: t("jobs.labels.net_repairs"),
+ total: job.job_totals.totals.net_repairs,
+ bold: true,
+ },
+ ];
+ }, [job.job_totals, job.cieca_pft, t, bodyshop.md_responsibility_centers]);
+
+ const columns = [
+ {
+ //title: t("joblines.fields.part_type"),
+ dataIndex: "key",
+ key: "key",
+ width: "80%",
+ onCell: (record, rowIndex) => {
+ return {style: {fontWeight: record.bold && "bold"}};
+ },
+ },
+ {
+ title: t("joblines.fields.total"),
+ dataIndex: "total",
+ key: "total",
+ align: "right",
+ render: (text, record) => Dinero(record.total).toFormat(),
+ width: "20%",
+ onCell: (record, rowIndex) => {
+ return {style: {fontWeight: record.bold && "bold"}};
+ },
+ },
];
- }, [job.job_totals, job.cieca_pft, t, bodyshop.md_responsibility_centers]);
- const columns = [
- {
- //title: t("joblines.fields.part_type"),
- dataIndex: "key",
- key: "key",
- width: "80%",
- onCell: (record, rowIndex) => {
- return { style: { fontWeight: record.bold && "bold" } };
- },
- },
- {
- title: t("joblines.fields.total"),
- dataIndex: "total",
- key: "total",
- align: "right",
- render: (text, record) => Dinero(record.total).toFormat(),
- width: "20%",
- onCell: (record, rowIndex) => {
- return { style: { fontWeight: record.bold && "bold" } };
- },
- },
- ];
-
- return (
-
- );
+ return (
+
+ );
}
diff --git a/client/src/components/jobs-admin-change-status/jobs-admin-change.status.component.jsx b/client/src/components/jobs-admin-change-status/jobs-admin-change.status.component.jsx
index edef81343..63133a18d 100644
--- a/client/src/components/jobs-admin-change-status/jobs-admin-change.status.component.jsx
+++ b/client/src/components/jobs-admin-change-status/jobs-admin-change.status.component.jsx
@@ -1,64 +1,62 @@
-import { DownCircleFilled } from "@ant-design/icons";
-import { useMutation } from "@apollo/client";
-import { Button, Dropdown, Menu, notification } from "antd";
+import {DownCircleFilled} from "@ant-design/icons";
+import {useMutation} from "@apollo/client";
+import {Button, Dropdown, notification} from "antd";
import React from "react";
-import { useTranslation } from "react-i18next";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { UPDATE_JOB_STATUS } from "../../graphql/jobs.queries";
-import { insertAuditTrail } from "../../redux/application/application.actions";
-import { selectBodyshop } from "../../redux/user/user.selectors";
+import {useTranslation} from "react-i18next";
+import {connect} from "react-redux";
+import {createStructuredSelector} from "reselect";
+import {UPDATE_JOB_STATUS} from "../../graphql/jobs.queries";
+import {insertAuditTrail} from "../../redux/application/application.actions";
+import {selectBodyshop} from "../../redux/user/user.selectors";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
const mapStateToProps = createStructuredSelector({
- bodyshop: selectBodyshop,
+ bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
- insertAuditTrail: ({ jobid, operation }) =>
- dispatch(insertAuditTrail({ jobid, operation })),
+ insertAuditTrail: ({jobid, operation}) =>
+ dispatch(insertAuditTrail({jobid, operation})),
});
export default connect(mapStateToProps, mapDispatchToProps)(JobsAdminStatus);
-export function JobsAdminStatus({ insertAuditTrail, bodyshop, job }) {
- const { t } = useTranslation();
+export function JobsAdminStatus({insertAuditTrail, bodyshop, job}) {
+ const {t} = useTranslation();
- const [mutationUpdateJobstatus] = useMutation(UPDATE_JOB_STATUS);
- const updateJobStatus = (status) => {
- mutationUpdateJobstatus({
- variables: { jobId: job.id, status: status },
- })
- .then((r) => {
- notification["success"]({ message: t("jobs.successes.save") });
- insertAuditTrail({
- jobid: job.id,
- operation: AuditTrailMapping.admin_jobstatuschange(status),
- });
- // refetch();
- })
- .catch((error) => {
- notification["error"]({ message: t("jobs.errors.saving") });
- });
- };
+ const [mutationUpdateJobstatus] = useMutation(UPDATE_JOB_STATUS);
+ const updateJobStatus = (status) => {
+ mutationUpdateJobstatus({
+ variables: {jobId: job.id, status: status},
+ })
+ .then((r) => {
+ notification["success"]({message: t("jobs.successes.save")});
+ insertAuditTrail({
+ jobid: job.id,
+ operation: AuditTrailMapping.admin_jobstatuschange(status),
+ });
+ // refetch();
+ })
+ .catch((error) => {
+ notification["error"]({message: t("jobs.errors.saving")});
+ });
+ };
- const statusmenu = (
-
- );
+ const statusMenu = {
+ items: bodyshop.md_ro_statuses.statuses.map((item) => ({
+ key: item,
+ label: item,
+ })),
+ onClick: (e) => {
+ updateJobStatus(e.key);
+ },
+ }
- return (
-
-
+
+ );
}
diff --git a/client/src/components/jobs-admin-class/jobs-admin-class.component.jsx b/client/src/components/jobs-admin-class/jobs-admin-class.component.jsx
index 55142344e..4d5b80541 100644
--- a/client/src/components/jobs-admin-class/jobs-admin-class.component.jsx
+++ b/client/src/components/jobs-admin-class/jobs-admin-class.component.jsx
@@ -1,84 +1,84 @@
-import { useMutation } from "@apollo/client";
-import { Button, Form, notification, Popconfirm, Select } from "antd";
-import React, { useEffect, useState } from "react";
-import { useTranslation } from "react-i18next";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { UPDATE_JOB } from "../../graphql/jobs.queries";
-import { selectBodyshop } from "../../redux/user/user.selectors";
+import {useMutation} from "@apollo/client";
+import {Button, Form, notification, Popconfirm, Select} from "antd";
+import React, {useEffect, useState} from "react";
+import {useTranslation} from "react-i18next";
+import {connect} from "react-redux";
+import {createStructuredSelector} from "reselect";
+import {UPDATE_JOB} from "../../graphql/jobs.queries";
+import {selectBodyshop} from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
- bodyshop: selectBodyshop,
+ bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
- //setUserLanguage: language => dispatch(setUserLanguage(language))
+ //setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(mapStateToProps, mapDispatchToProps)(JobsAdminClass);
-export function JobsAdminClass({ bodyshop, job }) {
- const { t } = useTranslation();
- const [loading, setLoading] = useState(false);
- const [form] = Form.useForm();
- const [updateJob] = useMutation(UPDATE_JOB);
+export function JobsAdminClass({bodyshop, job}) {
+ const {t} = useTranslation();
+ const [loading, setLoading] = useState(false);
+ const [form] = Form.useForm();
+ const [updateJob] = useMutation(UPDATE_JOB);
- const handleFinish = async (values) => {
- setLoading(true);
- const result = await updateJob({
- variables: { jobId: job.id, job: values },
- });
+ const handleFinish = async (values) => {
+ setLoading(true);
+ const result = await updateJob({
+ variables: {jobId: job.id, job: values},
+ });
- if (!!!result.errors) {
- notification["success"]({ message: t("jobs.successes.save") });
- } else {
- notification["error"]({
- message: t("jobs.errors.saving", {
- error: JSON.stringify(result.errors),
- }),
- });
- }
- setLoading(false);
- //Get the owner details, populate it all back into the job.
- };
+ if (!!!result.errors) {
+ notification["success"]({message: t("jobs.successes.save")});
+ } else {
+ notification["error"]({
+ message: t("jobs.errors.saving", {
+ error: JSON.stringify(result.errors),
+ }),
+ });
+ }
+ setLoading(false);
+ //Get the owner details, populate it all back into the job.
+ };
- useEffect(() => {
- //form.resetFields();
- }, [form, job]);
+ useEffect(() => {
+ //form.resetFields();
+ }, [form, job]);
- return (
-
-
-
-
-
+ return (
+
+
+
+
+
-
form.submit()}
- >
- {t("general.actions.save")}
-
-
- );
+
form.submit()}
+ >
+ {t("general.actions.save")}
+
+
+ );
}
diff --git a/client/src/components/jobs-admin-dates/jobs-admin-dates.component.jsx b/client/src/components/jobs-admin-dates/jobs-admin-dates.component.jsx
index 5ac31da74..200a24975 100644
--- a/client/src/components/jobs-admin-dates/jobs-admin-dates.component.jsx
+++ b/client/src/components/jobs-admin-dates/jobs-admin-dates.component.jsx
@@ -1,197 +1,198 @@
-import { useMutation } from "@apollo/client";
-import { Button, Form, notification } from "antd";
-import moment from "moment";
-import React, { useEffect, useState } from "react";
-import { useTranslation } from "react-i18next";
-import { UPDATE_JOB } from "../../graphql/jobs.queries";
+import {useMutation} from "@apollo/client";
+import {Button, Form, notification} from "antd";
+import dayjs from "../../utils/day";
+import React, {useEffect, useState} from "react";
+import {useTranslation} from "react-i18next";
+import {UPDATE_JOB} from "../../graphql/jobs.queries";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
import FormDatePicker from "../form-date-picker/form-date-picker.component";
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component";
import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { insertAuditTrail } from "../../redux/application/application.actions";
-import { DateTimeFormat } from "./../../utils/DateFormatter";
+import {connect} from "react-redux";
+import {createStructuredSelector} from "reselect";
+import {insertAuditTrail} from "../../redux/application/application.actions";
+import {DateTimeFormat} from "./../../utils/DateFormatter";
const mapStateToProps = createStructuredSelector({
- //currentUser: selectCurrentUser
+ //currentUser: selectCurrentUser
});
const mapDispatchToProps = (dispatch) => ({
- insertAuditTrail: ({ jobid, operation }) =>
- dispatch(insertAuditTrail({ jobid, operation })),
+ insertAuditTrail: ({jobid, operation}) =>
+ dispatch(insertAuditTrail({jobid, operation})),
});
export default connect(
- mapStateToProps,
- mapDispatchToProps
+ mapStateToProps,
+ mapDispatchToProps
)(JobsAdminDatesChange);
-export function JobsAdminDatesChange({ insertAuditTrail, job }) {
- const { t } = useTranslation();
- const [loading, setLoading] = useState(false);
- const [form] = Form.useForm();
- const [updateJob] = useMutation(UPDATE_JOB);
+export function JobsAdminDatesChange({insertAuditTrail, job}) {
+ const {t} = useTranslation();
+ const [loading, setLoading] = useState(false);
+ const [form] = Form.useForm();
+ const [updateJob] = useMutation(UPDATE_JOB);
- const handleFinish = async (values) => {
- setLoading(true);
- const result = await updateJob({
- variables: { jobId: job.id, job: values },
- refetchQueries: ["GET_JOB_BY_PK"],
- awaitRefetchQueries: true,
- });
+ const handleFinish = async (values) => {
+ setLoading(true);
+ const result = await updateJob({
+ variables: {jobId: job.id, job: values},
+ refetchQueries: ["GET_JOB_BY_PK"],
+ awaitRefetchQueries: true,
+ });
- const changedAuditFields = form.getFieldsValue(
- true,
- (meta) => meta && meta.touched
+ const changedAuditFields = form.getFieldsValue(
+ true,
+ (meta) => meta && meta.touched
+ );
+
+ Object.keys(changedAuditFields).forEach((key) => {
+ insertAuditTrail({
+ jobid: job.id,
+ operation: AuditTrailMapping.admin_jobfieldchange(
+ key,
+ changedAuditFields[key] instanceof dayjs
+ ? DateTimeFormat(changedAuditFields[key])
+ : changedAuditFields[key]
+ ),
+ });
+ });
+
+ if (!!!result.errors) {
+ notification["success"]({message: t("jobs.successes.save")});
+ } else {
+ notification["error"]({
+ message: t("jobs.errors.saving", {
+ error: JSON.stringify(result.errors),
+ }),
+ });
+ }
+
+ form.resetFields();
+
+ setLoading(false);
+ //Get the owner details, populate it all back into the job.
+ };
+
+ useEffect(() => {
+ //form.resetFields();
+ }, [form, job]);
+
+ return (
+
+
+
+ form.submit()}>
+ {t("general.actions.save")}
+
+
);
-
- Object.keys(changedAuditFields).forEach((key) => {
- insertAuditTrail({
- jobid: job.id,
- operation: AuditTrailMapping.admin_jobfieldchange(
- key,
- changedAuditFields[key] instanceof moment
- ? DateTimeFormat(changedAuditFields[key])
- : changedAuditFields[key]
- ),
- });
- });
-
- if (!!!result.errors) {
- notification["success"]({ message: t("jobs.successes.save") });
- } else {
- notification["error"]({
- message: t("jobs.errors.saving", {
- error: JSON.stringify(result.errors),
- }),
- });
- }
- form.resetFields();
- form.resetFields();
- setLoading(false);
- //Get the owner details, populate it all back into the job.
- };
-
- useEffect(() => {
- //form.resetFields();
- }, [form, job]);
-
- return (
-
-
-
- form.submit()}>
- {t("general.actions.save")}
-
-
- );
}
diff --git a/client/src/components/jobs-admin-delete-intake/jobs-admin-delete-intake.component.jsx b/client/src/components/jobs-admin-delete-intake/jobs-admin-delete-intake.component.jsx
index 190778437..68b50c3c2 100644
--- a/client/src/components/jobs-admin-delete-intake/jobs-admin-delete-intake.component.jsx
+++ b/client/src/components/jobs-admin-delete-intake/jobs-admin-delete-intake.component.jsx
@@ -1,79 +1,79 @@
-import { useMutation } from "@apollo/client";
-import { Button, notification } from "antd";
-import { gql } from "@apollo/client";
-import React, { useState } from "react";
-import { useTranslation } from "react-i18next";
-export default function JobAdminDeleteIntake({ job }) {
- const { t } = useTranslation();
- const [loading, setLoading] = useState(false);
- const [deleteIntake] = useMutation(gql`
- mutation DELETE_INTAKE($jobId: uuid!) {
- update_jobs_by_pk(
- pk_columns: { id: $jobId }
- _set: { intakechecklist: null }
- ) {
- id
- intakechecklist
- }
- }
- `);
+import {gql, useMutation} from "@apollo/client";
+import {Button, notification} from "antd";
+import React, {useState} from "react";
+import {useTranslation} from "react-i18next";
- const [DELETE_DELIVERY] = useMutation(gql`
- mutation DELETE_DELIVERY($jobId: uuid!) {
- update_jobs_by_pk(
- pk_columns: { id: $jobId }
- _set: { deliverchecklist: null }
- ) {
- id
- deliverchecklist
- }
- }
- `);
+export default function JobAdminDeleteIntake({job}) {
+ const {t} = useTranslation();
+ const [loading, setLoading] = useState(false);
+ const [deleteIntake] = useMutation(gql`
+ mutation DELETE_INTAKE($jobId: uuid!) {
+ update_jobs_by_pk(
+ pk_columns: { id: $jobId }
+ _set: { intakechecklist: null }
+ ) {
+ id
+ intakechecklist
+ }
+ }
+ `);
- const handleDelete = async (values) => {
- setLoading(true);
- const result = await deleteIntake({
- variables: { jobId: job.id },
- });
+ const [DELETE_DELIVERY] = useMutation(gql`
+ mutation DELETE_DELIVERY($jobId: uuid!) {
+ update_jobs_by_pk(
+ pk_columns: { id: $jobId }
+ _set: { deliverchecklist: null }
+ ) {
+ id
+ deliverchecklist
+ }
+ }
+ `);
- if (!!!result.errors) {
- notification["success"]({ message: t("jobs.successes.save") });
- } else {
- notification["error"]({
- message: t("jobs.errors.saving", {
- error: JSON.stringify(result.errors),
- }),
- });
- }
- setLoading(false);
- };
+ const handleDelete = async (values) => {
+ setLoading(true);
+ const result = await deleteIntake({
+ variables: {jobId: job.id},
+ });
- const handleDeleteDelivery = async (values) => {
- setLoading(true);
- const result = await DELETE_DELIVERY({
- variables: { jobId: job.id },
- });
+ if (!!!result.errors) {
+ notification["success"]({message: t("jobs.successes.save")});
+ } else {
+ notification["error"]({
+ message: t("jobs.errors.saving", {
+ error: JSON.stringify(result.errors),
+ }),
+ });
+ }
+ setLoading(false);
+ };
- if (!!!result.errors) {
- notification["success"]({ message: t("jobs.successes.save") });
- } else {
- notification["error"]({
- message: t("jobs.errors.saving", {
- error: JSON.stringify(result.errors),
- }),
- });
- }
- setLoading(false);
- };
+ const handleDeleteDelivery = async (values) => {
+ setLoading(true);
+ const result = await DELETE_DELIVERY({
+ variables: {jobId: job.id},
+ });
- return (
- <>
-
- {t("jobs.labels.deleteintake")}
-
-
- {t("jobs.labels.deletedelivery")}
-
- >
- );
+ if (!!!result.errors) {
+ notification["success"]({message: t("jobs.successes.save")});
+ } else {
+ notification["error"]({
+ message: t("jobs.errors.saving", {
+ error: JSON.stringify(result.errors),
+ }),
+ });
+ }
+ setLoading(false);
+ };
+
+ return (
+ <>
+
+ {t("jobs.labels.deleteintake")}
+
+
+ {t("jobs.labels.deletedelivery")}
+
+ >
+ );
}
diff --git a/client/src/components/jobs-admin-mark-reexport/jobs-admin-mark-reexport.component.jsx b/client/src/components/jobs-admin-mark-reexport/jobs-admin-mark-reexport.component.jsx
index c47c30def..3b4cbe9bd 100644
--- a/client/src/components/jobs-admin-mark-reexport/jobs-admin-mark-reexport.component.jsx
+++ b/client/src/components/jobs-admin-mark-reexport/jobs-admin-mark-reexport.component.jsx
@@ -1,191 +1,189 @@
-import { gql, useMutation } from "@apollo/client";
-import { Button, notification } from "antd";
-import React, { useState } from "react";
-import { useTranslation } from "react-i18next";
+import {gql, useMutation} from "@apollo/client";
+import {Button, notification} from "antd";
+import React, {useState} from "react";
+import {useTranslation} from "react-i18next";
-import moment from "moment";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
-import { insertAuditTrail } from "../../redux/application/application.actions";
-import {
- selectBodyshop,
- selectCurrentUser,
-} from "../../redux/user/user.selectors";
+import dayjs from "../../utils/day";
+import {connect} from "react-redux";
+import {createStructuredSelector} from "reselect";
+import {INSERT_EXPORT_LOG} from "../../graphql/accounting.queries";
+import {insertAuditTrail} from "../../redux/application/application.actions";
+import {selectBodyshop, selectCurrentUser,} from "../../redux/user/user.selectors";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
+
const mapStateToProps = createStructuredSelector({
- bodyshop: selectBodyshop,
- currentUser: selectCurrentUser,
+ bodyshop: selectBodyshop,
+ currentUser: selectCurrentUser,
});
const mapDispatchToProps = (dispatch) => ({
- insertAuditTrail: ({ jobid, operation }) =>
- dispatch(insertAuditTrail({ jobid, operation })),
+ insertAuditTrail: ({jobid, operation}) =>
+ dispatch(insertAuditTrail({jobid, operation})),
});
export default connect(
- mapStateToProps,
- mapDispatchToProps
+ mapStateToProps,
+ mapDispatchToProps
)(JobAdminMarkReexport);
export function JobAdminMarkReexport({
- insertAuditTrail,
- bodyshop,
- currentUser,
- job,
-}) {
- const { t } = useTranslation();
- const [loading, setLoading] = useState(false);
- const [insertExportLog] = useMutation(INSERT_EXPORT_LOG);
- const [markJobForReexport] = useMutation(gql`
- mutation MARK_JOB_FOR_REEXPORT($jobId: uuid!) {
- update_jobs_by_pk(
- pk_columns: { id: $jobId }
- _set: { date_exported: null
- status: "${bodyshop.md_ro_statuses.default_invoiced}"
+ insertAuditTrail,
+ bodyshop,
+ currentUser,
+ job,
+ }) {
+ const {t} = useTranslation();
+ const [loading, setLoading] = useState(false);
+ const [insertExportLog] = useMutation(INSERT_EXPORT_LOG);
+ const [markJobForReexport] = useMutation(gql`
+ mutation MARK_JOB_FOR_REEXPORT($jobId: uuid!) {
+ update_jobs_by_pk(
+ pk_columns: { id: $jobId }
+ _set: { date_exported: null
+ status: "${bodyshop.md_ro_statuses.default_invoiced}"
+ }
+ ) {
+ id
+ date_exported
+ status
+ date_invoiced
+ }
}
- ) {
- id
- date_exported
- status
- date_invoiced
- }
- }
- `);
+ `);
- const [markJobExported] = useMutation(gql`
- mutation MARK_JOB_AS_EXPORTED($jobId: uuid!, $date_exported: timestamptz!) {
- update_jobs_by_pk(
- pk_columns: { id: $jobId }
- _set: { date_exported: $date_exported
- status: "${bodyshop.md_ro_statuses.default_exported}"
+ const [markJobExported] = useMutation(gql`
+ mutation MARK_JOB_AS_EXPORTED($jobId: uuid!, $date_exported: timestamptz!) {
+ update_jobs_by_pk(
+ pk_columns: { id: $jobId }
+ _set: { date_exported: $date_exported
+ status: "${bodyshop.md_ro_statuses.default_exported}"
+ }
+ ) {
+ id
+ date_exported
+ date_invoiced
+ status
+ }
}
- ) {
- id
- date_exported
- date_invoiced
- status
- }
- }
- `);
- const [markJobUninvoiced] = useMutation(gql`
- mutation MARK_JOB_AS_UNINVOICED($jobId: uuid!, ) {
- update_jobs_by_pk(
- pk_columns: { id: $jobId }
- _set: { date_exported: null
- date_invoiced: null
- status: "${bodyshop.md_ro_statuses.default_delivered}"
+ `);
+ const [markJobUninvoiced] = useMutation(gql`
+ mutation MARK_JOB_AS_UNINVOICED($jobId: uuid!, ) {
+ update_jobs_by_pk(
+ pk_columns: { id: $jobId }
+ _set: { date_exported: null
+ date_invoiced: null
+ status: "${bodyshop.md_ro_statuses.default_delivered}"
+ }
+ ) {
+ id
+ date_exported
+ date_invoiced
+ status
+ }
}
- ) {
- id
- date_exported
- date_invoiced
- status
- }
- }
- `);
+ `);
- const handleMarkForExport = async () => {
- setLoading(true);
- const result = await markJobForReexport({
- variables: { jobId: job.id },
- });
+ const handleMarkForExport = async () => {
+ setLoading(true);
+ const result = await markJobForReexport({
+ variables: {jobId: job.id},
+ });
- if (!result.errors) {
- notification["success"]({ message: t("jobs.successes.save") });
- insertAuditTrail({
- jobid: job.id,
- operation: AuditTrailMapping.admin_jobmarkforreexport(),
- });
- } else {
- notification["error"]({
- message: t("jobs.errors.saving", {
- error: JSON.stringify(result.errors),
- }),
- });
- }
- setLoading(false);
- };
+ if (!result.errors) {
+ notification["success"]({message: t("jobs.successes.save")});
+ insertAuditTrail({
+ jobid: job.id,
+ operation: AuditTrailMapping.admin_jobmarkforreexport(),
+ });
+ } else {
+ notification["error"]({
+ message: t("jobs.errors.saving", {
+ error: JSON.stringify(result.errors),
+ }),
+ });
+ }
+ setLoading(false);
+ };
- const handleMarkExported = async () => {
- setLoading(true);
- const result = await markJobExported({
- variables: { jobId: job.id, date_exported: moment() },
- });
+ const handleMarkExported = async () => {
+ setLoading(true);
+ const result = await markJobExported({
+ variables: {jobId: job.id, date_exported: dayjs()},
+ });
- await insertExportLog({
- variables: {
- logs: [
- {
- bodyshopid: bodyshop.id,
- jobid: job.id,
- successful: true,
- message: JSON.stringify([t("general.labels.markedexported")]),
- useremail: currentUser.email,
- },
- ],
- },
- });
+ await insertExportLog({
+ variables: {
+ logs: [
+ {
+ bodyshopid: bodyshop.id,
+ jobid: job.id,
+ successful: true,
+ message: JSON.stringify([t("general.labels.markedexported")]),
+ useremail: currentUser.email,
+ },
+ ],
+ },
+ });
- if (!result.errors) {
- notification["success"]({ message: t("jobs.successes.save") });
- insertAuditTrail({
- jobid: job.id,
- operation: AuditTrailMapping.admin_jobmarkexported(),
- });
- } else {
- notification["error"]({
- message: t("jobs.errors.saving", {
- error: JSON.stringify(result.errors),
- }),
- });
- }
- setLoading(false);
- };
+ if (!result.errors) {
+ notification["success"]({message: t("jobs.successes.save")});
+ insertAuditTrail({
+ jobid: job.id,
+ operation: AuditTrailMapping.admin_jobmarkexported(),
+ });
+ } else {
+ notification["error"]({
+ message: t("jobs.errors.saving", {
+ error: JSON.stringify(result.errors),
+ }),
+ });
+ }
+ setLoading(false);
+ };
- const handleUninvoice = async () => {
- setLoading(true);
- const result = await markJobUninvoiced({
- variables: { jobId: job.id },
- });
+ const handleUninvoice = async () => {
+ setLoading(true);
+ const result = await markJobUninvoiced({
+ variables: {jobId: job.id},
+ });
- if (!result.errors) {
- notification["success"]({ message: t("jobs.successes.save") });
- insertAuditTrail({
- jobid: job.id,
- operation: AuditTrailMapping.admin_jobuninvoice(),
- });
- } else {
- notification["error"]({
- message: t("jobs.errors.saving", {
- error: JSON.stringify(result.errors),
- }),
- });
- }
- setLoading(false);
- };
+ if (!result.errors) {
+ notification["success"]({message: t("jobs.successes.save")});
+ insertAuditTrail({
+ jobid: job.id,
+ operation: AuditTrailMapping.admin_jobuninvoice(),
+ });
+ } else {
+ notification["error"]({
+ message: t("jobs.errors.saving", {
+ error: JSON.stringify(result.errors),
+ }),
+ });
+ }
+ setLoading(false);
+ };
- return (
- <>
-
- {t("jobs.labels.markforreexport")}
-
-
- {t("jobs.actions.markasexported")}
-
-
- {t("jobs.actions.uninvoice")}
-
- >
- );
+ return (
+ <>
+
+ {t("jobs.labels.markforreexport")}
+
+
+ {t("jobs.actions.markasexported")}
+
+
+ {t("jobs.actions.uninvoice")}
+
+ >
+ );
}
diff --git a/client/src/components/jobs-admin-owner-reassociate/jobs-admin-owner-reassociate.component.jsx b/client/src/components/jobs-admin-owner-reassociate/jobs-admin-owner-reassociate.component.jsx
index 27f468526..737753cdb 100644
--- a/client/src/components/jobs-admin-owner-reassociate/jobs-admin-owner-reassociate.component.jsx
+++ b/client/src/components/jobs-admin-owner-reassociate/jobs-admin-owner-reassociate.component.jsx
@@ -1,63 +1,64 @@
-import { useMutation } from "@apollo/client";
-import { Button, Form, notification } from "antd";
-import React, { useEffect, useState } from "react";
-import { useTranslation } from "react-i18next";
-import { UPDATE_JOB } from "../../graphql/jobs.queries";
+import {useMutation} from "@apollo/client";
+import {Button, Form, notification} from "antd";
+import React, {useEffect, useState} from "react";
+import {useTranslation} from "react-i18next";
+import {UPDATE_JOB} from "../../graphql/jobs.queries";
import OwnerSearchSelect from "../owner-search-select/owner-search-select.component";
-export default function JobAdminOwnerReassociate({ job }) {
- const { t } = useTranslation();
- const [loading, setLoading] = useState(false);
- const [form] = Form.useForm();
- const [updateJob] = useMutation(UPDATE_JOB);
- const handleFinish = async (values) => {
- setLoading(true);
- const result = await updateJob({
- variables: { jobId: job.id, job: { ownerid: values.ownerid } },
- });
- if (!!!result.errors) {
- notification["success"]({ message: t("jobs.successes.save") });
- } else {
- notification["error"]({
- message: t("jobs.errors.saving", {
- error: JSON.stringify(result.errors),
- }),
- });
- }
- setLoading(false);
- //Get the owner details, populate it all back into the job.
- };
+export default function JobAdminOwnerReassociate({job}) {
+ const {t} = useTranslation();
+ const [loading, setLoading] = useState(false);
+ const [form] = Form.useForm();
+ const [updateJob] = useMutation(UPDATE_JOB);
+ const handleFinish = async (values) => {
+ setLoading(true);
+ const result = await updateJob({
+ variables: {jobId: job.id, job: {ownerid: values.ownerid}},
+ });
- useEffect(() => {
- //form.resetFields();
- }, [form, job]);
+ if (!!!result.errors) {
+ notification["success"]({message: t("jobs.successes.save")});
+ } else {
+ notification["error"]({
+ message: t("jobs.errors.saving", {
+ error: JSON.stringify(result.errors),
+ }),
+ });
+ }
+ setLoading(false);
+ //Get the owner details, populate it all back into the job.
+ };
- return (
-
-
{t("jobs.labels.ownerassociation")}
-
-
-
-
-
{t("jobs.labels.associationwarning")}
-
form.submit()}>
- {t("general.actions.save")}
-
-
- );
+ useEffect(() => {
+ //form.resetFields();
+ }, [form, job]);
+
+ return (
+
+
{t("jobs.labels.ownerassociation")}
+
+
+
+
+
{t("jobs.labels.associationwarning")}
+
form.submit()}>
+ {t("general.actions.save")}
+
+
+ );
}
diff --git a/client/src/components/jobs-admin-unvoid/jobs-admin-unvoid.component.jsx b/client/src/components/jobs-admin-unvoid/jobs-admin-unvoid.component.jsx
index 7963fd05f..1fe074ca3 100644
--- a/client/src/components/jobs-admin-unvoid/jobs-admin-unvoid.component.jsx
+++ b/client/src/components/jobs-admin-unvoid/jobs-admin-unvoid.component.jsx
@@ -1,117 +1,114 @@
-import { gql, useMutation } from "@apollo/client";
-import { Button, notification } from "antd";
-import React, { useState } from "react";
-import { useTranslation } from "react-i18next";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { insertAuditTrail } from "../../redux/application/application.actions";
-import {
- selectBodyshop,
- selectCurrentUser,
-} from "../../redux/user/user.selectors";
+import {gql, useMutation} from "@apollo/client";
+import {Button, notification} from "antd";
+import React, {useState} from "react";
+import {useTranslation} from "react-i18next";
+import {connect} from "react-redux";
+import {createStructuredSelector} from "reselect";
+import {insertAuditTrail} from "../../redux/application/application.actions";
+import {selectBodyshop, selectCurrentUser,} from "../../redux/user/user.selectors";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
const mapStateToProps = createStructuredSelector({
- bodyshop: selectBodyshop,
- currentUser: selectCurrentUser,
+ bodyshop: selectBodyshop,
+ currentUser: selectCurrentUser,
});
const mapDispatchToProps = (dispatch) => ({
- insertAuditTrail: ({ jobid, operation }) =>
- dispatch(insertAuditTrail({ jobid, operation })),
+ insertAuditTrail: ({jobid, operation}) =>
+ dispatch(insertAuditTrail({jobid, operation})),
});
export default connect(mapStateToProps, mapDispatchToProps)(JobsAdminUnvoid);
export function JobsAdminUnvoid({
- insertAuditTrail,
- bodyshop,
- job,
- currentUser,
-}) {
- const { t } = useTranslation();
- const [loading, setLoading] = useState(false);
- const [updateJob] = useMutation(gql`
-mutation UNVOID_JOB($jobId: uuid!) {
- update_jobs_by_pk(pk_columns: {id: $jobId}, _set: {voided: false, status: "${
+ insertAuditTrail,
+ bodyshop,
+ job,
+ currentUser,
+ }) {
+ const {t} = useTranslation();
+ const [loading, setLoading] = useState(false);
+ const [updateJob] = useMutation(gql`
+ mutation UNVOID_JOB($jobId: uuid!) {
+ update_jobs_by_pk(pk_columns: {id: $jobId}, _set: {voided: false, status: "${
bodyshop.md_ro_statuses.default_imported
- }", date_void: null}) {
+ }", date_void: null}) {
id
- date_void
- voided
- status
- }
- insert_notes(objects: {jobid: $jobId, audit: true, created_by: "${
+ date_void
+ voided
+ status
+ }
+ insert_notes(objects: {jobid: $jobId, audit: true, created_by: "${
currentUser.email
- }", text: "${t("jobs.labels.unvoidnote")}"}) {
+ }", text: "${t("jobs.labels.unvoidnote")}"}) {
returning {
- id
- }
- }
-}
-
- `);
-
- // const result = await voidJob({
- // variables: {
- // jobId: job.id,
- // job: {
- // status: bodyshop.md_ro_statuses.default_void,
- // voided: true,
- // },
- // note: [
- // {
- // jobid: job.id,
- // created_by: currentUser.email,
- // audit: true,
- // text: t("jobs.labels.voidnote", {
- // date: moment().format("MM/DD/yyy"),
- // time: moment().format("hh:mm a"),
- // }),
- // },
- // ],
- // },
- // });
-
- // if (!!!result.errors) {
- // notification["success"]({
- // message: t("jobs.successes.voided"),
- // });
- // //go back to jobs list.
- // history.push(`/manage/`);
- // } else {
- // notification["error"]({
- // message: t("jobs.errors.voiding", {
- // error: JSON.stringify(result.errors),
- // }),
- // });
- // }
-
- const handleUpdate = async (values) => {
- setLoading(true);
- const result = await updateJob({
- variables: { jobId: job.id },
- });
-
- if (!result.errors) {
- notification["success"]({ message: t("jobs.successes.save") });
-
- insertAuditTrail({
- jobid: job.id,
- operation: AuditTrailMapping.admin_jobunvoid(),
- });
- } else {
- notification["error"]({
- message: t("jobs.errors.saving", {
- error: JSON.stringify(result.errors),
- }),
- });
- }
- setLoading(false);
- //Get the owner details, populate it all back into the job.
- };
-
- return (
-
- {t("jobs.actions.unvoid")}
-
- );
+ id
+ }
+ }
+ }
+
+ `);
+
+ // const result = await voidJob({
+ // variables: {
+ // jobId: job.id,
+ // job: {
+ // status: bodyshop.md_ro_statuses.default_void,
+ // voided: true,
+ // },
+ // note: [
+ // {
+ // jobid: job.id,
+ // created_by: currentUser.email,
+ // audit: true,
+ // text: t("jobs.labels.voidnote", {
+ // date: dayjs().format("MM/DD/yyy"),
+ // time: dayjs().format("hh:mm a"),
+ // }),
+ // },
+ // ],
+ // },
+ // });
+
+ // if (!!!result.errors) {
+ // notification["success"]({
+ // message: t("jobs.successes.voided"),
+ // });
+ // //go back to jobs list.
+ // history.push(`/manage/`);
+ // } else {
+ // notification["error"]({
+ // message: t("jobs.errors.voiding", {
+ // error: JSON.stringify(result.errors),
+ // }),
+ // });
+ // }
+
+ const handleUpdate = async (values) => {
+ setLoading(true);
+ const result = await updateJob({
+ variables: {jobId: job.id},
+ });
+
+ if (!result.errors) {
+ notification["success"]({message: t("jobs.successes.save")});
+
+ insertAuditTrail({
+ jobid: job.id,
+ operation: AuditTrailMapping.admin_jobunvoid(),
+ });
+ } else {
+ notification["error"]({
+ message: t("jobs.errors.saving", {
+ error: JSON.stringify(result.errors),
+ }),
+ });
+ }
+ setLoading(false);
+ //Get the owner details, populate it all back into the job.
+ };
+
+ return (
+
+ {t("jobs.actions.unvoid")}
+
+ );
}
diff --git a/client/src/components/jobs-admin-vehicle-reassociate/jobs-admin-vehicle-reassociate.component.jsx b/client/src/components/jobs-admin-vehicle-reassociate/jobs-admin-vehicle-reassociate.component.jsx
index 060d24de5..60e9c268e 100644
--- a/client/src/components/jobs-admin-vehicle-reassociate/jobs-admin-vehicle-reassociate.component.jsx
+++ b/client/src/components/jobs-admin-vehicle-reassociate/jobs-admin-vehicle-reassociate.component.jsx
@@ -1,63 +1,64 @@
-import { useMutation } from "@apollo/client";
-import { Button, Form, notification } from "antd";
-import React, { useEffect, useState } from "react";
-import { useTranslation } from "react-i18next";
-import { UPDATE_JOB } from "../../graphql/jobs.queries";
+import {useMutation} from "@apollo/client";
+import {Button, Form, notification} from "antd";
+import React, {useEffect, useState} from "react";
+import {useTranslation} from "react-i18next";
+import {UPDATE_JOB} from "../../graphql/jobs.queries";
import VehicleSearchSelect from "../vehicle-search-select/vehicle-search-select.component";
-export default function JobAdminOwnerReassociate({ job }) {
- const { t } = useTranslation();
- const [loading, setLoading] = useState(false);
- const [form] = Form.useForm();
- const [updateJob] = useMutation(UPDATE_JOB);
- const handleFinish = async (values) => {
- setLoading(true);
- const result = await updateJob({
- variables: { jobId: job.id, job: { vehicleid: values.vehicleid } },
- });
- if (!!!result.errors) {
- notification["success"]({ message: t("jobs.successes.save") });
- } else {
- notification["error"]({
- message: t("jobs.errors.saving", {
- error: JSON.stringify(result.errors),
- }),
- });
- }
- setLoading(false);
- //Get the owner details, populate it all back into the job.
- };
+export default function JobAdminOwnerReassociate({job}) {
+ const {t} = useTranslation();
+ const [loading, setLoading] = useState(false);
+ const [form] = Form.useForm();
+ const [updateJob] = useMutation(UPDATE_JOB);
+ const handleFinish = async (values) => {
+ setLoading(true);
+ const result = await updateJob({
+ variables: {jobId: job.id, job: {vehicleid: values.vehicleid}},
+ });
- useEffect(() => {
- //form.resetFields();
- }, [form, job]);
+ if (!!!result.errors) {
+ notification["success"]({message: t("jobs.successes.save")});
+ } else {
+ notification["error"]({
+ message: t("jobs.errors.saving", {
+ error: JSON.stringify(result.errors),
+ }),
+ });
+ }
+ setLoading(false);
+ //Get the owner details, populate it all back into the job.
+ };
- return (
-
-
{t("jobs.labels.vehicleassociation")}
-
-
-
-
-
{t("jobs.labels.associationwarning")}
-
form.submit()}>
- {t("general.actions.save")}
-
-
- );
+ useEffect(() => {
+ //form.resetFields();
+ }, [form, job]);
+
+ return (
+
+
{t("jobs.labels.vehicleassociation")}
+
+
+
+
+
{t("jobs.labels.associationwarning")}
+
form.submit()}>
+ {t("general.actions.save")}
+
+
+ );
}
diff --git a/client/src/components/jobs-available-scan/jobs-available-scan.component.jsx b/client/src/components/jobs-available-scan/jobs-available-scan.component.jsx
index d2f41f5a8..a0dc4491b 100644
--- a/client/src/components/jobs-available-scan/jobs-available-scan.component.jsx
+++ b/client/src/components/jobs-available-scan/jobs-available-scan.component.jsx
@@ -1,158 +1,159 @@
-import { DownloadOutlined, SyncOutlined } from "@ant-design/icons";
-import { Button, Card, Input, notification, Space, Table } from "antd";
+import {DownloadOutlined, SyncOutlined} from "@ant-design/icons";
+import {Button, Card, Input, notification, Space, Table} from "antd";
import axios from "axios";
-import React, { useState } from "react";
-import { useTranslation } from "react-i18next";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { selectPartnerVersion } from "../../redux/application/application.selectors";
-import { alphaSort } from "../../utils/sorters";
+import React, {useState} from "react";
+import {useTranslation} from "react-i18next";
+import {connect} from "react-redux";
+import {createStructuredSelector} from "reselect";
+import {selectPartnerVersion} from "../../redux/application/application.selectors";
+import {alphaSort} from "../../utils/sorters";
+
const mapStateToProps = createStructuredSelector({
- //currentUser: selectCurrentUser
- partnerVersion: selectPartnerVersion,
+ //currentUser: selectCurrentUser
+ partnerVersion: selectPartnerVersion,
});
const mapDispatchToProps = (dispatch) => ({
- //setUserLanguage: language => dispatch(setUserLanguage(language))
+ //setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(mapStateToProps, mapDispatchToProps)(JobsAvailableScan);
-export function JobsAvailableScan({ partnerVersion, refetch }) {
- const [estimatesOnDisk, setEstimatesOnDisk] = useState([]);
- const [loading, setLoading] = useState(false);
- const [searchText, setSearchText] = useState("");
- const [state, setState] = useState({
- sortedInfo: {},
- filteredInfo: { text: "" },
- });
- const { t } = useTranslation();
-
- const handleTableChange = (pagination, filters, sorter) => {
- setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
- };
-
- const handleImport = async (filepath) => {
- setLoading(true);
- const response = await axios.post("http://localhost:1337/import/", {
- filepath,
+export function JobsAvailableScan({partnerVersion, refetch}) {
+ const [estimatesOnDisk, setEstimatesOnDisk] = useState([]);
+ const [loading, setLoading] = useState(false);
+ const [searchText, setSearchText] = useState("");
+ const [state, setState] = useState({
+ sortedInfo: {},
+ filteredInfo: {text: ""},
});
- if (response.data.success) {
- //Came through
- if (refetch) refetch();
- } else {
- notification["error"]({
- message: t("jobs.errors.scanimport", { message: response.data.error }),
- });
- }
- setLoading(false);
- };
+ const {t} = useTranslation();
- const columns = [
- {
- title: t("jobs.fields.cieca_id"),
- dataIndex: "cieca_id",
- key: "cieca_id",
- sorter: (a, b) => alphaSort(a, b),
- sortOrder:
- state.sortedInfo.columnKey === "cieca_id" && state.sortedInfo.order,
- },
- {
- title: t("jobs.fields.owner"),
- dataIndex: "owner",
- key: "owner",
- ellipsis: true,
- sorter: (a, b) => alphaSort(a.owner, b.owner),
- sortOrder:
- state.sortedInfo.columnKey === "owner" && state.sortedInfo.order,
- },
- {
- title: t("jobs.fields.vehicle"),
- dataIndex: "vehicle",
- key: "vehicle",
- sorter: (a, b) => alphaSort(a.vehicle, b.vehicle),
- sortOrder:
- state.sortedInfo.columnKey === "vehicle" && state.sortedInfo.order,
- },
- {
- title: t("jobs.fields.clm_no"),
- dataIndex: "clm_no",
- key: "clm_no",
- sorter: (a, b) => alphaSort(a.clm_no, b.clm_no),
- sortOrder:
- state.sortedInfo.columnKey === "clm_no" && state.sortedInfo.order,
- },
- {
- title: t("jobs.fields.ins_co_nm"),
- dataIndex: "ins_co_nm",
- key: "ins_co_nm",
- sorter: (a, b) => alphaSort(a.ins_co_nm, b.ins_co_nm),
- sortOrder:
- state.sortedInfo.columnKey === "ins_co_nm" && state.sortedInfo.order,
- },
- {
- title: t("general.labels.actions"),
- key: "actions",
- render: (text, record) => (
- handleImport(record.filepath)}>
-
-
- ),
- },
- ];
+ const handleTableChange = (pagination, filters, sorter) => {
+ setState({...state, filteredInfo: filters, sortedInfo: sorter});
+ };
- const scanEstimates = async () => {
- setLoading(true);
- const estimatesOnDiskResponse = await axios.post(
- "http://localhost:1337/scan/"
+ const handleImport = async (filepath) => {
+ setLoading(true);
+ const response = await axios.post("http://localhost:1337/import/", {
+ filepath,
+ });
+ if (response.data.success) {
+ //Came through
+ if (refetch) refetch();
+ } else {
+ notification["error"]({
+ message: t("jobs.errors.scanimport", {message: response.data.error}),
+ });
+ }
+ setLoading(false);
+ };
+
+ const columns = [
+ {
+ title: t("jobs.fields.cieca_id"),
+ dataIndex: "cieca_id",
+ key: "cieca_id",
+ sorter: (a, b) => alphaSort(a, b),
+ sortOrder:
+ state.sortedInfo.columnKey === "cieca_id" && state.sortedInfo.order,
+ },
+ {
+ title: t("jobs.fields.owner"),
+ dataIndex: "owner",
+ key: "owner",
+ ellipsis: true,
+ sorter: (a, b) => alphaSort(a.owner, b.owner),
+ sortOrder:
+ state.sortedInfo.columnKey === "owner" && state.sortedInfo.order,
+ },
+ {
+ title: t("jobs.fields.vehicle"),
+ dataIndex: "vehicle",
+ key: "vehicle",
+ sorter: (a, b) => alphaSort(a.vehicle, b.vehicle),
+ sortOrder:
+ state.sortedInfo.columnKey === "vehicle" && state.sortedInfo.order,
+ },
+ {
+ title: t("jobs.fields.clm_no"),
+ dataIndex: "clm_no",
+ key: "clm_no",
+ sorter: (a, b) => alphaSort(a.clm_no, b.clm_no),
+ sortOrder:
+ state.sortedInfo.columnKey === "clm_no" && state.sortedInfo.order,
+ },
+ {
+ title: t("jobs.fields.ins_co_nm"),
+ dataIndex: "ins_co_nm",
+ key: "ins_co_nm",
+ sorter: (a, b) => alphaSort(a.ins_co_nm, b.ins_co_nm),
+ sortOrder:
+ state.sortedInfo.columnKey === "ins_co_nm" && state.sortedInfo.order,
+ },
+ {
+ title: t("general.labels.actions"),
+ key: "actions",
+ render: (text, record) => (
+ handleImport(record.filepath)}>
+
+
+ ),
+ },
+ ];
+
+ const scanEstimates = async () => {
+ setLoading(true);
+ const estimatesOnDiskResponse = await axios.post(
+ "http://localhost:1337/scan/"
+ );
+ setEstimatesOnDisk(estimatesOnDiskResponse.data);
+ setLoading(false);
+ };
+
+ const data = estimatesOnDisk
+ ? searchText
+ ? estimatesOnDisk.filter(
+ (j) =>
+ (j.owner || "").toLowerCase().includes(searchText.toLowerCase()) ||
+ (j.vehicle || "")
+ .toLowerCase()
+ .includes(searchText.toLowerCase()) ||
+ (j.clm_no || "").toLowerCase().includes(searchText.toLowerCase())
+ )
+ : estimatesOnDisk
+ : [];
+
+ return (
+
+ {
+ scanEstimates();
+ }}
+ >
+
+
+
+ {
+ setSearchText(e.currentTarget.value);
+ }}
+ />
+
+ }
+ >
+
+
);
- setEstimatesOnDisk(estimatesOnDiskResponse.data);
- setLoading(false);
- };
-
- const data = estimatesOnDisk
- ? searchText
- ? estimatesOnDisk.filter(
- (j) =>
- (j.owner || "").toLowerCase().includes(searchText.toLowerCase()) ||
- (j.vehicle || "")
- .toLowerCase()
- .includes(searchText.toLowerCase()) ||
- (j.clm_no || "").toLowerCase().includes(searchText.toLowerCase())
- )
- : estimatesOnDisk
- : [];
-
- return (
-
- {
- scanEstimates();
- }}
- >
-
-
-
- {
- setSearchText(e.currentTarget.value);
- }}
- />
-
- }
- >
-
-
- );
}
diff --git a/client/src/components/jobs-available-table/jobs-available-supplement.estlines.util.js b/client/src/components/jobs-available-table/jobs-available-supplement.estlines.util.js
index 6849609be..8d7c6d58d 100644
--- a/client/src/components/jobs-available-table/jobs-available-supplement.estlines.util.js
+++ b/client/src/components/jobs-available-table/jobs-available-supplement.estlines.util.js
@@ -1,78 +1,78 @@
-import { gql } from "@apollo/client";
+import {gql} from "@apollo/client";
import _ from "lodash";
-import { GET_ALL_JOBLINES_BY_PK } from "../../graphql/jobs-lines.queries";
+import {GET_ALL_JOBLINES_BY_PK} from "../../graphql/jobs-lines.queries";
export const GetSupplementDelta = async (client, jobId, newLines) => {
- const {
- data: { joblines: existingLinesFromDb },
- } = await client.query({
- query: GET_ALL_JOBLINES_BY_PK,
- variables: { id: jobId },
- });
-
- const existingLines = _.cloneDeep(existingLinesFromDb);
- const linesToInsert = [];
- const linesToUpdate = [];
-
- newLines.forEach((newLine) => {
- const matchingIndex = existingLines.findIndex(
- (eL) => eL.unq_seq === newLine.unq_seq
- );
-
- //Should do a check to make sure there is only 1 matching unq sequence number.
-
- if (matchingIndex >= 0) {
- //Found a relevant matching line. Add it to lines to update.
- linesToUpdate.push({
- id: existingLines[matchingIndex].id,
- newData: { ...newLine, removed: false, act_price_before_ppc: null },
- });
-
- //Splice out item we found for performance.
- existingLines.splice(matchingIndex, 1);
- } else {
- //Didn't find a match. Must be a new line.
- linesToInsert.push(newLine);
- }
- });
-
- //Wahtever is left in the existing lines, are lines that should be removed.
- const insertQueries = linesToInsert.reduce((acc, value, idx) => {
- return acc + generateInsertQuery(value, idx, jobId);
- }, "");
-
- const updateQueries = linesToUpdate.reduce((acc, value, idx) => {
- return acc + generateUpdateQuery(value, idx);
- }, "");
-
- const removeQueries = existingLines
- .filter((l) => !l.manual_line)
- .reduce((acc, value, idx) => {
- return acc + generateRemoveQuery(value, idx);
- }, "");
- //console.log(insertQueries, updateQueries, removeQueries);
-
- if ((insertQueries + updateQueries + removeQueries).trim() === "") {
- return new Promise((resolve, reject) => {
- resolve(null);
+ const {
+ data: {joblines: existingLinesFromDb},
+ } = await client.query({
+ query: GET_ALL_JOBLINES_BY_PK,
+ variables: {id: jobId},
});
- }
- return new Promise((resolve, reject) => {
- resolve(gql`
- mutation SUPPLEMENT_EST_LINES{
- ${insertQueries + updateQueries + removeQueries}
+ const existingLines = _.cloneDeep(existingLinesFromDb);
+ const linesToInsert = [];
+ const linesToUpdate = [];
+
+ newLines.forEach((newLine) => {
+ const matchingIndex = existingLines.findIndex(
+ (eL) => eL.unq_seq === newLine.unq_seq
+ );
+
+ //Should do a check to make sure there is only 1 matching unq sequence number.
+
+ if (matchingIndex >= 0) {
+ //Found a relevant matching line. Add it to lines to update.
+ linesToUpdate.push({
+ id: existingLines[matchingIndex].id,
+ newData: {...newLine, removed: false, act_price_before_ppc: null},
+ });
+
+ //Splice out item we found for performance.
+ existingLines.splice(matchingIndex, 1);
+ } else {
+ //Didn't find a match. Must be a new line.
+ linesToInsert.push(newLine);
+ }
+ });
+
+ //Wahtever is left in the existing lines, are lines that should be removed.
+ const insertQueries = linesToInsert.reduce((acc, value, idx) => {
+ return acc + generateInsertQuery(value, idx, jobId);
+ }, "");
+
+ const updateQueries = linesToUpdate.reduce((acc, value, idx) => {
+ return acc + generateUpdateQuery(value, idx);
+ }, "");
+
+ const removeQueries = existingLines
+ .filter((l) => !l.manual_line)
+ .reduce((acc, value, idx) => {
+ return acc + generateRemoveQuery(value, idx);
+ }, "");
+ //console.log(insertQueries, updateQueries, removeQueries);
+
+ if ((insertQueries + updateQueries + removeQueries).trim() === "") {
+ return new Promise((resolve, reject) => {
+ resolve(null);
+ });
}
- `);
- });
+
+ return new Promise((resolve, reject) => {
+ resolve(gql`
+ mutation SUPPLEMENT_EST_LINES{
+ ${insertQueries + updateQueries + removeQueries}
+ }
+ `);
+ });
};
const generateInsertQuery = (lineToInsert, index, jobId) => {
- return `
+ return `
insert_joblines${index}: insert_joblines(objects: ${JSON.stringify({
- ...lineToInsert,
- jobid: jobId,
- }).replace(/"(\w+)"\s*:/g, "$1:")}) {
+ ...lineToInsert,
+ jobid: jobId,
+ }).replace(/"(\w+)"\s*:/g, "$1:")}) {
returning {
id
}
@@ -80,13 +80,13 @@ const generateInsertQuery = (lineToInsert, index, jobId) => {
};
const generateUpdateQuery = (lineToUpdate, index) => {
- return `
+ return `
update_joblines${index}: update_joblines(where: { id: { _eq: "${
- lineToUpdate.id
- }" } }, _set: ${JSON.stringify(lineToUpdate.newData).replace(
- /"(\w+)"\s*:/g,
- "$1:"
- )}) {
+ lineToUpdate.id
+ }" } }, _set: ${JSON.stringify(lineToUpdate.newData).replace(
+ /"(\w+)"\s*:/g,
+ "$1:"
+ )}) {
returning {
id
}
@@ -94,7 +94,7 @@ const generateUpdateQuery = (lineToUpdate, index) => {
};
const generateRemoveQuery = (lineToRemove, index) => {
- return `
+ return `
update_joblines_r${index}: update_joblines(where: {id: {_eq: "${lineToRemove.id}"}}, _set: {removed: true}) {
returning{
id
diff --git a/client/src/components/jobs-available-table/jobs-available-supplement.headerfields.js b/client/src/components/jobs-available-table/jobs-available-supplement.headerfields.js
index 07e91f8ea..348779424 100644
--- a/client/src/components/jobs-available-table/jobs-available-supplement.headerfields.js
+++ b/client/src/components/jobs-available-table/jobs-available-supplement.headerfields.js
@@ -1,234 +1,234 @@
const headerFields = [
- //AD1
- "ins_co_id",
- "ins_co_nm",
- "ins_addr1",
- "ins_addr2",
- "ins_city",
- "ins_st",
- "ins_zip",
- "ins_ctry",
- "ins_ea",
- "policy_no",
- "ded_amt",
- "ded_status",
- "asgn_no",
- "asgn_date",
- "asgn_type",
- "clm_no",
- "clm_ofc_id",
- "clm_ofc_nm",
- "clm_addr1",
- "clm_addr2",
- "clm_city",
- "clm_st",
- "clm_zip",
- "clm_ctry",
- "clm_ph1",
- "clm_ph1x",
- "clm_ph2",
- "clm_ph2x",
- "clm_fax",
- "clm_faxx",
- "clm_ct_ln",
- "clm_ct_fn",
- "clm_title",
- "clm_ct_ph",
- "clm_ct_phx",
- "clm_ea",
- "payee_nms",
- "pay_type",
- "pay_date",
- "pay_chknm",
- "pay_amt",
- "agt_co_id",
- "agt_co_nm",
- "agt_addr1",
- "agt_addr2",
- "agt_city",
- "agt_st",
- "agt_zip",
- "agt_ctry",
- "agt_ph1",
- "agt_ph1x",
- "agt_ph2",
- "agt_ph2x",
- "agt_fax",
- "agt_faxx",
- "agt_ct_ln",
- "agt_ct_fn",
- "agt_ct_ph",
- "agt_ct_phx",
- "agt_ea",
- "agt_lic_no",
- "loss_date",
- "loss_type",
- "loss_desc",
- "theft_ind",
- "cat_no",
- "tlos_ind",
- "cust_pr",
- "insd_ln",
- "insd_fn",
- "insd_title",
- "insd_co_nm",
- "insd_addr1",
- "insd_addr2",
- "insd_city",
- "insd_st",
- "insd_zip",
- "insd_ctry",
- "insd_ph1",
- "insd_ph1x",
- "insd_ph2",
- "insd_ph2x",
- "insd_fax",
- "insd_faxx",
- "insd_ea",
- "ownr_ln",
- "ownr_fn",
- "ownr_title",
- "ownr_co_nm",
- "ownr_addr1",
- "ownr_addr2",
- "ownr_city",
- "ownr_st",
- "ownr_zip",
- "ownr_ctry",
- "ownr_ph1",
- "ownr_ph1x",
- "ownr_ph2",
- "ownr_ph2x",
- "ownr_fax",
- "ownr_faxx",
- "ownr_ea",
- "ins_ph1",
- "ins_ph1x",
- "ins_ph2",
- "ins_ph2x",
- "ins_fax",
- "ins_faxx",
- "ins_ct_ln",
- "ins_ct_fn",
- "ins_title",
- "ins_ct_ph",
- "ins_ct_phx",
- "loss_cat",
- //AD2
- "clmt_ln",
- "clmt_fn",
- "clmt_title",
- "clmt_co_nm",
- "clmt_addr1",
- "clmt_addr2",
- "clmt_city",
- "clmt_st",
- "clmt_zip",
- "clmt_ctry",
- "clmt_ph1",
- "clmt_ph1x",
- "clmt_ph2",
- "clmt_ph2x",
- "clmt_fax",
- "clmt_faxx",
- "clmt_ea",
- "est_co_id",
- "est_co_nm",
- "est_addr1",
- "est_addr2",
- "est_city",
- "est_st",
- "est_zip",
- "est_ctry",
- "est_ph1",
- "est_ph1x",
- "est_ph2",
- "est_ph2x",
- "est_fax",
- "est_faxx",
- "est_ct_ln",
- "est_ct_fn",
- "est_ea",
- "est_lic_no",
- "est_fileno",
- "insp_ct_ln",
- "insp_ct_fn",
- "insp_addr1",
- "insp_addr2",
- "insp_city",
- "insp_st",
- "insp_zip",
- "insp_ctry",
- "insp_ph1",
- "insp_ph1x",
- "insp_ph2",
- "insp_ph2x",
- "insp_fax",
- "insp_faxx",
- "insp_ea",
- "insp_code",
- "insp_desc",
- "insp_date",
- "insp_time",
- "rf_co_id",
- "rf_co_nm",
- "rf_addr1",
- "rf_addr2",
- "rf_city",
- "rf_st",
- "rf_zip",
- "rf_ctry",
- "rf_ph1",
- "rf_ph1x",
- "rf_ph2",
- "rf_ph2x",
- "rf_fax",
- "rf_faxx",
- "rf_ct_ln",
- "rf_ct_fn",
- "rf_ea",
- "rf_tax_id",
- "rf_lic_no",
- "rf_bar_no",
- "ro_in_date",
- "ro_in_time",
- "tar_date",
- "tar_time",
- "ro_cmpdate",
- "ro_cmptime",
- "date_out",
- "time_out",
- "rf_estimtr",
- "mktg_type",
- "mktg_src",
- "loc_nm",
- "loc_addr1",
- "loc_addr2",
- "loc_city",
- "loc_st",
- "loc_zip",
- "loc_ctry",
- "loc_ph1",
- "loc_ph1x",
- "loc_ph2",
- "loc_ph2x",
- "loc_fax",
- "loc_faxx",
- "loc_ct_ln",
- "loc_ct_fn",
- "loc_title",
- "loc_ph",
- "loc_phx",
- "loc_ea",
- //VEH
- "plate_no",
- "plate_st",
- "v_vin",
- "v_model_yr",
- "v_make_desc",
- "v_model_desc",
- "v_options",
- "v_color",
+ //AD1
+ "ins_co_id",
+ "ins_co_nm",
+ "ins_addr1",
+ "ins_addr2",
+ "ins_city",
+ "ins_st",
+ "ins_zip",
+ "ins_ctry",
+ "ins_ea",
+ "policy_no",
+ "ded_amt",
+ "ded_status",
+ "asgn_no",
+ "asgn_date",
+ "asgn_type",
+ "clm_no",
+ "clm_ofc_id",
+ "clm_ofc_nm",
+ "clm_addr1",
+ "clm_addr2",
+ "clm_city",
+ "clm_st",
+ "clm_zip",
+ "clm_ctry",
+ "clm_ph1",
+ "clm_ph1x",
+ "clm_ph2",
+ "clm_ph2x",
+ "clm_fax",
+ "clm_faxx",
+ "clm_ct_ln",
+ "clm_ct_fn",
+ "clm_title",
+ "clm_ct_ph",
+ "clm_ct_phx",
+ "clm_ea",
+ "payee_nms",
+ "pay_type",
+ "pay_date",
+ "pay_chknm",
+ "pay_amt",
+ "agt_co_id",
+ "agt_co_nm",
+ "agt_addr1",
+ "agt_addr2",
+ "agt_city",
+ "agt_st",
+ "agt_zip",
+ "agt_ctry",
+ "agt_ph1",
+ "agt_ph1x",
+ "agt_ph2",
+ "agt_ph2x",
+ "agt_fax",
+ "agt_faxx",
+ "agt_ct_ln",
+ "agt_ct_fn",
+ "agt_ct_ph",
+ "agt_ct_phx",
+ "agt_ea",
+ "agt_lic_no",
+ "loss_date",
+ "loss_type",
+ "loss_desc",
+ "theft_ind",
+ "cat_no",
+ "tlos_ind",
+ "cust_pr",
+ "insd_ln",
+ "insd_fn",
+ "insd_title",
+ "insd_co_nm",
+ "insd_addr1",
+ "insd_addr2",
+ "insd_city",
+ "insd_st",
+ "insd_zip",
+ "insd_ctry",
+ "insd_ph1",
+ "insd_ph1x",
+ "insd_ph2",
+ "insd_ph2x",
+ "insd_fax",
+ "insd_faxx",
+ "insd_ea",
+ "ownr_ln",
+ "ownr_fn",
+ "ownr_title",
+ "ownr_co_nm",
+ "ownr_addr1",
+ "ownr_addr2",
+ "ownr_city",
+ "ownr_st",
+ "ownr_zip",
+ "ownr_ctry",
+ "ownr_ph1",
+ "ownr_ph1x",
+ "ownr_ph2",
+ "ownr_ph2x",
+ "ownr_fax",
+ "ownr_faxx",
+ "ownr_ea",
+ "ins_ph1",
+ "ins_ph1x",
+ "ins_ph2",
+ "ins_ph2x",
+ "ins_fax",
+ "ins_faxx",
+ "ins_ct_ln",
+ "ins_ct_fn",
+ "ins_title",
+ "ins_ct_ph",
+ "ins_ct_phx",
+ "loss_cat",
+ //AD2
+ "clmt_ln",
+ "clmt_fn",
+ "clmt_title",
+ "clmt_co_nm",
+ "clmt_addr1",
+ "clmt_addr2",
+ "clmt_city",
+ "clmt_st",
+ "clmt_zip",
+ "clmt_ctry",
+ "clmt_ph1",
+ "clmt_ph1x",
+ "clmt_ph2",
+ "clmt_ph2x",
+ "clmt_fax",
+ "clmt_faxx",
+ "clmt_ea",
+ "est_co_id",
+ "est_co_nm",
+ "est_addr1",
+ "est_addr2",
+ "est_city",
+ "est_st",
+ "est_zip",
+ "est_ctry",
+ "est_ph1",
+ "est_ph1x",
+ "est_ph2",
+ "est_ph2x",
+ "est_fax",
+ "est_faxx",
+ "est_ct_ln",
+ "est_ct_fn",
+ "est_ea",
+ "est_lic_no",
+ "est_fileno",
+ "insp_ct_ln",
+ "insp_ct_fn",
+ "insp_addr1",
+ "insp_addr2",
+ "insp_city",
+ "insp_st",
+ "insp_zip",
+ "insp_ctry",
+ "insp_ph1",
+ "insp_ph1x",
+ "insp_ph2",
+ "insp_ph2x",
+ "insp_fax",
+ "insp_faxx",
+ "insp_ea",
+ "insp_code",
+ "insp_desc",
+ "insp_date",
+ "insp_time",
+ "rf_co_id",
+ "rf_co_nm",
+ "rf_addr1",
+ "rf_addr2",
+ "rf_city",
+ "rf_st",
+ "rf_zip",
+ "rf_ctry",
+ "rf_ph1",
+ "rf_ph1x",
+ "rf_ph2",
+ "rf_ph2x",
+ "rf_fax",
+ "rf_faxx",
+ "rf_ct_ln",
+ "rf_ct_fn",
+ "rf_ea",
+ "rf_tax_id",
+ "rf_lic_no",
+ "rf_bar_no",
+ "ro_in_date",
+ "ro_in_time",
+ "tar_date",
+ "tar_time",
+ "ro_cmpdate",
+ "ro_cmptime",
+ "date_out",
+ "time_out",
+ "rf_estimtr",
+ "mktg_type",
+ "mktg_src",
+ "loc_nm",
+ "loc_addr1",
+ "loc_addr2",
+ "loc_city",
+ "loc_st",
+ "loc_zip",
+ "loc_ctry",
+ "loc_ph1",
+ "loc_ph1x",
+ "loc_ph2",
+ "loc_ph2x",
+ "loc_fax",
+ "loc_faxx",
+ "loc_ct_ln",
+ "loc_ct_fn",
+ "loc_title",
+ "loc_ph",
+ "loc_phx",
+ "loc_ea",
+ //VEH
+ "plate_no",
+ "plate_st",
+ "v_vin",
+ "v_model_yr",
+ "v_make_desc",
+ "v_model_desc",
+ "v_options",
+ "v_color",
];
export default headerFields;
diff --git a/client/src/components/jobs-available-table/jobs-available-table.component.jsx b/client/src/components/jobs-available-table/jobs-available-table.component.jsx
index 508eddc6f..475979e7f 100644
--- a/client/src/components/jobs-available-table/jobs-available-table.component.jsx
+++ b/client/src/components/jobs-available-table/jobs-available-table.component.jsx
@@ -1,262 +1,254 @@
-import {
- DeleteFilled,
- DownloadOutlined,
- PlusCircleFilled,
- SyncOutlined,
-} from "@ant-design/icons";
-import { useMutation } from "@apollo/client";
-import { Alert, Button, Card, Input, notification, Space, Table } from "antd";
-import React, { useState } from "react";
-import { useTranslation } from "react-i18next";
-import { connect } from "react-redux";
-import { Link } from "react-router-dom";
-import { createStructuredSelector } from "reselect";
-import {
- DELETE_ALL_AVAILABLE_JOBS,
- DELETE_AVAILABLE_JOB,
-} from "../../graphql/available-jobs.queries";
-import { selectBodyshop } from "../../redux/user/user.selectors";
+import {DeleteFilled, DownloadOutlined, PlusCircleFilled, SyncOutlined,} from "@ant-design/icons";
+import {useMutation} from "@apollo/client";
+import {Alert, Button, Card, Input, notification, Space, Table} from "antd";
+import React, {useState} from "react";
+import {useTranslation} from "react-i18next";
+import {connect} from "react-redux";
+import {Link} from "react-router-dom";
+import {createStructuredSelector} from "reselect";
+import {DELETE_ALL_AVAILABLE_JOBS, DELETE_AVAILABLE_JOB,} from "../../graphql/available-jobs.queries";
+import {selectBodyshop} from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
-import { TimeAgoFormatter } from "../../utils/DateFormatter";
-import { alphaSort } from "../../utils/sorters";
+import {TimeAgoFormatter} from "../../utils/DateFormatter";
+import {alphaSort} from "../../utils/sorters";
const mapStateToProps = createStructuredSelector({
- bodyshop: selectBodyshop,
+ bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
- //setUserLanguage: language => dispatch(setUserLanguage(language))
+ //setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(
- mapStateToProps,
- mapDispatchToProps
+ mapStateToProps,
+ mapDispatchToProps
)(JobsAvailableComponent);
export function JobsAvailableComponent({
- bodyshop,
- loading,
- data,
- refetch,
- addJobAsNew,
- addJobAsSupp,
-}) {
- const [deleteAllAvailableJobs] = useMutation(DELETE_ALL_AVAILABLE_JOBS);
- const [deleteJob] = useMutation(DELETE_AVAILABLE_JOB);
- const { t } = useTranslation();
- const [searchText, setSearchText] = useState("");
- const [state, setState] = useState({
- sortedInfo: {},
- filteredInfo: { text: "" },
- });
+ bodyshop,
+ loading,
+ data,
+ refetch,
+ addJobAsNew,
+ addJobAsSupp,
+ }) {
+ const [deleteAllAvailableJobs] = useMutation(DELETE_ALL_AVAILABLE_JOBS);
+ const [deleteJob] = useMutation(DELETE_AVAILABLE_JOB);
+ const {t} = useTranslation();
+ const [searchText, setSearchText] = useState("");
+ const [state, setState] = useState({
+ sortedInfo: {},
+ filteredInfo: {text: ""},
+ });
- const handleTableChange = (pagination, filters, sorter) => {
- setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
- };
+ const handleTableChange = (pagination, filters, sorter) => {
+ setState({...state, filteredInfo: filters, sortedInfo: sorter});
+ };
- const columns = [
- {
- title: t("jobs.fields.cieca_id"),
- dataIndex: "cieca_id",
- key: "cieca_id",
- sorter: (a, b) => alphaSort(a.cieca_id, b.cieca_id),
- sortOrder:
- state.sortedInfo.columnKey === "cieca_id" && state.sortedInfo.order,
- },
- {
- title: t("jobs.fields.ro_number"),
- dataIndex: "job_id",
- key: "job_id",
- //width: "8%",
- // onFilter: (value, record) => record.ro_number.includes(value),
- // filteredValue: state.filteredInfo.text || null,
- sorter: (a, b) =>
- alphaSort(a.job && a.job.ro_number, b.job && b.job.ro_number),
- sortOrder:
- state.sortedInfo.columnKey === "job_id" && state.sortedInfo.order,
- render: (text, record) =>
- record.job ? (
-
- {(record.job && record.job.ro_number) || t("general.labels.na")}
-
- ) : (
-
- {(record.job && record.job.ro_number) || t("general.labels.na")}
-
- ),
- },
- {
- title: t("jobs.fields.owner"),
- dataIndex: "ownr_name",
- key: "ownr_name",
- ellipsis: true,
- sorter: (a, b) => alphaSort(a.ownr_name, b.ownr_name),
- sortOrder:
- state.sortedInfo.columnKey === "ownr_name" && state.sortedInfo.order,
- },
- {
- title: t("jobs.fields.vehicle"),
- dataIndex: "vehicle_info",
- key: "vehicle_info",
- sorter: (a, b) => alphaSort(a.vehicle_info, b.vehicle_info),
- sortOrder:
- state.sortedInfo.columnKey === "vehicle_info" && state.sortedInfo.order,
- },
- {
- title: t("jobs.fields.clm_no"),
- dataIndex: "clm_no",
- key: "clm_no",
- sorter: (a, b) => alphaSort(a.clm_no, b.clm_no),
- sortOrder:
- state.sortedInfo.columnKey === "clm_no" && state.sortedInfo.order,
- },
- {
- title: t("jobs.fields.ins_co_nm"),
- dataIndex: "ins_co_nm",
- key: "ins_co_nm",
- sorter: (a, b) => alphaSort(a.ins_co_nm, b.ins_co_nm),
- sortOrder:
- state.sortedInfo.columnKey === "ins_co_nm" && state.sortedInfo.order,
- },
- {
- title: t("jobs.fields.clm_total"),
- dataIndex: "clm_amt",
- key: "clm_amt",
- sorter: (a, b) => a.clm_amt - b.clm_amt,
- sortOrder:
- state.sortedInfo.columnKey === "clm_amt" && state.sortedInfo.order,
- render: (text, record) => (
- {record.clm_amt}
- ),
- },
- {
- title: t("jobs.fields.uploaded_by"),
- dataIndex: "uploaded_by",
- key: "uploaded_by",
- sorter: (a, b) => alphaSort(a.uploaded_by, b.uploaded_by),
- sortOrder:
- state.sortedInfo.columnKey === "uploaded_by" && state.sortedInfo.order,
- },
- {
- title: t("jobs.fields.updated_at"),
- dataIndex: "updated_at",
- key: "updated_at",
- sorter: (a, b) => new Date(a.updated_at) - new Date(b.updated_at),
- sortOrder:
- state.sortedInfo.columnKey === "updated_at" && state.sortedInfo.order,
- render: (text, record) => (
- {record.updated_at}
- ),
- },
- {
- title: t("general.labels.actions"),
- key: "actions",
- render: (text, record) => {
- const isClosed =
- record.job &&
- (record.job.status === bodyshop.md_ro_statuses.default_exported ||
- record.job.status === bodyshop.md_ro_statuses.default_invoiced);
- return (
-
- {
- deleteJob({ variables: { id: record.id } }).then((r) => {
- notification["success"]({
- message: t("jobs.successes.deleted"),
- });
- refetch();
- });
- }}
- >
-
-
- {!isClosed && (
- <>
- addJobAsNew(record)}
- disabled={record.issupplement}
- >
-
-
- addJobAsSupp(record)}>
-
-
- >
- )}
- {isClosed && (
-
- )}
-
- );
- },
- },
- ];
+ const columns = [
+ {
+ title: t("jobs.fields.cieca_id"),
+ dataIndex: "cieca_id",
+ key: "cieca_id",
+ sorter: (a, b) => alphaSort(a.cieca_id, b.cieca_id),
+ sortOrder:
+ state.sortedInfo.columnKey === "cieca_id" && state.sortedInfo.order,
+ },
+ {
+ title: t("jobs.fields.ro_number"),
+ dataIndex: "job_id",
+ key: "job_id",
+ //width: "8%",
+ // onFilter: (value, record) => record.ro_number.includes(value),
+ // filteredValue: state.filteredInfo.text || null,
+ sorter: (a, b) =>
+ alphaSort(a.job && a.job.ro_number, b.job && b.job.ro_number),
+ sortOrder:
+ state.sortedInfo.columnKey === "job_id" && state.sortedInfo.order,
+ render: (text, record) =>
+ record.job ? (
+
+ {(record.job && record.job.ro_number) || t("general.labels.na")}
+
+ ) : (
+
+ {(record.job && record.job.ro_number) || t("general.labels.na")}
+
+ ),
+ },
+ {
+ title: t("jobs.fields.owner"),
+ dataIndex: "ownr_name",
+ key: "ownr_name",
+ ellipsis: true,
+ sorter: (a, b) => alphaSort(a.ownr_name, b.ownr_name),
+ sortOrder:
+ state.sortedInfo.columnKey === "ownr_name" && state.sortedInfo.order,
+ },
+ {
+ title: t("jobs.fields.vehicle"),
+ dataIndex: "vehicle_info",
+ key: "vehicle_info",
+ sorter: (a, b) => alphaSort(a.vehicle_info, b.vehicle_info),
+ sortOrder:
+ state.sortedInfo.columnKey === "vehicle_info" && state.sortedInfo.order,
+ },
+ {
+ title: t("jobs.fields.clm_no"),
+ dataIndex: "clm_no",
+ key: "clm_no",
+ sorter: (a, b) => alphaSort(a.clm_no, b.clm_no),
+ sortOrder:
+ state.sortedInfo.columnKey === "clm_no" && state.sortedInfo.order,
+ },
+ {
+ title: t("jobs.fields.ins_co_nm"),
+ dataIndex: "ins_co_nm",
+ key: "ins_co_nm",
+ sorter: (a, b) => alphaSort(a.ins_co_nm, b.ins_co_nm),
+ sortOrder:
+ state.sortedInfo.columnKey === "ins_co_nm" && state.sortedInfo.order,
+ },
+ {
+ title: t("jobs.fields.clm_total"),
+ dataIndex: "clm_amt",
+ key: "clm_amt",
+ sorter: (a, b) => a.clm_amt - b.clm_amt,
+ sortOrder:
+ state.sortedInfo.columnKey === "clm_amt" && state.sortedInfo.order,
+ render: (text, record) => (
+ {record.clm_amt}
+ ),
+ },
+ {
+ title: t("jobs.fields.uploaded_by"),
+ dataIndex: "uploaded_by",
+ key: "uploaded_by",
+ sorter: (a, b) => alphaSort(a.uploaded_by, b.uploaded_by),
+ sortOrder:
+ state.sortedInfo.columnKey === "uploaded_by" && state.sortedInfo.order,
+ },
+ {
+ title: t("jobs.fields.updated_at"),
+ dataIndex: "updated_at",
+ key: "updated_at",
+ sorter: (a, b) => new Date(a.updated_at) - new Date(b.updated_at),
+ sortOrder:
+ state.sortedInfo.columnKey === "updated_at" && state.sortedInfo.order,
+ render: (text, record) => (
+ {record.updated_at}
+ ),
+ },
+ {
+ title: t("general.labels.actions"),
+ key: "actions",
+ render: (text, record) => {
+ const isClosed =
+ record.job &&
+ (record.job.status === bodyshop.md_ro_statuses.default_exported ||
+ record.job.status === bodyshop.md_ro_statuses.default_invoiced);
+ return (
+
+ {
+ deleteJob({variables: {id: record.id}}).then((r) => {
+ notification["success"]({
+ message: t("jobs.successes.deleted"),
+ });
+ refetch();
+ });
+ }}
+ >
+
+
+ {!isClosed && (
+ <>
+ addJobAsNew(record)}
+ disabled={record.issupplement}
+ >
+
+
+ addJobAsSupp(record)}>
+
+
+ >
+ )}
+ {isClosed && (
+
+ )}
+
+ );
+ },
+ },
+ ];
- const availableJobs = data
- ? searchText
- ? data.available_jobs.filter(
- (j) =>
- (j.ownr_name || "")
- .toLowerCase()
- .includes(searchText.toLowerCase()) ||
- (j.vehicle_info || "")
- .toLowerCase()
- .includes(searchText.toLowerCase()) ||
- (j.clm_no || "").toLowerCase().includes(searchText.toLowerCase())
- )
- : data.available_jobs
- : [];
+ const availableJobs = data
+ ? searchText
+ ? data.available_jobs.filter(
+ (j) =>
+ (j.ownr_name || "")
+ .toLowerCase()
+ .includes(searchText.toLowerCase()) ||
+ (j.vehicle_info || "")
+ .toLowerCase()
+ .includes(searchText.toLowerCase()) ||
+ (j.clm_no || "").toLowerCase().includes(searchText.toLowerCase())
+ )
+ : data.available_jobs
+ : [];
- return (
-
- {
- refetch();
- }}
- >
-
-
- {
- deleteAllAvailableJobs()
- .then((r) => {
- notification["success"]({
- message: t("jobs.successes.all_deleted", {
- count: r.data.delete_available_jobs.affected_rows,
- }),
- });
- refetch();
- })
- .catch((r) => {
- notification["error"]({
- message: t("jobs.errors.deleted") + " " + r.message,
- });
- });
- }}
- >
- {t("general.actions.deleteall")}
-
+ return (
+
+ {
+ refetch();
+ }}
+ >
+
+
+ {
+ deleteAllAvailableJobs()
+ .then((r) => {
+ notification["success"]({
+ message: t("jobs.successes.all_deleted", {
+ count: r.data.delete_available_jobs.affected_rows,
+ }),
+ });
+ refetch();
+ })
+ .catch((r) => {
+ notification["error"]({
+ message: t("jobs.errors.deleted") + " " + r.message,
+ });
+ });
+ }}
+ >
+ {t("general.actions.deleteall")}
+
- {
- setSearchText(e.currentTarget.value);
- }}
- />
-
- }
- >
-
-
- );
+ {
+ setSearchText(e.currentTarget.value);
+ }}
+ />
+
+ }
+ >
+
+
+ );
}
diff --git a/client/src/components/jobs-available-table/jobs-available-table.container.jsx b/client/src/components/jobs-available-table/jobs-available-table.container.jsx
index 5f6443775..74ffb54b1 100644
--- a/client/src/components/jobs-available-table/jobs-available-table.container.jsx
+++ b/client/src/components/jobs-available-table/jobs-available-table.container.jsx
@@ -1,35 +1,26 @@
-import {
- gql,
- useApolloClient,
- useLazyQuery,
- useMutation,
- useQuery,
-} from "@apollo/client";
-import { useTreatments } from "@splitsoftware/splitio-react";
-import { Button, Col, Row, notification } from "antd";
+import {gql, useApolloClient, useLazyQuery, useMutation, useQuery,} from "@apollo/client";
+import {useSplitTreatments} from "@splitsoftware/splitio-react";
+import {Button, Col, notification, Row} from "antd";
import Axios from "axios";
import _ from "lodash";
-import moment from "moment";
+import dayjs from "../../utils/day";
import queryString from "query-string";
-import React, { useCallback, useEffect, useState } 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 React, {useCallback, useEffect, useState} from "react";
+import {useTranslation} from "react-i18next";
+import {connect} from "react-redux";
+import {useLocation, useNavigate} from "react-router-dom";
+import {createStructuredSelector} from "reselect";
+import {logImEXEvent} from "../../firebase/firebase.utils";
import {
- DELETE_AVAILABLE_JOB,
- QUERY_AVAILABLE_JOBS,
- QUERY_AVAILABLE_NEW_JOBS_EST_DATA_BY_PK,
+ DELETE_AVAILABLE_JOB,
+ QUERY_AVAILABLE_JOBS,
+ QUERY_AVAILABLE_NEW_JOBS_EST_DATA_BY_PK,
} from "../../graphql/available-jobs.queries";
-import { INSERT_NEW_JOB, UPDATE_JOB } from "../../graphql/jobs.queries";
-import { INSERT_NEW_NOTE } from "../../graphql/notes.queries";
-import { SEARCH_VEHICLE_BY_VIN } from "../../graphql/vehicles.queries";
-import { insertAuditTrail } from "../../redux/application/application.actions";
-import {
- selectBodyshop,
- selectCurrentUser,
-} from "../../redux/user/user.selectors";
+import {INSERT_NEW_JOB, UPDATE_JOB} from "../../graphql/jobs.queries";
+import {INSERT_NEW_NOTE} from "../../graphql/notes.queries";
+import {SEARCH_VEHICLE_BY_VIN} from "../../graphql/vehicles.queries";
+import {insertAuditTrail} from "../../redux/application/application.actions";
+import {selectBodyshop, selectCurrentUser,} from "../../redux/user/user.selectors";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
import CriticalPartsScan from "../../utils/criticalPartsScan";
import AlertComponent from "../alert/alert.component";
@@ -37,581 +28,581 @@ import JobsAvailableScan from "../jobs-available-scan/jobs-available-scan.compon
import JobsFindModalContainer from "../jobs-find-modal/jobs-find-modal.container";
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
import OwnerFindModalContainer from "../owner-find-modal/owner-find-modal.container";
-import { GetSupplementDelta } from "./jobs-available-supplement.estlines.util";
+import {GetSupplementDelta} from "./jobs-available-supplement.estlines.util";
import HeaderFields from "./jobs-available-supplement.headerfields";
import JobsAvailableTableComponent from "./jobs-available-table.component";
const mapStateToProps = createStructuredSelector({
- bodyshop: selectBodyshop,
- currentUser: selectCurrentUser,
+ bodyshop: selectBodyshop,
+ currentUser: selectCurrentUser,
});
const mapDispatchToProps = (dispatch) => ({
- insertAuditTrail: ({ jobid, operation }) =>
- dispatch(insertAuditTrail({ jobid, operation })),
+ insertAuditTrail: ({jobid, operation}) =>
+ dispatch(insertAuditTrail({jobid, operation})),
});
-export function JobsAvailableContainer({
- bodyshop,
- currentUser,
- insertAuditTrail,
-}) {
- const { CriticalPartsScanning } = useTreatments(
- ["CriticalPartsScanning"],
- {},
- bodyshop.imexshopid
- );
- const { loading, error, data, refetch } = useQuery(QUERY_AVAILABLE_JOBS, {
- fetchPolicy: "network-only",
- nextFetchPolicy: "network-only",
- });
- const { clm_no, availableJobId } = queryString.parse(useLocation().search);
- const history = useHistory();
- const { t } = useTranslation();
- const [ownerModalVisible, setOwnerModalVisible] = useState(false);
- const [jobModalVisible, setJobModalVisible] = useState(false);
+export function JobsAvailableContainer({bodyshop, currentUser, insertAuditTrail,}) {
- const [selectedJob, setSelectedJob] = useState(null);
- const [selectedOwner, setSelectedOwner] = useState(null);
- const [partsQueueToggle, setPartsQueueToggle] = useState(bodyshop.md_functionality_toggles.parts_queue_toggle);
+ const {treatments: {CriticalPartsScanning}} = useSplitTreatments({
+ attributes: {},
+ names: ["CriticalPartsScanning"],
+ splitKey: bodyshop.imexshopid,
+ });
- const [insertLoading, setInsertLoading] = useState(false);
+ const {loading, error, data, refetch} = useQuery(QUERY_AVAILABLE_JOBS, {
+ fetchPolicy: "network-only",
+ nextFetchPolicy: "network-only",
+ });
+ const {clm_no, availableJobId} = queryString.parse(useLocation().search);
+ const history = useNavigate();
+ const {t} = useTranslation();
- const [insertNote] = useMutation(INSERT_NEW_NOTE);
- const [deleteJob] = useMutation(DELETE_AVAILABLE_JOB);
- const [updateJob] = useMutation(UPDATE_JOB);
+ const [ownerModalVisible, setOwnerModalVisible] = useState(false);
+ const [jobModalVisible, setJobModalVisible] = useState(false);
- const [insertNewJob] = useMutation(INSERT_NEW_JOB);
- const client = useApolloClient();
+ const [selectedJob, setSelectedJob] = useState(null);
+ const [selectedOwner, setSelectedOwner] = useState(null);
+ const [partsQueueToggle, setPartsQueueToggle] = useState(bodyshop.md_functionality_toggles.parts_queue_toggle);
- const estDataLazyLoad = useLazyQuery(QUERY_AVAILABLE_NEW_JOBS_EST_DATA_BY_PK);
- const [loadEstData, estDataRaw] = estDataLazyLoad;
+ const [insertLoading, setInsertLoading] = useState(false);
- const importOptionsState = useState({ overrideHeaders: false });
- const importOptions = importOptionsState[0];
- const modalSearchState = useState("");
+ const [insertNote] = useMutation(INSERT_NEW_NOTE);
+ const [deleteJob] = useMutation(DELETE_AVAILABLE_JOB);
+ const [updateJob] = useMutation(UPDATE_JOB);
- //Import Scenario
- const onOwnerFindModalOk = async (lazyData) => {
- logImEXEvent("job_import_new");
+ const [insertNewJob] = useMutation(INSERT_NEW_JOB);
+ const client = useApolloClient();
- setOwnerModalVisible(false);
+ const estDataLazyLoad = useLazyQuery(QUERY_AVAILABLE_NEW_JOBS_EST_DATA_BY_PK);
+ const [loadEstData, estDataRaw] = estDataLazyLoad;
- setInsertLoading(true);
- const estData = replaceEmpty(
- lazyData?.available_jobs_by_pk || estDataRaw.data.available_jobs_by_pk
- );
+ const importOptionsState = useState({overrideHeaders: false});
+ const importOptions = importOptionsState[0];
+ const modalSearchState = useState("");
- if (!(estData && estData.est_data)) {
- //We don't have the right data. Error!
- setInsertLoading(false);
- notification["error"]({
- message: t("jobs.errors.creating", { error: "No job data present." }),
- });
- return;
- }
- // if (process.env.REACT_APP_COUNTRY === "USA") {
- //Massage the CCC file set to remove duplicate UNQ_SEQ.
- await ResolveCCCLineIssues(estData.est_data, bodyshop);
- // } else {
- //IO-539 Check for Parts Rate on PAL for SGI use case.
- await CheckTaxRates(estData.est_data, bodyshop);
- // }
- // const newTotals = (
- // await Axios.post("/job/totals", {
- // job: {
- // ...estData.est_data,
- // joblines: estData.est_data.joblines.data,
- // },
- // })
- // ).data;
+ //Import Scenario
+ const onOwnerFindModalOk = async (lazyData) => {
+ logImEXEvent("job_import_new");
- let existingVehicles;
- if (estData.est_data.v_vin) {
- //There's vehicle data, need to double-check the VIN.
- existingVehicles = await client.query({
- query: SEARCH_VEHICLE_BY_VIN,
- variables: {
- vin: estData.est_data.v_vin || estData.est_data.vehicle.data.v_vin,
- },
- });
- }
+ setOwnerModalVisible(false);
- const newJob = {
- ...estData.est_data,
- // clm_total: Dinero(newTotals.totals.total_repairs).toFormat("0.00"),
- // owner_owing: Dinero(newTotals.totals.custPayable.total).toFormat("0.00"),
- // job_totals: newTotals,
- date_open: moment(),
- status: bodyshop.md_ro_statuses.default_imported,
- notes: {
- data: {
- created_by: currentUser.email,
- audit: true,
- text: t("jobs.labels.importnote"),
- },
- },
- queued_for_parts: partsQueueToggle,
- ...(existingVehicles && existingVehicles.data.vehicles.length > 0
- ? { vehicleid: existingVehicles.data.vehicles[0].id, vehicle: null }
- : {}),
+ setInsertLoading(true);
+ const estData = replaceEmpty(
+ lazyData?.available_jobs_by_pk || estDataRaw.data.available_jobs_by_pk
+ );
+
+ if (!(estData && estData.est_data)) {
+ //We don't have the right data. Error!
+ setInsertLoading(false);
+ notification["error"]({
+ message: t("jobs.errors.creating", {error: "No job data present."}),
+ });
+ return;
+ }
+ // if (process.env.REACT_APP_COUNTRY === "USA") {
+ //Massage the CCC file set to remove duplicate UNQ_SEQ.
+ await ResolveCCCLineIssues(estData.est_data, bodyshop);
+ // } else {
+ //IO-539 Check for Parts Rate on PAL for SGI use case.
+ await CheckTaxRates(estData.est_data, bodyshop);
+ // }
+ // const newTotals = (
+ // await Axios.post("/job/totals", {
+ // job: {
+ // ...estData.est_data,
+ // joblines: estData.est_data.joblines.data,
+ // },
+ // })
+ // ).data;
+
+ let existingVehicles;
+ if (estData.est_data.v_vin) {
+ //There's vehicle data, need to double-check the VIN.
+ existingVehicles = await client.query({
+ query: SEARCH_VEHICLE_BY_VIN,
+ variables: {
+ vin: estData.est_data.v_vin || estData.est_data.vehicle.data.v_vin,
+ },
+ });
+ }
+
+ const newJob = {
+ ...estData.est_data,
+ // clm_total: Dinero(newTotals.totals.total_repairs).toFormat("0.00"),
+ // owner_owing: Dinero(newTotals.totals.custPayable.total).toFormat("0.00"),
+ // job_totals: newTotals,
+ date_open: dayjs(),
+ status: bodyshop.md_ro_statuses.default_imported,
+ notes: {
+ data: {
+ created_by: currentUser.email,
+ audit: true,
+ text: t("jobs.labels.importnote"),
+ },
+ },
+ queued_for_parts: partsQueueToggle,
+ ...(existingVehicles && existingVehicles.data.vehicles.length > 0
+ ? {vehicleid: existingVehicles.data.vehicles[0].id, vehicle: null}
+ : {}),
+ };
+
+ if (selectedOwner) {
+ newJob.ownerid = selectedOwner;
+ delete newJob.owner;
+ }
+ if (newJob.vehicleid) {
+ delete newJob.vehicle;
+ }
+
+ if (typeof newJob.kmin === "string") {
+ newJob.kmin = null;
+ }
+
+ try {
+ const r = await insertNewJob({
+ variables: {
+ job: newJob,
+ },
+ });
+ await Axios.post("/job/totalsssu", {
+ id: r.data.insert_jobs.returning[0].id,
+ });
+
+ if (CriticalPartsScanning.treatment === "on") {
+ CriticalPartsScan(r.data.insert_jobs.returning[0].id);
+ }
+ notification["success"]({
+ message: t("jobs.successes.created"),
+ onClick: () => {
+ history(`/manage/jobs/${r.data.insert_jobs.returning[0].id}`);
+ },
+ });
+ //Job has been inserted. Clean up the available jobs record.
+
+ insertAuditTrail({
+ jobid: r.data.insert_jobs.returning[0].id,
+ operation: AuditTrailMapping.jobimported(),
+ });
+
+ await deleteJob({
+ variables: {id: estData.id},
+ }).then((r) => {
+ refetch();
+ setInsertLoading(false);
+ });
+
+ setPartsQueueToggle(bodyshop.md_functionality_toggles.parts_queue_toggle);
+ } catch (r) {
+ //error while inserting
+ notification["error"]({
+ message: t("jobs.errors.creating", {error: r.message}),
+ });
+ refetch();
+ setInsertLoading(false);
+ setPartsQueueToggle(bodyshop.md_functionality_toggles.parts_queue_toggle);
+
+ }
};
- if (selectedOwner) {
- newJob.ownerid = selectedOwner;
- delete newJob.owner;
- }
- if (newJob.vehicleid) {
- delete newJob.vehicle;
- }
+ //Supplement scenario
+ const onJobFindModalOk = async () => {
+ logImEXEvent("job_import_supplement");
- if (typeof newJob.kmin === "string") {
- newJob.kmin = null;
- }
+ setJobModalVisible(false);
+ setInsertLoading(true);
- try {
- const r = await insertNewJob({
- variables: {
- job: newJob,
- },
- });
- await Axios.post("/job/totalsssu", {
- id: r.data.insert_jobs.returning[0].id,
- });
+ const estData = estDataRaw.data.available_jobs_by_pk;
- if (CriticalPartsScanning.treatment === "on") {
- CriticalPartsScan(r.data.insert_jobs.returning[0].id);
- }
- notification["success"]({
- message: t("jobs.successes.created"),
- onClick: () => {
- history.push(`/manage/jobs/${r.data.insert_jobs.returning[0].id}`);
- },
- });
- //Job has been inserted. Clean up the available jobs record.
+ if (!(estData && estData.est_data)) {
+ //We don't have the right data. Error!
+ setInsertLoading(false);
+ notification["error"]({
+ message: t("jobs.errors.creating", {error: "No job data present."}),
+ });
+ } else {
+ //create upsert job
+ let supp = replaceEmpty({...estData.est_data});
+ //IO-539 Check for Parts Rate on PAL for SGI use case.
+ await CheckTaxRates(supp, bodyshop);
+ await ResolveCCCLineIssues(supp, bodyshop);
- insertAuditTrail({
- jobid: r.data.insert_jobs.returning[0].id,
- operation: AuditTrailMapping.jobimported(),
- });
-
- await deleteJob({
- variables: { id: estData.id },
- }).then((r) => {
- refetch();
- setInsertLoading(false);
- });
-
- setPartsQueueToggle(bodyshop.md_functionality_toggles.parts_queue_toggle);
- } catch (r) {
- //error while inserting
- notification["error"]({
- message: t("jobs.errors.creating", { error: r.message }),
- });
- refetch();
- setInsertLoading(false);
- setPartsQueueToggle(bodyshop.md_functionality_toggles.parts_queue_toggle);
-
- }
- };
-
- //Supplement scenario
- const onJobFindModalOk = async () => {
- logImEXEvent("job_import_supplement");
-
- setJobModalVisible(false);
- setInsertLoading(true);
-
- const estData = estDataRaw.data.available_jobs_by_pk;
-
- if (!(estData && estData.est_data)) {
- //We don't have the right data. Error!
- setInsertLoading(false);
- notification["error"]({
- message: t("jobs.errors.creating", { error: "No job data present." }),
- });
- } else {
- //create upsert job
- let supp = replaceEmpty({ ...estData.est_data });
- //IO-539 Check for Parts Rate on PAL for SGI use case.
- await CheckTaxRates(supp, bodyshop);
- await ResolveCCCLineIssues(supp, bodyshop);
-
- delete supp.owner;
- delete supp.vehicle;
- delete supp.ins_co_nm;
- if (!importOptions.overrideHeaders) {
- HeaderFields.forEach((item) => delete supp[item]);
- }
-
- let suppDelta = await GetSupplementDelta(
- client,
- selectedJob,
- supp.joblines.data
- );
-
- delete supp.joblines;
- if (suppDelta !== null) {
- await client.mutate({
- mutation: gql`
- ${suppDelta}
- `,
- });
- }
- const updateResult = await updateJob({
- variables: {
- jobId: selectedJob,
- job: {
- ...supp,
- // clm_total: Dinero(newTotals.totals.total_repairs).toFormat("0.00"),
- // owner_owing: Dinero(newTotals.totals.custPayable.total).toFormat(
- // "0.00"
- // ),
- // job_totals: newTotals,
- queued_for_parts: partsQueueToggle,
- },
- },
- });
-
- setPartsQueueToggle(bodyshop.md_functionality_toggles.parts_queue_toggle);
-
- if (CriticalPartsScanning.treatment === "on") {
- CriticalPartsScan(updateResult.data.update_jobs.returning[0].id);
- }
- if (updateResult.errors) {
- //error while inserting
- notification["error"]({
- message: t("jobs.errors.creating", {
- error: JSON.stringify(updateResult.errors),
- }),
- });
- refetch();
- setInsertLoading(false);
- return;
- }
-
- const newTotals = await Axios.post("/job/totalsssu", {
- id: selectedJob,
- });
-
- if (newTotals.status !== 200) {
- notification["error"]({
- message: t("jobs.errors.totalscalc"),
- });
- setInsertLoading(false);
- return;
- }
- notification["success"]({
- message: t("jobs.successes.supplemented"),
- onClick: () => {
- history.push(
- `/manage/jobs/${updateResult.data.update_jobs.returning[0].id}`
- );
- },
- });
- //Job has been inserted. Clean up the available jobs record.
-
- deleteJob({
- variables: { id: estData.id },
- }).then((r) => {
- refetch();
- setInsertLoading(false);
- });
-
- await insertNote({
- variables: {
- noteInput: [
- {
- jobid: selectedJob,
- created_by: currentUser.email,
- audit: true,
- text: t("jobs.labels.supplementnote"),
- },
- ],
- },
- });
- insertAuditTrail({
- jobid: selectedJob,
- operation: AuditTrailMapping.jobsupplement(),
- });
- }
- };
-
- const owner =
- estDataRaw.data &&
- estDataRaw.data.available_jobs_by_pk &&
- estDataRaw.data.available_jobs_by_pk.est_data &&
- estDataRaw.data.available_jobs_by_pk.est_data.owner &&
- estDataRaw.data.available_jobs_by_pk.est_data.owner.data &&
- !estDataRaw.data.available_jobs_by_pk.issupplement
- ? estDataRaw.data.available_jobs_by_pk.est_data.owner.data
- : null;
-
- const onOwnerModalCancel = () => {
- setOwnerModalVisible(false);
- setSelectedOwner(null);
- setPartsQueueToggle(bodyshop.md_functionality_toggles.parts_queue_toggle);
- };
-
- const onJobModalCancel = () => {
- setJobModalVisible(false);
- modalSearchState[1]("");
- setSelectedJob(null);
- setPartsQueueToggle(bodyshop.md_functionality_toggles.parts_queue_toggle);
- };
-
- const addJobAsNew = (record) => {
- loadEstData({ variables: { id: record.id } });
- setOwnerModalVisible(true);
- };
-
- const addJobAsSupp = useCallback((record) => {
- loadEstData({ variables: { id: record.id } });
- modalSearchState[1](record.clm_no);
- setJobModalVisible(true);
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, []);
-
- useEffect(() => {
- if (availableJobId && clm_no)
- addJobAsSupp({ id: availableJobId, clm_no: clm_no });
- }, [addJobAsSupp, availableJobId, clm_no]);
-
- if (error) return ;
-
-
- return (
-
-
-
- {currentUser.email.includes("@rome.") ||
- currentUser.email.includes("@imex.") ? (
- {
- 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);
+ delete supp.owner;
+ delete supp.vehicle;
+ delete supp.ins_co_nm;
+ if (!importOptions.overrideHeaders) {
+ HeaderFields.forEach((item) => delete supp[item]);
}
- }}
- >
- Add all jobs as new.
-
- ) : null}
-
-
-
-
-
-
-
-
-
- );
+ let suppDelta = await GetSupplementDelta(
+ client,
+ selectedJob,
+ supp.joblines.data
+ );
+
+ delete supp.joblines;
+ if (suppDelta !== null) {
+ await client.mutate({
+ mutation: gql`
+ ${suppDelta}
+ `,
+ });
+ }
+ const updateResult = await updateJob({
+ variables: {
+ jobId: selectedJob,
+ job: {
+ ...supp,
+ // clm_total: Dinero(newTotals.totals.total_repairs).toFormat("0.00"),
+ // owner_owing: Dinero(newTotals.totals.custPayable.total).toFormat(
+ // "0.00"
+ // ),
+ // job_totals: newTotals,
+ queued_for_parts: partsQueueToggle,
+ },
+ },
+ });
+
+ setPartsQueueToggle(bodyshop.md_functionality_toggles.parts_queue_toggle);
+
+ if (CriticalPartsScanning.treatment === "on") {
+ CriticalPartsScan(updateResult.data.update_jobs.returning[0].id);
+ }
+ if (updateResult.errors) {
+ //error while inserting
+ notification["error"]({
+ message: t("jobs.errors.creating", {
+ error: JSON.stringify(updateResult.errors),
+ }),
+ });
+ refetch();
+ setInsertLoading(false);
+ return;
+ }
+
+ const newTotals = await Axios.post("/job/totalsssu", {
+ id: selectedJob,
+ });
+
+ if (newTotals.status !== 200) {
+ notification["error"]({
+ message: t("jobs.errors.totalscalc"),
+ });
+ setInsertLoading(false);
+ return;
+ }
+ notification["success"]({
+ message: t("jobs.successes.supplemented"),
+ onClick: () => {
+ history(
+ `/manage/jobs/${updateResult.data.update_jobs.returning[0].id}`
+ );
+ },
+ });
+ //Job has been inserted. Clean up the available jobs record.
+
+ deleteJob({
+ variables: {id: estData.id},
+ }).then((r) => {
+ refetch();
+ setInsertLoading(false);
+ });
+
+ await insertNote({
+ variables: {
+ noteInput: [
+ {
+ jobid: selectedJob,
+ created_by: currentUser.email,
+ audit: true,
+ text: t("jobs.labels.supplementnote"),
+ },
+ ],
+ },
+ });
+ insertAuditTrail({
+ jobid: selectedJob,
+ operation: AuditTrailMapping.jobsupplement(),
+ });
+ }
+ };
+
+ const owner =
+ estDataRaw.data &&
+ estDataRaw.data.available_jobs_by_pk &&
+ estDataRaw.data.available_jobs_by_pk.est_data &&
+ estDataRaw.data.available_jobs_by_pk.est_data.owner &&
+ estDataRaw.data.available_jobs_by_pk.est_data.owner.data &&
+ !estDataRaw.data.available_jobs_by_pk.issupplement
+ ? estDataRaw.data.available_jobs_by_pk.est_data.owner.data
+ : null;
+
+ const onOwnerModalCancel = () => {
+ setOwnerModalVisible(false);
+ setSelectedOwner(null);
+ setPartsQueueToggle(bodyshop.md_functionality_toggles.parts_queue_toggle);
+ };
+
+ const onJobModalCancel = () => {
+ setJobModalVisible(false);
+ modalSearchState[1]("");
+ setSelectedJob(null);
+ setPartsQueueToggle(bodyshop.md_functionality_toggles.parts_queue_toggle);
+ };
+
+ const addJobAsNew = (record) => {
+ loadEstData({variables: {id: record.id}});
+ setOwnerModalVisible(true);
+ };
+
+ const addJobAsSupp = useCallback((record) => {
+ loadEstData({variables: {id: record.id}});
+ modalSearchState[1](record.clm_no);
+ setJobModalVisible(true);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
+ useEffect(() => {
+ if (availableJobId && clm_no)
+ addJobAsSupp({id: availableJobId, clm_no: clm_no});
+ }, [addJobAsSupp, availableJobId, clm_no]);
+
+ if (error) return ;
+
+
+ return (
+
+
+
+ {currentUser.email.includes("@rome.") ||
+ currentUser.email.includes("@imex.") ? (
+ {
+ 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.
+
+ ) : null}
+
+
+
+
+
+
+
+
+
+
+ );
}
+
export default connect(
- mapStateToProps,
- mapDispatchToProps
+ mapStateToProps,
+ mapDispatchToProps
)(JobsAvailableContainer);
function replaceEmpty(someObj, replaceValue = null) {
- const replacer = (key, value) =>
- value === "" ? replaceValue || null : value;
- //^ because you seem to want to replace (strings) "null" or "undefined" too
- const temp = JSON.stringify(someObj, replacer);
- return JSON.parse(temp);
+ const replacer = (key, value) =>
+ value === "" ? replaceValue || null : value;
+ //^ because you seem to want to replace (strings) "null" or "undefined" too
+ const temp = JSON.stringify(someObj, replacer);
+ return JSON.parse(temp);
}
async function CheckTaxRates(estData, bodyshop) {
- // //LKQ Check
- // if (
- // !estData.parts_tax_rates?.PAL ||
- // estData.parts_tax_rates?.PAL?.prt_tax_rt === null ||
- // estData.parts_tax_rates?.PAL?.prt_tax_rt === 0
- // ) {
- // const res = await confirmDialog(
- // `Rome Online has detected that there is a missing tax rate for LKQ parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.`
- // );
- // if (res) {
- // if (!estData.parts_tax_rates.PAL) {
- // estData.parts_tax_rates.PAL = {
- // prt_discp: 0,
- // prt_mktyp: true,
- // prt_mkupp: 0,
- // prt_type: "PAL",
- // };
- // }
- // estData.parts_tax_rates.PAL.prt_tax_rt =
- // bodyshop.bill_tax_rates.state_tax_rate / 100;
- // estData.parts_tax_rates.PAL.prt_tax_in = true;
- // }
- // }
- // //PAC Check
- // if (
- // !estData.parts_tax_rates?.PAC ||
- // estData.parts_tax_rates?.PAC?.prt_tax_rt === null ||
- // estData.parts_tax_rates?.PAC?.prt_tax_rt === 0
- // ) {
- // const res = await confirmDialog(
- // `Rome Online has detected that there is a missing tax rate for rechromed parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.`
- // );
- // if (res) {
- // if (!estData.parts_tax_rates.PAC) {
- // estData.parts_tax_rates.PAC = {
- // prt_discp: 0,
- // prt_mktyp: true,
- // prt_mkupp: 0,
- // prt_type: "PAC",
- // };
- // }
- // estData.parts_tax_rates.PAC.prt_tax_rt =
- // bodyshop.bill_tax_rates.state_tax_rate / 100;
- // estData.parts_tax_rates.PAC.prt_tax_in = true;
- // }
- // }
+ // //LKQ Check
+ // if (
+ // !estData.parts_tax_rates?.PAL ||
+ // estData.parts_tax_rates?.PAL?.prt_tax_rt === null ||
+ // estData.parts_tax_rates?.PAL?.prt_tax_rt === 0
+ // ) {
+ // const res = await confirmDialog(
+ // `Rome Online has detected that there is a missing tax rate for LKQ parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.`
+ // );
+ // if (res) {
+ // if (!estData.parts_tax_rates.PAL) {
+ // estData.parts_tax_rates.PAL = {
+ // prt_discp: 0,
+ // prt_mktyp: true,
+ // prt_mkupp: 0,
+ // prt_type: "PAL",
+ // };
+ // }
+ // estData.parts_tax_rates.PAL.prt_tax_rt =
+ // bodyshop.bill_tax_rates.state_tax_rate / 100;
+ // estData.parts_tax_rates.PAL.prt_tax_in = true;
+ // }
+ // }
+ // //PAC Check
+ // if (
+ // !estData.parts_tax_rates?.PAC ||
+ // estData.parts_tax_rates?.PAC?.prt_tax_rt === null ||
+ // estData.parts_tax_rates?.PAC?.prt_tax_rt === 0
+ // ) {
+ // const res = await confirmDialog(
+ // `Rome Online has detected that there is a missing tax rate for rechromed parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.`
+ // );
+ // if (res) {
+ // if (!estData.parts_tax_rates.PAC) {
+ // estData.parts_tax_rates.PAC = {
+ // prt_discp: 0,
+ // prt_mktyp: true,
+ // prt_mkupp: 0,
+ // prt_type: "PAC",
+ // };
+ // }
+ // estData.parts_tax_rates.PAC.prt_tax_rt =
+ // bodyshop.bill_tax_rates.state_tax_rate / 100;
+ // estData.parts_tax_rates.PAC.prt_tax_in = true;
+ // }
+ // }
- //PAM Check
- if (!estData.parts_tax_rates?.PAM) {
- estData.parts_tax_rates.PAM = estData.parts_tax_rates.PAC;
- }
+ //PAM Check
+ if (!estData.parts_tax_rates?.PAM) {
+ estData.parts_tax_rates.PAM = estData.parts_tax_rates.PAC;
+ }
- // //PAM Check
- // if (
- // !estData.parts_tax_rates?.PAM ||
- // estData.parts_tax_rates?.PAM?.prt_tax_rt === null ||
- // estData.parts_tax_rates?.PAM?.prt_tax_rt === 0
- // ) {
- // const res = await confirmDialog(
- // `Rome Online has detected that there is a missing tax rate for remanufactured parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.`
- // );
- // if (res) {
- // if (!estData.parts_tax_rates.PAM) {
- // estData.parts_tax_rates.PAM = {
- // prt_discp: 0,
- // prt_mktyp: true,
- // prt_mkupp: 0,
- // prt_type: "PAM",
- // };
- // }
- // estData.parts_tax_rates.PAM.prt_tax_rt =
- // bodyshop.bill_tax_rates.state_tax_rate / 100;
- // estData.parts_tax_rates.PAM.prt_tax_in = true;
- // }
- // }
+ // //PAM Check
+ // if (
+ // !estData.parts_tax_rates?.PAM ||
+ // estData.parts_tax_rates?.PAM?.prt_tax_rt === null ||
+ // estData.parts_tax_rates?.PAM?.prt_tax_rt === 0
+ // ) {
+ // const res = await confirmDialog(
+ // `Rome Online has detected that there is a missing tax rate for remanufactured parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.`
+ // );
+ // if (res) {
+ // if (!estData.parts_tax_rates.PAM) {
+ // estData.parts_tax_rates.PAM = {
+ // prt_discp: 0,
+ // prt_mktyp: true,
+ // prt_mkupp: 0,
+ // prt_type: "PAM",
+ // };
+ // }
+ // estData.parts_tax_rates.PAM.prt_tax_rt =
+ // bodyshop.bill_tax_rates.state_tax_rate / 100;
+ // estData.parts_tax_rates.PAM.prt_tax_in = true;
+ // }
+ // }
- // if (
- // !estData.parts_tax_rates?.PAR ||
- // estData.parts_tax_rates?.PAR?.prt_tax_rt === null ||
- // estData.parts_tax_rates?.PAR?.prt_tax_rt === 0
- // ) {
- // const res = await confirmDialog(
- // `Rome Online has detected that there is a missing tax rate for recored parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.`
- // );
- // if (res) {
- // if (!estData.parts_tax_rates.PAR) {
- // estData.parts_tax_rates.PAR = {
- // prt_discp: 0,
- // prt_mktyp: true,
- // prt_mkupp: 0,
- // prt_type: "PAR",
- // };
- // }
- // estData.parts_tax_rates.PAR.prt_tax_rt =
- // bodyshop.bill_tax_rates.state_tax_rate / 100;
- // estData.parts_tax_rates.PAR.prt_tax_in = true;
- // }
- // }
+ // if (
+ // !estData.parts_tax_rates?.PAR ||
+ // estData.parts_tax_rates?.PAR?.prt_tax_rt === null ||
+ // estData.parts_tax_rates?.PAR?.prt_tax_rt === 0
+ // ) {
+ // const res = await confirmDialog(
+ // `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.
- //Currently limited to SK shops only.
- if (bodyshop.region_config === "CA_SK") {
- estData.joblines.data.forEach((jl, index) => {
- if (
- (jl.part_type === "PASL" || jl.part_type === "PAS") &&
- jl.lbr_op !== "OP11"
- ) {
- estData.joblines.data[index].tax_part = jl.lbr_tax;
- }
+ //IO-1387 If a sublet line is NOT R&R, use the labor tax. If it is, use the sublet tax rate.
+ //Currently limited to SK shops only.
+ if (bodyshop.region_config === "CA_SK") {
+ estData.joblines.data.forEach((jl, index) => {
+ if (
+ (jl.part_type === "PASL" || jl.part_type === "PAS") &&
+ jl.lbr_op !== "OP11"
+ ) {
+ estData.joblines.data[index].tax_part = jl.lbr_tax;
+ }
- //Set markup lines and tax lines as taxable.
- //900510 is a mark up. 900510 is a discount.
- if (jl.db_ref === "900510") {
- estData.joblines.data[index].tax_part = true;
- }
- });
- }
+ //Set markup lines and tax lines as taxable.
+ //900510 is a mark up. 900510 is a discount.
+ if (jl.db_ref === "900510") {
+ estData.joblines.data[index].tax_part = true;
+ }
+ });
+ }
}
async function ResolveCCCLineIssues(estData, bodyshop) {
- //Find all misc amounts, populate them to the act price.
- //TODO Ensure that this doesnt get violated
- //This needs to be done before cleansing unq_seq since some misc prices could move over.
- estData.joblines.data.forEach((line) => {
- if (line.misc_amt && line.misc_amt !== 0) {
- line.act_price = line.act_price + line.misc_amt;
- line.tax_part = !!line.misc_tax;
- }
- });
+ //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
+ //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
);
- 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,
- };
- });
+
+ 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,
+ };
+ });
}
diff --git a/client/src/components/jobs-change-status/jobs-change-status.component.jsx b/client/src/components/jobs-change-status/jobs-change-status.component.jsx
index aa5f61fc2..daf384d9d 100644
--- a/client/src/components/jobs-change-status/jobs-change-status.component.jsx
+++ b/client/src/components/jobs-change-status/jobs-change-status.component.jsx
@@ -1,119 +1,119 @@
-import { DownCircleFilled } from "@ant-design/icons";
-import { useMutation } from "@apollo/client";
-import { Button, Dropdown, Menu, notification } from "antd";
-import React, { useEffect, useState } from "react";
-import { useTranslation } from "react-i18next";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { UPDATE_JOB_STATUS } from "../../graphql/jobs.queries";
-import { insertAuditTrail } from "../../redux/application/application.actions";
-import { selectJobReadOnly } from "../../redux/application/application.selectors";
-import { selectBodyshop } from "../../redux/user/user.selectors";
+import {DownCircleFilled} from "@ant-design/icons";
+import {useMutation} from "@apollo/client";
+import {Button, Dropdown, notification} from "antd";
+import React, {useEffect, useState} from "react";
+import {useTranslation} from "react-i18next";
+import {connect} from "react-redux";
+import {createStructuredSelector} from "reselect";
+import {UPDATE_JOB_STATUS} from "../../graphql/jobs.queries";
+import {insertAuditTrail} from "../../redux/application/application.actions";
+import {selectJobReadOnly} from "../../redux/application/application.selectors";
+import {selectBodyshop} from "../../redux/user/user.selectors";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
const mapStateToProps = createStructuredSelector({
- bodyshop: selectBodyshop,
- jobRO: selectJobReadOnly,
+ bodyshop: selectBodyshop,
+ jobRO: selectJobReadOnly,
});
const mapDispatchToProps = (dispatch) => ({
- insertAuditTrail: ({ jobid, operation }) =>
- dispatch(insertAuditTrail({ jobid, operation })),
+ insertAuditTrail: ({jobid, operation}) =>
+ dispatch(insertAuditTrail({jobid, operation})),
});
-export function JobsChangeStatus({ job, bodyshop, jobRO, insertAuditTrail }) {
- const { t } = useTranslation();
+export function JobsChangeStatus({job, bodyshop, jobRO, insertAuditTrail}) {
+ const {t} = useTranslation();
- const [availableStatuses, setAvailableStatuses] = useState([]);
- const [otherStages, setOtherStages] = useState([]);
- const [mutationUpdateJobstatus] = useMutation(UPDATE_JOB_STATUS);
- const updateJobStatus = (status) => {
- mutationUpdateJobstatus({
- variables: { jobId: job.id, status: status },
- })
- .then((r) => {
- notification["success"]({ message: t("jobs.successes.save") });
- insertAuditTrail({
- jobid: job.id,
- operation: AuditTrailMapping.jobstatuschange(status),
- });
- // refetch();
- })
- .catch((error) => {
- notification["error"]({ message: t("jobs.errors.saving") });
- });
- };
+ const [availableStatuses, setAvailableStatuses] = useState([]);
+ const [otherStages, setOtherStages] = useState([]);
+ const [mutationUpdateJobstatus] = useMutation(UPDATE_JOB_STATUS);
+ const updateJobStatus = (status) => {
+ mutationUpdateJobstatus({
+ variables: {jobId: job.id, status: status},
+ })
+ .then((r) => {
+ notification["success"]({message: t("jobs.successes.save")});
+ insertAuditTrail({
+ jobid: job.id,
+ operation: AuditTrailMapping.jobstatuschange(status),
+ });
+ // refetch();
+ })
+ .catch((error) => {
+ notification["error"]({message: t("jobs.errors.saving")});
+ });
+ };
- useEffect(() => {
- //Figure out what scenario were in, populate accodingly
- if (job && bodyshop) {
- if (
- bodyshop.md_ro_statuses.pre_production_statuses.includes(job.status)
- ) {
- setAvailableStatuses(bodyshop.md_ro_statuses.pre_production_statuses);
- if (bodyshop.md_ro_statuses.production_statuses[0])
- setOtherStages([bodyshop.md_ro_statuses.production_statuses[0]]);
- } else if (
- bodyshop.md_ro_statuses.production_statuses.includes(job.status)
- ) {
- setAvailableStatuses(bodyshop.md_ro_statuses.production_statuses);
- setOtherStages([
- bodyshop.md_ro_statuses.default_imported,
- bodyshop.md_ro_statuses.default_delivered,
- ]);
- } else if (
- bodyshop.md_ro_statuses.post_production_statuses.includes(job.status)
- ) {
- setAvailableStatuses(
- bodyshop.md_ro_statuses.post_production_statuses.filter(
- (s) =>
- s !== bodyshop.md_ro_statuses.default_invoiced &&
- s !== bodyshop.md_ro_statuses.default_exported
- )
- );
- if (bodyshop.md_ro_statuses.production_statuses[0])
- setOtherStages([bodyshop.md_ro_statuses.production_statuses[0]]);
- } else {
- console.log(
- "Status didn't match any restrictions. Allowing all status changes."
- );
- setAvailableStatuses(bodyshop.md_ro_statuses.statuses);
- }
+ useEffect(() => {
+ //Figure out what scenario were in, populate accodingly
+ if (job && bodyshop) {
+ if (
+ bodyshop.md_ro_statuses.pre_production_statuses.includes(job.status)
+ ) {
+ setAvailableStatuses(bodyshop.md_ro_statuses.pre_production_statuses);
+ if (bodyshop.md_ro_statuses.production_statuses[0])
+ setOtherStages([bodyshop.md_ro_statuses.production_statuses[0]]);
+ } else if (
+ bodyshop.md_ro_statuses.production_statuses.includes(job.status)
+ ) {
+ setAvailableStatuses(bodyshop.md_ro_statuses.production_statuses);
+ setOtherStages([
+ bodyshop.md_ro_statuses.default_imported,
+ bodyshop.md_ro_statuses.default_delivered,
+ ]);
+ } else if (
+ bodyshop.md_ro_statuses.post_production_statuses.includes(job.status)
+ ) {
+ setAvailableStatuses(
+ bodyshop.md_ro_statuses.post_production_statuses.filter(
+ (s) =>
+ s !== bodyshop.md_ro_statuses.default_invoiced &&
+ s !== bodyshop.md_ro_statuses.default_exported
+ )
+ );
+ if (bodyshop.md_ro_statuses.production_statuses[0])
+ setOtherStages([bodyshop.md_ro_statuses.production_statuses[0]]);
+ } else {
+ console.log(
+ "Status didn't match any restrictions. Allowing all status changes."
+ );
+ setAvailableStatuses(bodyshop.md_ro_statuses.statuses);
+ }
+ }
+ }, [job, setAvailableStatuses, bodyshop]);
+
+ const statusMenu = {
+ items: [
+ ...availableStatuses.map((item) => ({
+ key: item,
+ label: item,
+ })),
+ ...(job.converted
+ ? [
+ {type: "divider"},
+ ...otherStages.map((item) => ({
+ key: item,
+ label: item,
+ })),
+ ]
+ : []),
+ ],
+ onClick: (e) => updateJobStatus(e.key)
}
- }, [job, setAvailableStatuses, bodyshop]);
- const statusmenu = (
-
- );
+ return (
+
+
+ {job.status}
- return (
-
-
- {job.status}
-
-
-
-
- );
+
+
+
+ );
}
+
export default connect(mapStateToProps, mapDispatchToProps)(JobsChangeStatus);
diff --git a/client/src/components/jobs-close-auto-allocate/jobs-close-auto-allocate.component.jsx b/client/src/components/jobs-close-auto-allocate/jobs-close-auto-allocate.component.jsx
index c315cf009..346c88d55 100644
--- a/client/src/components/jobs-close-auto-allocate/jobs-close-auto-allocate.component.jsx
+++ b/client/src/components/jobs-close-auto-allocate/jobs-close-auto-allocate.component.jsx
@@ -1,87 +1,90 @@
-import { Button, Dropdown, Menu } from "antd";
+import {Button, Dropdown} from "antd";
import _ from "lodash";
import React from "react";
-import { useTranslation } from "react-i18next";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { logImEXEvent } from "../../firebase/firebase.utils";
-import { selectBodyshop } from "../../redux/user/user.selectors";
+import {useTranslation} from "react-i18next";
+import {connect} from "react-redux";
+import {createStructuredSelector} from "reselect";
+import {logImEXEvent} from "../../firebase/firebase.utils";
+import {selectBodyshop} from "../../redux/user/user.selectors";
+
const mapStateToProps = createStructuredSelector({
- bodyshop: selectBodyshop,
+ bodyshop: selectBodyshop,
});
-export function JobsCloseAutoAllocate({ bodyshop, joblines, form, disabled }) {
- const { t } = useTranslation();
+export function JobsCloseAutoAllocate({bodyshop, joblines, form, disabled}) {
+ const {t} = useTranslation();
- const handleAllocate = (defaults) => {
- form.setFieldsValue({
- joblines: joblines.map((jl) => {
- const ret = _.cloneDeep(jl);
- if (jl.part_type) {
- ret.profitcenter_part = defaults.profits[jl.part_type.toUpperCase()];
- } else {
- }
- if (jl.mod_lbr_ty) {
- ret.profitcenter_labor =
- defaults.profits[jl.mod_lbr_ty.toUpperCase()];
- } else {
- ret.profitcenter_labor = null;
- }
- //Verify that this is also manually updated in server/job-costing
- if (!jl.part_type && !jl.mod_lbr_ty) {
- const lineDesc = jl.line_desc ? jl.line_desc.toLowerCase() : "";
- if (lineDesc.includes("shop materials")) {
- ret.profitcenter_part = defaults.profits["MASH"];
- } else if (lineDesc.includes("paint/materials")) {
- ret.profitcenter_part = defaults.profits["MAPA"];
- } else if (lineDesc.includes("ats amount")) {
- ret.profitcenter_part = defaults.profits["ATS"];
- } else if (jl.act_price > 0) {
- ret.profitcenter_part = defaults.profits["PAO"];
- } else {
- ret.profitcenter_part = null;
- }
- }
- return ret;
- }),
- });
- };
+ const handleAllocate = (defaults) => {
+ form.setFieldsValue({
+ joblines: joblines.map((jl) => {
+ const ret = _.cloneDeep(jl);
+ if (jl.part_type) {
+ ret.profitcenter_part = defaults.profits[jl.part_type.toUpperCase()];
+ } else {
+ }
+ if (jl.mod_lbr_ty) {
+ ret.profitcenter_labor =
+ defaults.profits[jl.mod_lbr_ty.toUpperCase()];
+ } else {
+ ret.profitcenter_labor = null;
+ }
+ //Verify that this is also manually updated in server/job-costing
+ if (!jl.part_type && !jl.mod_lbr_ty) {
+ const lineDesc = jl.line_desc ? jl.line_desc.toLowerCase() : "";
+ if (lineDesc.includes("shop materials")) {
+ ret.profitcenter_part = defaults.profits["MASH"];
+ } else if (lineDesc.includes("paint/materials")) {
+ ret.profitcenter_part = defaults.profits["MAPA"];
+ } else if (lineDesc.includes("ats amount")) {
+ ret.profitcenter_part = defaults.profits["ATS"];
+ } else if (jl.act_price > 0) {
+ ret.profitcenter_part = defaults.profits["PAO"];
+ } else {
+ ret.profitcenter_part = null;
+ }
+ }
+ return ret;
+ }),
+ });
+ };
- const handleAutoAllocateClick = () => {
- logImEXEvent("jobs_close_allocate_auto");
+ const handleAutoAllocateClick = () => {
+ logImEXEvent("jobs_close_allocate_auto");
- const { defaults } = bodyshop.md_responsibility_centers;
- handleAllocate(defaults);
- };
+ const {defaults} = bodyshop.md_responsibility_centers;
+ handleAllocate(defaults);
+ };
- const handleMenuClick = ({ item, key, keyPath, domEvent }) => {
- logImEXEvent("jobs_close_allocate_auto_dms");
- form.setFieldsValue({ dms_allocation: key });
- handleAllocate(
- bodyshop.md_responsibility_centers.dms_defaults.find(
- (x) => x.name === key
- )
+ const handleMenuClick = ({item, key, keyPath, domEvent}) => {
+ logImEXEvent("jobs_close_allocate_auto_dms");
+ form.setFieldsValue({dms_allocation: key});
+ handleAllocate(
+ bodyshop.md_responsibility_centers.dms_defaults.find(
+ (x) => x.name === key
+ )
+ );
+ };
+
+ const menu = bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber ? {
+ items: bodyshop.md_responsibility_centers.dms_defaults.map((mapping) => ({
+ key: mapping.name,
+ label: mapping.name,
+ disabled: disabled,
+ })),
+ onClick: handleMenuClick,
+ } : {
+ items: []
+ }
+
+ return bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber ? (
+
+ {t("jobs.actions.dmsautoallocate")}
+
+ ) : (
+
+ {t("jobs.actions.autoallocate")}
+
);
- };
-
- const overlay = (bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
-
- );
-
- return bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber ? (
-
- {t("jobs.actions.dmsautoallocate")}
-
- ) : (
-
- {t("jobs.actions.autoallocate")}
-
- );
}
+
export default connect(mapStateToProps, null)(JobsCloseAutoAllocate);
diff --git a/client/src/components/jobs-close-export-button/jobs-close-export-button.component.jsx b/client/src/components/jobs-close-export-button/jobs-close-export-button.component.jsx
index 8bbda03e1..8245af6d1 100644
--- a/client/src/components/jobs-close-export-button/jobs-close-export-button.component.jsx
+++ b/client/src/components/jobs-close-export-button/jobs-close-export-button.component.jsx
@@ -1,230 +1,227 @@
-import { useMutation } from "@apollo/client";
-import { Button, notification } from "antd";
+import {useMutation} from "@apollo/client";
+import {Button, notification} from "antd";
import axios from "axios";
-import React, { useState } from "react";
-import { useTranslation } from "react-i18next";
-import { connect } from "react-redux";
-import { useHistory } from "react-router-dom";
-import { createStructuredSelector } from "reselect";
-import { auth, logImEXEvent } from "../../firebase/firebase.utils";
-import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
-import { UPDATE_JOB } from "../../graphql/jobs.queries";
-import {
- selectBodyshop,
- selectCurrentUser,
-} from "../../redux/user/user.selectors";
+import React, {useState} from "react";
+import {useTranslation} from "react-i18next";
+import {connect} from "react-redux";
+import {useNavigate} from "react-router-dom";
+import {createStructuredSelector} from "reselect";
+import {auth, logImEXEvent} from "../../firebase/firebase.utils";
+import {INSERT_EXPORT_LOG} from "../../graphql/accounting.queries";
+import {UPDATE_JOB} from "../../graphql/jobs.queries";
+import {selectBodyshop, selectCurrentUser,} from "../../redux/user/user.selectors";
import client from "../../utils/GraphQLClient";
const mapStateToProps = createStructuredSelector({
- bodyshop: selectBodyshop,
- currentUser: selectCurrentUser,
+ bodyshop: selectBodyshop,
+ currentUser: selectCurrentUser,
});
function updateJobCache(items) {
- client.cache.modify({
- id: "ROOT_QUERY",
- fields: {
- jobs(existingJobs = []) {
- return existingJobs.filter(
- (jobRef) => jobRef.__ref.includes(items) === false
- );
- },
- },
- });
+ client.cache.modify({
+ id: "ROOT_QUERY",
+ fields: {
+ jobs(existingJobs = []) {
+ return existingJobs.filter(
+ (jobRef) => jobRef.__ref.includes(items) === false
+ );
+ },
+ },
+ });
}
export function JobsCloseExportButton({
- bodyshop,
- currentUser,
- jobId,
- disabled,
- setSelectedJobs,
- refetch,
-}) {
- const history = useHistory();
- const { t } = useTranslation();
- const [updateJob] = useMutation(UPDATE_JOB);
- const [insertExportLog] = useMutation(INSERT_EXPORT_LOG);
- const [loading, setLoading] = useState(false);
+ bodyshop,
+ currentUser,
+ jobId,
+ disabled,
+ setSelectedJobs,
+ refetch,
+ }) {
+ const history = useNavigate();
+ const {t} = useTranslation();
+ const [updateJob] = useMutation(UPDATE_JOB);
+ const [insertExportLog] = useMutation(INSERT_EXPORT_LOG);
+ const [loading, setLoading] = useState(false);
- const handleQbxml = async () => {
- //Check if it's a CDK setup.
- if (bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) {
- history.push(`/manage/dms?jobId=${jobId}`);
- return;
- }
- logImEXEvent("jobs_close_export");
-
- setLoading(true);
- //Check if it's a QBO Setup.
- let PartnerResponse;
- if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) {
- PartnerResponse = await axios.post(`/qbo/receivables`, {
- jobIds: [jobId],
- elgen: true,
- });
- } else {
- //Default is QBD
-
- let QbXmlResponse;
- try {
- QbXmlResponse = await axios.post(
- "/accounting/qbxml/receivables",
- { jobIds: [jobId] },
- {
- headers: {
- Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
- },
- }
- );
- console.log("handle -> XML", QbXmlResponse);
- } catch (error) {
- console.log("Error getting QBXML from Server.", error);
- notification["error"]({
- message: t("jobs.errors.exporting", {
- error: "Unable to retrieve QBXML. " + JSON.stringify(error.message),
- }),
- });
- setLoading(false);
- return;
- }
-
- try {
- PartnerResponse = await axios.post(
- "http://localhost:1337/qb/",
- // "http://609feaeae986.ngrok.io/qb/",
- QbXmlResponse.data,
- {
- headers: {
- Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
- },
- }
- );
- } catch (error) {
- console.log("Error connecting to quickbooks or partner.", error);
- notification["error"]({
- message: t("jobs.errors.exporting-partner"),
- });
- setLoading(false);
- return;
- }
- }
-
- console.log("PartnerResponse", PartnerResponse);
-
- //Check to see if any of them failed. If they didn't don't execute the update.
- const failedTransactions = PartnerResponse.data.filter((r) => !r.success);
- const successfulTransactions = PartnerResponse.data.filter(
- (r) => r.success
- );
- if (failedTransactions.length > 0) {
- //Uh oh. At least one was no good.
- failedTransactions.forEach((ft) => {
- //insert failed export log
- notification.open({
- // key: "failedexports",
- type: "error",
- message: t("jobs.errors.exporting", {
- error: ft.errorMessage || "",
- }),
- });
- });
-
- if (!(bodyshop.accountingconfig && bodyshop.accountingconfig.qbo)) {
- //QBO Logs are handled server side.
- await insertExportLog({
- variables: {
- logs: [
- {
- bodyshopid: bodyshop.id,
- jobid: jobId,
- successful: false,
- message: JSON.stringify(
- failedTransactions.map((ft) => ft.errorMessage)
- ),
- useremail: currentUser.email,
- },
- ],
- },
- });
- }
- } else {
- //Insert success export log.
- if (!(bodyshop.accountingconfig && bodyshop.accountingconfig.qbo)) {
- //QBO Logs are handled server side.
- await insertExportLog({
- variables: {
- logs: [
- {
- bodyshopid: bodyshop.id,
- jobid: jobId,
- successful: true,
- useremail: currentUser.email,
- },
- ],
- },
- });
-
- const jobUpdateResponse = await updateJob({
- variables: {
- jobId: jobId,
- job: {
- status: bodyshop.md_ro_statuses.default_exported || "Exported*",
- date_exported: new Date(),
- },
- },
- });
-
- if (!!!jobUpdateResponse.errors) {
- notification.open({
- type: "success",
- key: "jobsuccessexport",
- message: t("jobs.successes.exported"),
- });
- updateJobCache(
- jobUpdateResponse.data.update_jobs.returning.map((job) => job.id)
- );
- } else {
- notification["error"]({
- message: t("jobs.errors.exporting", {
- error: JSON.stringify(jobUpdateResponse.error),
- }),
- });
+ const handleQbxml = async () => {
+ //Check if it's a CDK setup.
+ if (bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) {
+ history(`/manage/dms?jobId=${jobId}`);
+ return;
}
- }
- if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && successfulTransactions.length > 0) {
- notification.open({
- type: "success",
- key: "jobsuccessexport",
- message: t("jobs.successes.exported"),
- });
- updateJobCache([
- ...new Set(
- successfulTransactions.map(
- (st) =>
- st[
- bodyshop.accountingconfig && bodyshop.accountingconfig.qbo
- ? "jobid"
- : "id"
- ]
- )
- ),
- ]);
- }
- if (setSelectedJobs) {
- setSelectedJobs((selectedJobs) => {
- return selectedJobs.filter((i) => i !== jobId);
- });
- }
- }
- setLoading(false);
- };
+ logImEXEvent("jobs_close_export");
- return (
-
- {t("jobs.actions.export")}
-
- );
+ setLoading(true);
+ //Check if it's a QBO Setup.
+ let PartnerResponse;
+ if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) {
+ PartnerResponse = await axios.post(`/qbo/receivables`, {
+ jobIds: [jobId],
+ elgen: true,
+ });
+ } else {
+ //Default is QBD
+
+ let QbXmlResponse;
+ try {
+ QbXmlResponse = await axios.post(
+ "/accounting/qbxml/receivables",
+ {jobIds: [jobId]},
+ {
+ headers: {
+ Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
+ },
+ }
+ );
+ console.log("handle -> XML", QbXmlResponse);
+ } catch (error) {
+ console.log("Error getting QBXML from Server.", error);
+ notification["error"]({
+ message: t("jobs.errors.exporting", {
+ error: "Unable to retrieve QBXML. " + JSON.stringify(error.message),
+ }),
+ });
+ setLoading(false);
+ return;
+ }
+
+ try {
+ PartnerResponse = await axios.post(
+ "http://localhost:1337/qb/",
+ // "http://609feaeae986.ngrok.io/qb/",
+ QbXmlResponse.data,
+ {
+ headers: {
+ Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
+ },
+ }
+ );
+ } catch (error) {
+ console.log("Error connecting to quickbooks or partner.", error);
+ notification["error"]({
+ message: t("jobs.errors.exporting-partner"),
+ });
+ setLoading(false);
+ return;
+ }
+ }
+
+ console.log("PartnerResponse", PartnerResponse);
+
+ //Check to see if any of them failed. If they didn't don't execute the update.
+ const failedTransactions = PartnerResponse.data.filter((r) => !r.success);
+ const successfulTransactions = PartnerResponse.data.filter(
+ (r) => r.success
+ );
+ if (failedTransactions.length > 0) {
+ //Uh oh. At least one was no good.
+ failedTransactions.forEach((ft) => {
+ //insert failed export log
+ notification.open({
+ // key: "failedexports",
+ type: "error",
+ message: t("jobs.errors.exporting", {
+ error: ft.errorMessage || "",
+ }),
+ });
+ });
+
+ if (!(bodyshop.accountingconfig && bodyshop.accountingconfig.qbo)) {
+ //QBO Logs are handled server side.
+ await insertExportLog({
+ variables: {
+ logs: [
+ {
+ bodyshopid: bodyshop.id,
+ jobid: jobId,
+ successful: false,
+ message: JSON.stringify(
+ failedTransactions.map((ft) => ft.errorMessage)
+ ),
+ useremail: currentUser.email,
+ },
+ ],
+ },
+ });
+ }
+ } else {
+ //Insert success export log.
+ if (!(bodyshop.accountingconfig && bodyshop.accountingconfig.qbo)) {
+ //QBO Logs are handled server side.
+ await insertExportLog({
+ variables: {
+ logs: [
+ {
+ bodyshopid: bodyshop.id,
+ jobid: jobId,
+ successful: true,
+ useremail: currentUser.email,
+ },
+ ],
+ },
+ });
+
+ const jobUpdateResponse = await updateJob({
+ variables: {
+ jobId: jobId,
+ job: {
+ status: bodyshop.md_ro_statuses.default_exported || "Exported*",
+ date_exported: new Date(),
+ },
+ },
+ });
+
+ if (!!!jobUpdateResponse.errors) {
+ notification.open({
+ type: "success",
+ key: "jobsuccessexport",
+ message: t("jobs.successes.exported"),
+ });
+ updateJobCache(
+ jobUpdateResponse.data.update_jobs.returning.map((job) => job.id)
+ );
+ } else {
+ notification["error"]({
+ message: t("jobs.errors.exporting", {
+ error: JSON.stringify(jobUpdateResponse.error),
+ }),
+ });
+ }
+ }
+ if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && successfulTransactions.length > 0) {
+ notification.open({
+ type: "success",
+ key: "jobsuccessexport",
+ message: t("jobs.successes.exported"),
+ });
+ updateJobCache([
+ ...new Set(
+ successfulTransactions.map(
+ (st) =>
+ st[
+ bodyshop.accountingconfig && bodyshop.accountingconfig.qbo
+ ? "jobid"
+ : "id"
+ ]
+ )
+ ),
+ ]);
+ }
+ if (setSelectedJobs) {
+ setSelectedJobs((selectedJobs) => {
+ return selectedJobs.filter((i) => i !== jobId);
+ });
+ }
+ }
+ setLoading(false);
+ };
+
+ return (
+
+ {t("jobs.actions.export")}
+
+ );
}
export default connect(mapStateToProps, null)(JobsCloseExportButton);
diff --git a/client/src/components/jobs-close-lines/jobs-close-lines.component.jsx b/client/src/components/jobs-close-lines/jobs-close-lines.component.jsx
index bbb3f978e..98acce7e2 100644
--- a/client/src/components/jobs-close-lines/jobs-close-lines.component.jsx
+++ b/client/src/components/jobs-close-lines/jobs-close-lines.component.jsx
@@ -1,215 +1,216 @@
-import { Form, Select, Space, Tooltip } from "antd";
+import {Form, Select, Space, Tooltip} from "antd";
import React from "react";
-import { useTranslation } from "react-i18next";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { selectJobReadOnly } from "../../redux/application/application.selectors";
-import { selectBodyshop } from "../../redux/user/user.selectors";
+import {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 LaborTypeFormItem from "../form-items-formatted/labor-type-form-item.component";
import PartTypeFormItem from "../form-items-formatted/part-type-form-item.component";
import ReadOnlyFormItem from "../form-items-formatted/read-only-form-item.component";
-import { WarningOutlined } from "@ant-design/icons";
+import {WarningOutlined} from "@ant-design/icons";
import "./jobs-close-lines.styles.scss";
const mapStateToProps = createStructuredSelector({
- bodyshop: selectBodyshop,
- jobRO: selectJobReadOnly,
+ bodyshop: selectBodyshop,
+ jobRO: selectJobReadOnly,
});
const mapDispatchToProps = (dispatch) => ({
- //setUserLanguage: language => dispatch(setUserLanguage(language))
+ //setUserLanguage: language => dispatch(setUserLanguage(language))
});
-export function JobsCloseLines({ bodyshop, job, jobRO }) {
- const { t } = useTranslation();
- return (
-
-
- {(fields, { add, remove, move }) => {
- return (
-
-
-
- | {t("joblines.fields.line_desc")} |
- {t("joblines.fields.part_type")} |
- {t("joblines.fields.act_price")} |
- {t("joblines.fields.prt_dsmk_m")} |
- {t("joblines.fields.op_code_desc")} |
- {t("joblines.fields.mod_lbr_ty")} |
- {t("joblines.fields.mod_lb_hrs")} |
- {t("joblines.fields.profitcenter_part")} |
- {t("joblines.fields.profitcenter_labor")} |
-
-
-
- {fields.map((field, index) => (
-
- |
-
-
-
- |
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
- |
-
-
-
-
- |
-
-
-
-
- |
-
-
-
-
- |
-
-
-
-
- |
-
-
-
-
- |
-
-
-
-
- |
-
- ))}
-
-
- );
- }}
-
-
- );
+export function JobsCloseLines({bodyshop, job, jobRO}) {
+ const {t} = useTranslation();
+ return (
+
+
+ {(fields, {add, remove, move}) => {
+ return (
+
+
+
+ | {t("joblines.fields.line_desc")} |
+ {t("joblines.fields.part_type")} |
+ {t("joblines.fields.act_price")} |
+ {t("joblines.fields.prt_dsmk_m")} |
+ {t("joblines.fields.op_code_desc")} |
+ {t("joblines.fields.mod_lbr_ty")} |
+ {t("joblines.fields.mod_lb_hrs")} |
+ {t("joblines.fields.profitcenter_part")} |
+ {t("joblines.fields.profitcenter_labor")} |
+
+
+
+ {fields.map((field, index) => (
+
+ |
+
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+ |
+
+ ))}
+
+
+ );
+ }}
+
+
+ );
}
+
export default connect(mapStateToProps, mapDispatchToProps)(JobsCloseLines);
-const HasBeenConvertedTolabor = ({ value }) => {
- const { t } = useTranslation();
-
- if (!value) return null;
- return (
-
-
-
- );
+const HasBeenConvertedTolabor = ({value}) => {
+ const {t} = useTranslation();
+
+ if (!value) return null;
+ return (
+
+
+
+ );
};
diff --git a/client/src/components/jobs-close-lines/jobs-close-lines.styles.scss b/client/src/components/jobs-close-lines/jobs-close-lines.styles.scss
index 578d57155..e68b23d22 100644
--- a/client/src/components/jobs-close-lines/jobs-close-lines.styles.scss
+++ b/client/src/components/jobs-close-lines/jobs-close-lines.styles.scss
@@ -12,6 +12,7 @@
margin-bottom: 0px !important;
}
}
+
tr:hover {
background-color: #f5f5f5;
}
diff --git a/client/src/components/jobs-convert-button/jobs-convert-button.component.jsx b/client/src/components/jobs-convert-button/jobs-convert-button.component.jsx
index 543ad36ca..3c54e0fad 100644
--- a/client/src/components/jobs-convert-button/jobs-convert-button.component.jsx
+++ b/client/src/components/jobs-convert-button/jobs-convert-button.component.jsx
@@ -1,281 +1,275 @@
-import { useMutation } from "@apollo/client";
-import {
- Button,
- Form,
- Input,
- notification,
- Popover,
- Select,
- Space,
- Switch,
-} from "antd";
+import {useMutation} from "@apollo/client";
+import {Button, Form, Input, notification, Popover, Select, Space, Switch,} from "antd";
import axios from "axios";
-import React, { useState } from "react";
-import { useTranslation } from "react-i18next";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { CONVERT_JOB_TO_RO } from "../../graphql/jobs.queries";
-import { insertAuditTrail } from "../../redux/application/application.actions";
-import { selectJobReadOnly } from "../../redux/application/application.selectors";
-import { selectBodyshop } from "../../redux/user/user.selectors";
+import React, {useState} from "react";
+import {useTranslation} from "react-i18next";
+import {connect} from "react-redux";
+import {createStructuredSelector} from "reselect";
+import {CONVERT_JOB_TO_RO} from "../../graphql/jobs.queries";
+import {insertAuditTrail} from "../../redux/application/application.actions";
+import {selectJobReadOnly} from "../../redux/application/application.selectors";
+import {selectBodyshop} from "../../redux/user/user.selectors";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
+
const mapStateToProps = createStructuredSelector({
- //currentUser: selectCurrentUser
- bodyshop: selectBodyshop,
- jobRO: selectJobReadOnly,
+ //currentUser: selectCurrentUser
+ bodyshop: selectBodyshop,
+ jobRO: selectJobReadOnly,
});
const mapDispatchToProps = (dispatch) => ({
- insertAuditTrail: ({ jobid, operation }) =>
- dispatch(insertAuditTrail({ jobid, operation })),
+ insertAuditTrail: ({jobid, operation}) =>
+ dispatch(insertAuditTrail({jobid, operation})),
});
export function JobsConvertButton({
- bodyshop,
- job,
- refetch,
- jobRO,
- insertAuditTrail,
- parentFormIsFieldsTouched,
-}) {
- const [visible, setVisible] = useState(false);
- const [loading, setLoading] = useState(false);
- const [mutationConvertJob] = useMutation(CONVERT_JOB_TO_RO);
- const { t } = useTranslation();
- const [form] = Form.useForm();
+ bodyshop,
+ job,
+ refetch,
+ jobRO,
+ insertAuditTrail,
+ parentFormIsFieldsTouched,
+ }) {
+ const [open, setOpen] = useState(false);
+ const [loading, setLoading] = useState(false);
+ const [mutationConvertJob] = useMutation(CONVERT_JOB_TO_RO);
+ const {t} = useTranslation();
+ const [form] = Form.useForm();
- const handleConvert = async ({ employee_csr, category, ...values }) => {
- if (parentFormIsFieldsTouched()) {
- alert(t("jobs.labels.savebeforeconversion"));
- return;
- }
- setLoading(true);
- const res = await mutationConvertJob({
- variables: {
- jobId: job.id,
- job: {
- converted: true,
- ...(bodyshop.enforce_conversion_csr ? { employee_csr } : {}),
- ...(bodyshop.enforce_conversion_category ? { category } : {}),
- ...values,
- },
- },
- });
-
- if (values.ca_gst_registrant) {
- await axios.post("/job/totalsssu", {
- id: job.id,
- });
- }
-
- if (!res.errors) {
- refetch();
- notification["success"]({
- message: t("jobs.successes.converted"),
- });
-
- insertAuditTrail({
- jobid: job.id,
- operation: AuditTrailMapping.jobconverted(
- res.data.update_jobs.returning[0].ro_number
- ),
- });
-
- setVisible(false);
- }
- setLoading(false);
- };
-
- const popMenu = (
-
-
-
-
- {bodyshop.enforce_class && (
-
-
-
- )}
- {bodyshop.enforce_referral && (
- <>
- {
+ if (parentFormIsFieldsTouched()) {
+ alert(t("jobs.labels.savebeforeconversion"));
+ return;
+ }
+ setLoading(true);
+ const res = await mutationConvertJob({
+ variables: {
+ jobId: job.id,
+ job: {
+ converted: true,
+ ...(bodyshop.enforce_conversion_csr ? {employee_csr} : {}),
+ ...(bodyshop.enforce_conversion_category ? {category} : {}),
+ ...values,
},
- ]}
- >
-
-
-
-
-
- >
- )}
- {bodyshop.enforce_conversion_csr && (
-
-
-
- )}
- {bodyshop.enforce_conversion_category && (
-
-
-
- )}
- {bodyshop.region_config.toLowerCase().startsWith("ca") && (
-
-
-
- )}
-
-
-
-
-
-
-
- form.submit()} loading={loading}>
- {t("jobs.actions.convert")}
-
- setVisible(false)}>
- {t("general.actions.close")}
-
-
-
-
- );
+ },
+ });
- if (job.converted) return <>>;
+ if (values.ca_gst_registrant) {
+ await axios.post("/job/totalsssu", {
+ id: job.id,
+ });
+ }
- return (
-
- {
- setVisible(true);
- form.setFieldsValue({
- driveable: true,
- towin: false,
- employee_csr: job.employee_csr,
- });
- }}
- >
- {t("jobs.actions.convert")}
-
-
- );
+ if (!res.errors) {
+ refetch();
+ notification["success"]({
+ message: t("jobs.successes.converted"),
+ });
+
+ insertAuditTrail({
+ jobid: job.id,
+ operation: AuditTrailMapping.jobconverted(
+ res.data.update_jobs.returning[0].ro_number
+ ),
+ });
+
+ setOpen(false);
+ }
+ setLoading(false);
+ };
+
+ const popMenu = (
+
+
+
+
+ {bodyshop.enforce_class && (
+
+
+
+ )}
+ {bodyshop.enforce_referral && (
+ <>
+
+
+
+
+
+
+ >
+ )}
+ {bodyshop.enforce_conversion_csr && (
+
+
+
+ )}
+ {bodyshop.enforce_conversion_category && (
+
+
+
+ )}
+ {bodyshop.region_config.toLowerCase().startsWith("ca") && (
+
+
+
+ )}
+
+
+
+
+
+
+
+ form.submit()} loading={loading}>
+ {t("jobs.actions.convert")}
+
+ setOpen(false)}>
+ {t("general.actions.close")}
+
+
+
+
+ );
+
+ if (job.converted) return <>>;
+
+ return (
+
+ {
+ setOpen(true);
+ form.setFieldsValue({
+ driveable: true,
+ towin: false,
+ employee_csr: job.employee_csr,
+ });
+ }}
+ >
+ {t("jobs.actions.convert")}
+
+
+ );
}
+
export default connect(mapStateToProps, mapDispatchToProps)(JobsConvertButton);
diff --git a/client/src/components/jobs-create-jobs-info/jobs-create-jobs-info.component.jsx b/client/src/components/jobs-create-jobs-info/jobs-create-jobs-info.component.jsx
index 31fa53a23..cdac7ee84 100644
--- a/client/src/components/jobs-create-jobs-info/jobs-create-jobs-info.component.jsx
+++ b/client/src/components/jobs-create-jobs-info/jobs-create-jobs-info.component.jsx
@@ -1,15 +1,13 @@
-import { Collapse, Form, Input, Select, Switch } from "antd";
+import {Collapse, Form, Input, Select, Switch} from "antd";
import React from "react";
-import { useTranslation } from "react-i18next";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { selectBodyshop } from "../../redux/user/user.selectors";
+import {useTranslation} from "react-i18next";
+import {connect} from "react-redux";
+import {createStructuredSelector} from "reselect";
+import {selectBodyshop} from "../../redux/user/user.selectors";
import FormDatePicker from "../form-date-picker/form-date-picker.component";
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
import FormItemEmail from "../form-items-formatted/email-form-item.component";
-import FormItemPhone, {
- PhoneItemFormatterValidation,
-} from "../form-items-formatted/phone-form-item.component";
+import FormItemPhone, {PhoneItemFormatterValidation,} from "../form-items-formatted/phone-form-item.component";
import JobsDetailRatesChangeButton from "../jobs-detail-rates-change-button/jobs-detail-rates-change-button.component";
import JobsDetailRatesParts from "../jobs-detail-rates/jobs-detail-rates.parts.component";
@@ -20,355 +18,357 @@ import JobsDetailRatesTaxes from "../jobs-detail-rates/jobs-detail-rates.taxes.c
import JobsMarkPstExempt from "../jobs-mark-pst-exempt/jobs-mark-pst-exempt.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
+
const mapStateToProps = createStructuredSelector({
- //currentUser: selectCurrentUser
- bodyshop: selectBodyshop,
+ //currentUser: selectCurrentUser
+ bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
- //setUserLanguage: language => dispatch(setUserLanguage(language))
+ //setUserLanguage: language => dispatch(setUserLanguage(language))
});
-export function JobsCreateJobsInfo({ bodyshop, form, selected }) {
- const { t } = useTranslation();
- const { getFieldValue } = form;
- return (
-
+ );
}
+
export default connect(mapStateToProps, mapDispatchToProps)(JobsCreateJobsInfo);
diff --git a/client/src/components/jobs-create-owner-info/jobs-create-owner-info.component.jsx b/client/src/components/jobs-create-owner-info/jobs-create-owner-info.component.jsx
index 0b75e6826..af0fd57b8 100644
--- a/client/src/components/jobs-create-owner-info/jobs-create-owner-info.component.jsx
+++ b/client/src/components/jobs-create-owner-info/jobs-create-owner-info.component.jsx
@@ -1,52 +1,52 @@
-import { Checkbox, Col, Row } from "antd";
-import React, { useContext } from "react";
-import { useTranslation } from "react-i18next";
+import {Checkbox, Col, Row} from "antd";
+import React, {useContext} from "react";
+import {useTranslation} from "react-i18next";
import JobCreateContext from "../../pages/jobs-create/jobs-create.context";
import JobsCreateOwnerInfoNewComponent from "./jobs-create-owner-info.new.component";
import JobsCreateOwnerInfoSearchComponent from "./jobs-create-owner-info.search.component";
const colSpan = {
- sm: { span: 24 },
- lg: { span: 12 },
+ sm: {span: 24},
+ lg: {span: 12},
};
-export default function JobsCreateOwnerInfoComponent({ loading, owners }) {
- const { t } = useTranslation();
- const [state, setState] = useContext(JobCreateContext);
+export default function JobsCreateOwnerInfoComponent({loading, owners}) {
+ const {t} = useTranslation();
+ const [state, setState] = useContext(JobCreateContext);
- return (
-
-
-
- {
- setState({
- ...state,
- owner: {
- ...state.owner,
- new: !state.owner.new,
- selectedid: null,
- },
- });
- }}
- >
- {t("jobs.labels.create.newowner")}
-
-
+ return (
+
+
+
+ {
+ setState({
+ ...state,
+ owner: {
+ ...state.owner,
+ new: !state.owner.new,
+ selectedid: null,
+ },
+ });
+ }}
+ >
+ {t("jobs.labels.create.newowner")}
+
+
-
-
-
+
+
+
-
-
-
-
-
- );
+
+
+
+
+
+ );
}
diff --git a/client/src/components/jobs-create-owner-info/jobs-create-owner-info.container.jsx b/client/src/components/jobs-create-owner-info/jobs-create-owner-info.container.jsx
index 2434fb569..2ff02825d 100644
--- a/client/src/components/jobs-create-owner-info/jobs-create-owner-info.container.jsx
+++ b/client/src/components/jobs-create-owner-info/jobs-create-owner-info.container.jsx
@@ -1,24 +1,24 @@
-import { useQuery } from "@apollo/client";
-import React, { useContext } from "react";
-import { QUERY_SEARCH_OWNER_BY_IDX } from "../../graphql/owners.queries";
+import {useQuery} from "@apollo/client";
+import React, {useContext} from "react";
+import {QUERY_SEARCH_OWNER_BY_IDX} from "../../graphql/owners.queries";
import JobCreateContext from "../../pages/jobs-create/jobs-create.context";
import AlertComponent from "../alert/alert.component";
import JobsCreateOwnerInfoComponent from "./jobs-create-owner-info.component";
export default function JobsCreateOwnerContainer() {
- const [state] = useContext(JobCreateContext);
- const { loading, error, data } = useQuery(QUERY_SEARCH_OWNER_BY_IDX, {
- variables: { search: `%${state.owner.search}%` },
- skip: !state.owner.search,
- fetchPolicy: "network-only",
- nextFetchPolicy: "network-only",
- });
+ const [state] = useContext(JobCreateContext);
+ const {loading, error, data} = useQuery(QUERY_SEARCH_OWNER_BY_IDX, {
+ variables: {search: `%${state.owner.search}%`},
+ skip: !state.owner.search,
+ fetchPolicy: "network-only",
+ nextFetchPolicy: "network-only",
+ });
- if (error) return ;
- return (
-
- );
+ if (error) return ;
+ return (
+
+ );
}
diff --git a/client/src/components/jobs-create-owner-info/jobs-create-owner-info.new.component.jsx b/client/src/components/jobs-create-owner-info/jobs-create-owner-info.new.component.jsx
index 2dea9a657..7eb8d794c 100644
--- a/client/src/components/jobs-create-owner-info/jobs-create-owner-info.new.component.jsx
+++ b/client/src/components/jobs-create-owner-info/jobs-create-owner-info.new.component.jsx
@@ -1,163 +1,178 @@
-import { Form, Input, Switch } from "antd";
-import React, { useContext } from "react";
-import { useTranslation } from "react-i18next";
+import {Form, Input, Switch} from "antd";
+import React, {useContext} from "react";
+import {useTranslation} from "react-i18next";
import JobCreateContext from "../../pages/jobs-create/jobs-create.context";
import FormItemEmail from "../form-items-formatted/email-form-item.component";
-import FormItemPhone, {
- PhoneItemFormatterValidation,
-} from "../form-items-formatted/phone-form-item.component";
+import FormItemPhone, {PhoneItemFormatterValidation,} from "../form-items-formatted/phone-form-item.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
export default function JobsCreateOwnerInfoNewComponent() {
- const [state] = useContext(JobCreateContext);
+ const [state] = useContext(JobCreateContext);
- const { t } = useTranslation();
- return (
-
-
-
-
-
-
-
-
-
+ const {t} = useTranslation();
+ return (
+
+
+ ({
+ required:
+ state.owner.new &&
+ (!getFieldValue(["owner", "data", "ownr_co_nm"]) ||
+ getFieldValue(["owner", "data", "ownr_co_nm"]) === ""),
+ //message: t("general.validation.required"),
+ }),
+ ]}
+ >
+
+
+ ({
+ required:
+ state.owner.new &&
+ (!getFieldValue(["owner", "data", "ownr_co_nm"]) ||
+ getFieldValue(["owner", "data", "ownr_co_nm"]) === ""),
+ //message: t("general.validation.required"),
+ }),
+ ]}
+ >
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+ ({
+ required:
+ state.owner.new &&
+ (!getFieldValue(["owner", "data", "ownr_ln"]) ||
+ !getFieldValue(["owner", "data", "ownr_fn"]) ||
+ getFieldValue(["owner", "data", "ownr_ln"]) === "" ||
+ getFieldValue(["owner", "data", "ownr_fn"]) === ""),
+ //message: t("general.validation.required"),
+ }),
+ ]}
+ >
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
- PhoneItemFormatterValidation(
- getFieldValue,
- "owner.data.ownr_ph1"
- ),
- ]}
- >
-
-
-
- PhoneItemFormatterValidation(
- getFieldValue,
- "owner.data.ownr_ph2"
- ),
- ]}
- >
-
-
-
-
-
-
-
-
-
-
-
-
- );
+
+
+
+
+
+ PhoneItemFormatterValidation(
+ getFieldValue,
+ "owner.data.ownr_ph1"
+ ),
+ ]}
+ >
+
+
+
+ PhoneItemFormatterValidation(
+ getFieldValue,
+ "owner.data.ownr_ph2"
+ ),
+ ]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+ );
}
diff --git a/client/src/components/jobs-create-owner-info/jobs-create-owner-info.search.component.jsx b/client/src/components/jobs-create-owner-info/jobs-create-owner-info.search.component.jsx
index 9a3e56558..6a58fb409 100644
--- a/client/src/components/jobs-create-owner-info/jobs-create-owner-info.search.component.jsx
+++ b/client/src/components/jobs-create-owner-info/jobs-create-owner-info.search.component.jsx
@@ -1,165 +1,165 @@
-import { Card, Input, Table } from "antd";
-import React, { useContext, useState } from "react";
-import { useTranslation } from "react-i18next";
+import {Card, Input, Table} from "antd";
+import React, {useContext, useState} from "react";
+import {useTranslation} from "react-i18next";
import JobCreateContext from "../../pages/jobs-create/jobs-create.context";
import PhoneFormatter from "../../utils/PhoneFormatter";
-import { alphaSort } from "../../utils/sorters";
+import {alphaSort} from "../../utils/sorters";
export default function JobsCreateOwnerInfoSearchComponent({
- loading,
- owners,
-}) {
- const [state, setState] = useContext(JobCreateContext);
- const [tableState, setTableState] = useState({
- sortedInfo: {},
- filteredInfo: { text: "" },
- });
+ loading,
+ owners,
+ }) {
+ const [state, setState] = useContext(JobCreateContext);
+ const [tableState, setTableState] = useState({
+ sortedInfo: {},
+ filteredInfo: {text: ""},
+ });
- const { t } = useTranslation();
+ const {t} = useTranslation();
- const columns = [
- {
- title: t("owners.fields.ownr_ln"),
- dataIndex: "ownr_ln",
- key: "ownr_ln",
- sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
- sortOrder:
- tableState.sortedInfo.columnKey === "ownr_ln" &&
- tableState.sortedInfo.order,
- },
- {
- title: t("owners.fields.ownr_fn"),
- dataIndex: "ownr_fn",
- key: "ownr_fn",
- sorter: (a, b) => alphaSort(a.ownr_fn, b.ownr_fn),
- sortOrder:
- tableState.sortedInfo.columnKey === "ownr_fn" &&
- tableState.sortedInfo.order,
- },
- {
- title: t("owners.fields.ownr_co_nm"),
- dataIndex: "ownr_co_nm",
- key: "ownr_co_nm",
- sorter: (a, b) => alphaSort(a.ownr_co_nm, b.ownr_co_nm),
- sortOrder:
- tableState.sortedInfo.columnKey === "ownr_co_nm" &&
- tableState.sortedInfo.order,
- },
- {
- title: t("owners.fields.ownr_addr1"),
- dataIndex: "ownr_addr1",
- key: "ownr_addr1",
- sorter: (a, b) => alphaSort(a.ownr_addr1, b.ownr_addr1),
- sortOrder:
- tableState.sortedInfo.columnKey === "ownr_addr1" &&
- tableState.sortedInfo.order,
- },
- {
- title: t("owners.fields.ownr_city"),
- dataIndex: "ownr_city",
- key: "ownr_city",
- sorter: (a, b) => alphaSort(a.ownr_city, b.ownr_city),
- sortOrder:
- tableState.sortedInfo.columnKey === "ownr_city" &&
- tableState.sortedInfo.order,
- },
- {
- title: t("owners.fields.ownr_ea"),
- dataIndex: "ownr_ea",
- key: "ownr_ea",
- sorter: (a, b) => alphaSort(a.ownr_ea, b.ownr_ea),
- sortOrder:
- tableState.sortedInfo.columnKey === "ownr_ea" &&
- tableState.sortedInfo.order,
- },
- {
- title: t("owners.fields.ownr_ph1"),
- dataIndex: "ownr_ph1",
- key: "ownr_ph1",
- render: (text, record) => (
- {record.ownr_ph1}
- ),
- sorter: (a, b) => alphaSort(a.ownr_ph1, b.ownr_ph1),
- sortOrder:
- tableState.sortedInfo.columnKey === "ownr_ph1" &&
- tableState.sortedInfo.order,
- },
- {
- title: t("owners.fields.ownr_ph2"),
- dataIndex: "ownr_ph2",
- key: "ownr_ph2",
- render: (text, record) => (
- {record.ownr_ph2}
- ),
- sorter: (a, b) => alphaSort(a.ownr_ph2, b.ownr_ph2),
- sortOrder:
- tableState.sortedInfo.columnKey === "ownr_ph2" &&
- tableState.sortedInfo.order,
- },
- ];
+ const columns = [
+ {
+ title: t("owners.fields.ownr_ln"),
+ dataIndex: "ownr_ln",
+ key: "ownr_ln",
+ sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
+ sortOrder:
+ tableState.sortedInfo.columnKey === "ownr_ln" &&
+ tableState.sortedInfo.order,
+ },
+ {
+ title: t("owners.fields.ownr_fn"),
+ dataIndex: "ownr_fn",
+ key: "ownr_fn",
+ sorter: (a, b) => alphaSort(a.ownr_fn, b.ownr_fn),
+ sortOrder:
+ tableState.sortedInfo.columnKey === "ownr_fn" &&
+ tableState.sortedInfo.order,
+ },
+ {
+ title: t("owners.fields.ownr_co_nm"),
+ dataIndex: "ownr_co_nm",
+ key: "ownr_co_nm",
+ sorter: (a, b) => alphaSort(a.ownr_co_nm, b.ownr_co_nm),
+ sortOrder:
+ tableState.sortedInfo.columnKey === "ownr_co_nm" &&
+ tableState.sortedInfo.order,
+ },
+ {
+ title: t("owners.fields.ownr_addr1"),
+ dataIndex: "ownr_addr1",
+ key: "ownr_addr1",
+ sorter: (a, b) => alphaSort(a.ownr_addr1, b.ownr_addr1),
+ sortOrder:
+ tableState.sortedInfo.columnKey === "ownr_addr1" &&
+ tableState.sortedInfo.order,
+ },
+ {
+ title: t("owners.fields.ownr_city"),
+ dataIndex: "ownr_city",
+ key: "ownr_city",
+ sorter: (a, b) => alphaSort(a.ownr_city, b.ownr_city),
+ sortOrder:
+ tableState.sortedInfo.columnKey === "ownr_city" &&
+ tableState.sortedInfo.order,
+ },
+ {
+ title: t("owners.fields.ownr_ea"),
+ dataIndex: "ownr_ea",
+ key: "ownr_ea",
+ sorter: (a, b) => alphaSort(a.ownr_ea, b.ownr_ea),
+ sortOrder:
+ tableState.sortedInfo.columnKey === "ownr_ea" &&
+ tableState.sortedInfo.order,
+ },
+ {
+ title: t("owners.fields.ownr_ph1"),
+ dataIndex: "ownr_ph1",
+ key: "ownr_ph1",
+ render: (text, record) => (
+ {record.ownr_ph1}
+ ),
+ sorter: (a, b) => alphaSort(a.ownr_ph1, b.ownr_ph1),
+ sortOrder:
+ tableState.sortedInfo.columnKey === "ownr_ph1" &&
+ tableState.sortedInfo.order,
+ },
+ {
+ title: t("owners.fields.ownr_ph2"),
+ dataIndex: "ownr_ph2",
+ key: "ownr_ph2",
+ render: (text, record) => (
+ {record.ownr_ph2}
+ ),
+ sorter: (a, b) => alphaSort(a.ownr_ph2, b.ownr_ph2),
+ sortOrder:
+ tableState.sortedInfo.columnKey === "ownr_ph2" &&
+ tableState.sortedInfo.order,
+ },
+ ];
- const handleTableChange = (pagination, filters, sorter) => {
- setTableState({ ...tableState, filteredInfo: filters, sortedInfo: sorter });
- };
+ const handleTableChange = (pagination, filters, sorter) => {
+ setTableState({...tableState, filteredInfo: filters, sortedInfo: sorter});
+ };
- return (
- {
- setState({
- ...state,
- owner: { ...state.owner, search: value },
- });
- }}
- enterButton
- />
- }
- >
- {
- setState({
- ...state,
- owner: { ...state.owner, new: false, selectedid: props.id },
- });
- },
- type: "radio",
- selectedRowKeys: [state.owner.selectedid],
- }}
- onRow={(record, rowIndex) => {
- return {
- onClick: (event) => {
- if (record) {
- if (record.id) {
- setState({
- ...state,
- owner: {
- ...state.owner,
- new: false,
- selectedid: record.id,
+ return (
+ {
+ setState({
+ ...state,
+ owner: {...state.owner, search: value},
+ });
+ }}
+ enterButton
+ />
+ }
+ >
+ {
+ setState({
+ ...state,
+ owner: {...state.owner, new: false, selectedid: props.id},
+ });
},
- });
+ type: "radio",
+ selectedRowKeys: [state.owner.selectedid],
+ }}
+ onRow={(record, rowIndex) => {
+ return {
+ onClick: (event) => {
+ if (record) {
+ if (record.id) {
+ setState({
+ ...state,
+ owner: {
+ ...state.owner,
+ new: false,
+ selectedid: record.id,
+ },
+ });
- return;
- }
- }
- setState({
- ...state,
- owner: { ...state.owner, selectedid: null },
- });
- },
- };
- }}
- />
-
- );
+ return;
+ }
+ }
+ setState({
+ ...state,
+ owner: {...state.owner, selectedid: null},
+ });
+ },
+ };
+ }}
+ />
+
+ );
}
diff --git a/client/src/components/jobs-create-vehicle-info/jobs-create-vehicle-info.component.jsx b/client/src/components/jobs-create-vehicle-info/jobs-create-vehicle-info.component.jsx
index b3cbe0fdd..4cdad32bf 100644
--- a/client/src/components/jobs-create-vehicle-info/jobs-create-vehicle-info.component.jsx
+++ b/client/src/components/jobs-create-vehicle-info/jobs-create-vehicle-info.component.jsx
@@ -1,70 +1,71 @@
-import { Checkbox, Col, Row } from "antd";
-import React, { useContext } from "react";
+import {Checkbox, Col, Row} from "antd";
+import React, {useContext} from "react";
import JobCreateContext from "../../pages/jobs-create/jobs-create.context";
import JobsCreateVehicleInfoNewComponent from "./jobs-create-vehicle-info.new.component";
import JobsCreateVehicleInfoSearchComponent from "./jobs-create-vehicle-info.search.component";
-import { useTranslation } from "react-i18next";
+import {useTranslation} from "react-i18next";
+
const colSpan = {
- sm: { span: 24 },
- lg: { span: 12 },
+ sm: {span: 24},
+ lg: {span: 12},
};
export default function JobsCreateVehicleInfoComponent({
- loading,
- vehicles,
- form,
-}) {
- const [state, setState] = useContext(JobCreateContext);
- const { t } = useTranslation();
- return (
-
-
-
- {
- setState({
- ...state,
- vehicle: {
- ...state.vehicle,
- none: false,
- new: !state.vehicle.new,
- selectedid: null,
- },
- });
- }}
- >
- {t("jobs.labels.create.newvehicle")}
-
- {
- setState({
- ...state,
- vehicle: {
- ...state.vehicle,
- new: false,
- none: !state.vehicle.none,
- selectedid: null,
- },
- });
- }}
- >
- {t("jobs.labels.create.novehicle")}
-
-
-
-
-
-
-
-
-
-
- );
+ loading,
+ vehicles,
+ form,
+ }) {
+ const [state, setState] = useContext(JobCreateContext);
+ const {t} = useTranslation();
+ return (
+
+
+
+ {
+ setState({
+ ...state,
+ vehicle: {
+ ...state.vehicle,
+ none: false,
+ new: !state.vehicle.new,
+ selectedid: null,
+ },
+ });
+ }}
+ >
+ {t("jobs.labels.create.newvehicle")}
+
+ {
+ setState({
+ ...state,
+ vehicle: {
+ ...state.vehicle,
+ new: false,
+ none: !state.vehicle.none,
+ selectedid: null,
+ },
+ });
+ }}
+ >
+ {t("jobs.labels.create.novehicle")}
+
+
+
+
+
+
+
+
+
+
+ );
}
diff --git a/client/src/components/jobs-create-vehicle-info/jobs-create-vehicle-info.container.jsx b/client/src/components/jobs-create-vehicle-info/jobs-create-vehicle-info.container.jsx
index 072930164..a9bfa39c0 100644
--- a/client/src/components/jobs-create-vehicle-info/jobs-create-vehicle-info.container.jsx
+++ b/client/src/components/jobs-create-vehicle-info/jobs-create-vehicle-info.container.jsx
@@ -1,26 +1,26 @@
-import { useQuery } from "@apollo/client";
-import React, { useContext } from "react";
-import { SEARCH_VEHICLES } from "../../graphql/vehicles.queries";
+import {useQuery} from "@apollo/client";
+import React, {useContext} from "react";
+import {SEARCH_VEHICLES} from "../../graphql/vehicles.queries";
import JobCreateContext from "../../pages/jobs-create/jobs-create.context";
import AlertComponent from "../alert/alert.component";
import JobsCreateVehicleInfoComponent from "./jobs-create-vehicle-info.component";
-export default function JobsCreateVehicleInfoContainer({ form }) {
- const [state] = useContext(JobCreateContext);
- const { loading, error, data } = useQuery(SEARCH_VEHICLES, {
- variables: { search: `%${state.vehicle.search}%` },
- skip: !state.vehicle.search,
- fetchPolicy: "network-only",
- nextFetchPolicy: "network-only",
- });
+export default function JobsCreateVehicleInfoContainer({form}) {
+ const [state] = useContext(JobCreateContext);
+ const {loading, error, data} = useQuery(SEARCH_VEHICLES, {
+ variables: {search: `%${state.vehicle.search}%`},
+ skip: !state.vehicle.search,
+ fetchPolicy: "network-only",
+ nextFetchPolicy: "network-only",
+ });
- if (error) return ;
+ if (error) return ;
- return (
-
- );
+ return (
+
+ );
}
diff --git a/client/src/components/jobs-create-vehicle-info/jobs-create-vehicle-info.new.component.jsx b/client/src/components/jobs-create-vehicle-info/jobs-create-vehicle-info.new.component.jsx
index 0813f9f21..dad4385cd 100644
--- a/client/src/components/jobs-create-vehicle-info/jobs-create-vehicle-info.new.component.jsx
+++ b/client/src/components/jobs-create-vehicle-info/jobs-create-vehicle-info.new.component.jsx
@@ -1,202 +1,202 @@
-import { Form, Input } from "antd";
-import React, { useContext } from "react";
-import { useTranslation } from "react-i18next";
+import {Form, Input} from "antd";
+import React, {useContext} from "react";
+import {useTranslation} from "react-i18next";
import JobCreateContext from "../../pages/jobs-create/jobs-create.context";
import FormDatePicker from "../form-date-picker/form-date-picker.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
import JobsCreateVehicleInfoPredefined from "./jobs-create-vehicle-info.predefined.component";
-export default function JobsCreateVehicleInfoNewComponent({ form }) {
- const [state] = useContext(JobCreateContext);
+export default function JobsCreateVehicleInfoNewComponent({form}) {
+ const [state] = useContext(JobCreateContext);
- const { t } = useTranslation();
- return (
-
+ );
}
diff --git a/client/src/components/jobs-create-vehicle-info/jobs-create-vehicle-info.predefined.component.jsx b/client/src/components/jobs-create-vehicle-info/jobs-create-vehicle-info.predefined.component.jsx
index c2c2404ac..a8e577419 100644
--- a/client/src/components/jobs-create-vehicle-info/jobs-create-vehicle-info.predefined.component.jsx
+++ b/client/src/components/jobs-create-vehicle-info/jobs-create-vehicle-info.predefined.component.jsx
@@ -1,81 +1,81 @@
-import { PlusOutlined, SearchOutlined } from "@ant-design/icons";
-import { Button, Input, Popover, Table } from "antd";
-import React, { useState } from "react";
-import { useTranslation } from "react-i18next";
+import {PlusOutlined, SearchOutlined} from "@ant-design/icons";
+import {Button, Input, Popover, Table} from "antd";
+import React, {useState} from "react";
+import {useTranslation} from "react-i18next";
import PredefinedVehicles from "./predefined-vehicles.js";
-export default function JobsCreateVehicleInfoPredefined({ disabled, form }) {
- const [open, setOpen] = useState(false);
- const [search, setSearch] = useState("");
- const { t } = useTranslation();
- const handleOpenChange = (newOpen) => {
- setOpen(newOpen);
- setSearch("");
- };
- const filteredPredefinedVehicles =
- search === ""
- ? PredefinedVehicles
- : PredefinedVehicles.filter(
- (v) =>
- v.make.toLowerCase().includes(search.toLowerCase()) ||
- v.model.toLowerCase().includes(search.toLowerCase())
- );
+export default function JobsCreateVehicleInfoPredefined({disabled, form}) {
+ const [open, setOpen] = useState(false);
+ const [search, setSearch] = useState("");
+ const {t} = useTranslation();
+ const handleOpenChange = (newOpen) => {
+ setOpen(newOpen);
+ setSearch("");
+ };
+ const filteredPredefinedVehicles =
+ search === ""
+ ? PredefinedVehicles
+ : PredefinedVehicles.filter(
+ (v) =>
+ v.make.toLowerCase().includes(search.toLowerCase()) ||
+ v.model.toLowerCase().includes(search.toLowerCase())
+ );
- const popContent = () => (
-
-
setSearch(value)} />}
- dataSource={filteredPredefinedVehicles}
- columns={[
- {
- dataIndex: "make",
- key: "make",
- title: t("vehicles.fields.v_make_desc"),
- },
- {
- dataIndex: "model",
- key: "model",
- title: t("vehicles.fields.v_model_desc"),
- },
- {
- dataIndex: "select",
- key: "select",
- title: t("general.labels.actions"),
- render: (value, record) => (
- {
- form.setFieldsValue({
- vehicle: {
- data: {
- v_make_desc: record.make,
- v_model_desc: record.model,
- },
+ const popContent = () => (
+
+
setSearch(value)}/>}
+ dataSource={filteredPredefinedVehicles}
+ columns={[
+ {
+ dataIndex: "make",
+ key: "make",
+ title: t("vehicles.fields.v_make_desc"),
},
- });
- setOpen(false);
- setSearch("");
- }}
- >
-
-
- ),
- },
- ]}
- />
-
- );
- return (
-
-
-
- );
+ {
+ dataIndex: "model",
+ key: "model",
+ title: t("vehicles.fields.v_model_desc"),
+ },
+ {
+ dataIndex: "select",
+ key: "select",
+ title: t("general.labels.actions"),
+ render: (value, record) => (
+ {
+ form.setFieldsValue({
+ vehicle: {
+ data: {
+ v_make_desc: record.make,
+ v_model_desc: record.model,
+ },
+ },
+ });
+ setOpen(false);
+ setSearch("");
+ }}
+ >
+
+
+ ),
+ },
+ ]}
+ />
+
+ );
+ return (
+
+
+
+ );
}
diff --git a/client/src/components/jobs-create-vehicle-info/jobs-create-vehicle-info.search.component.jsx b/client/src/components/jobs-create-vehicle-info/jobs-create-vehicle-info.search.component.jsx
index b4c4152c8..44495f613 100644
--- a/client/src/components/jobs-create-vehicle-info/jobs-create-vehicle-info.search.component.jsx
+++ b/client/src/components/jobs-create-vehicle-info/jobs-create-vehicle-info.search.component.jsx
@@ -1,134 +1,134 @@
-import React, { useContext, useState } from "react";
-import { useTranslation } from "react-i18next";
-import { Table, Input, Card, Space } from "antd";
-import { Link } from "react-router-dom";
-import { alphaSort } from "../../utils/sorters";
+import React, {useContext, useState} from "react";
+import {useTranslation} from "react-i18next";
+import {Card, Input, Space, Table} from "antd";
+import {Link} from "react-router-dom";
+import {alphaSort} from "../../utils/sorters";
import JobCreateContext from "../../pages/jobs-create/jobs-create.context";
import VehicleVinDisplay from "../vehicle-vin-display/vehicle-vin-display.component";
export default function JobsCreateVehicleInfoSearchComponent({
- loading,
- vehicles,
-}) {
- const [state, setState] = useContext(JobCreateContext);
- const [tableState, setTableState] = useState({
- sortedInfo: {},
- filteredInfo: { text: "" },
- });
+ loading,
+ vehicles,
+ }) {
+ const [state, setState] = useContext(JobCreateContext);
+ const [tableState, setTableState] = useState({
+ sortedInfo: {},
+ filteredInfo: {text: ""},
+ });
- const { t } = useTranslation();
+ const {t} = useTranslation();
- const columns = [
- {
- title: t("vehicles.fields.v_vin"),
- dataIndex: "v_vin",
- key: "v_vin",
- sorter: (a, b) => alphaSort(a.v_vin, b.v_vin),
- sortOrder:
- tableState.sortedInfo.columnKey === "v_vin" &&
- tableState.sortedInfo.order,
- render: (text, record) => (
-
- {record.v_vin}
-
- ),
- },
- {
- title: t("vehicles.fields.description"),
- dataIndex: "description",
- key: "description",
- render: (text, record) => {
- return (
- {`${record.v_model_yr} ${record.v_make_desc} ${record.v_model_desc} ${record.v_color}`}
- );
- },
- },
- {
- title: t("vehicles.fields.plate_no"),
- dataIndex: "plate",
- key: "plate",
- render: (text, record) => {
- return {`${record.plate_st} | ${record.plate_no}`};
- },
- },
- ];
-
- const handleTableChange = (pagination, filters, sorter) => {
- setTableState({ ...tableState, filteredInfo: filters, sortedInfo: sorter });
- };
-
- return (
-
- {
- setState({
- ...state,
- vehicle: { ...state.vehicle, search: value },
- });
- }}
- enterButton
- />
-
- }
- >
- {
- setState({
- ...state,
- vehicle: {
- ...state.vehicle,
- none: false,
- new: false,
- selectedid: props.id,
- vehicleObj: props,
- },
- });
- },
- type: "radio",
- selectedRowKeys: [state.vehicle.selectedid],
- }}
- onRow={(record, rowIndex) => {
- return {
- onClick: (event) => {
- if (record) {
- if (record.id) {
- setState({
- ...state,
- vehicle: {
- ...state.vehicle,
- none: false,
- new: false,
- selectedid: record.id,
- vehicleObj: record,
- },
- });
-
- return;
- }
- }
- setState({
- ...state,
- vehicle: {
- ...state.vehicle,
- selectedid: null,
- vehicleObj: null,
- },
- });
+ const columns = [
+ {
+ title: t("vehicles.fields.v_vin"),
+ dataIndex: "v_vin",
+ key: "v_vin",
+ sorter: (a, b) => alphaSort(a.v_vin, b.v_vin),
+ sortOrder:
+ tableState.sortedInfo.columnKey === "v_vin" &&
+ tableState.sortedInfo.order,
+ render: (text, record) => (
+
+ {record.v_vin}
+
+ ),
+ },
+ {
+ title: t("vehicles.fields.description"),
+ dataIndex: "description",
+ key: "description",
+ render: (text, record) => {
+ return (
+ {`${record.v_model_yr} ${record.v_make_desc} ${record.v_model_desc} ${record.v_color}`}
+ );
},
- };
- }}
- />
-
- );
+ },
+ {
+ title: t("vehicles.fields.plate_no"),
+ dataIndex: "plate",
+ key: "plate",
+ render: (text, record) => {
+ return {`${record.plate_st} | ${record.plate_no}`};
+ },
+ },
+ ];
+
+ const handleTableChange = (pagination, filters, sorter) => {
+ setTableState({...tableState, filteredInfo: filters, sortedInfo: sorter});
+ };
+
+ return (
+
+ {
+ setState({
+ ...state,
+ vehicle: {...state.vehicle, search: value},
+ });
+ }}
+ enterButton
+ />
+
+ }
+ >
+ {
+ setState({
+ ...state,
+ vehicle: {
+ ...state.vehicle,
+ none: false,
+ new: false,
+ selectedid: props.id,
+ vehicleObj: props,
+ },
+ });
+ },
+ type: "radio",
+ selectedRowKeys: [state.vehicle.selectedid],
+ }}
+ onRow={(record, rowIndex) => {
+ return {
+ onClick: (event) => {
+ if (record) {
+ if (record.id) {
+ setState({
+ ...state,
+ vehicle: {
+ ...state.vehicle,
+ none: false,
+ new: false,
+ selectedid: record.id,
+ vehicleObj: record,
+ },
+ });
+
+ return;
+ }
+ }
+ setState({
+ ...state,
+ vehicle: {
+ ...state.vehicle,
+ selectedid: null,
+ vehicleObj: null,
+ },
+ });
+ },
+ };
+ }}
+ />
+
+ );
}
diff --git a/client/src/components/jobs-create-vehicle-info/predefined-vehicles.js b/client/src/components/jobs-create-vehicle-info/predefined-vehicles.js
index 7ca0042db..fab4b33a8 100644
--- a/client/src/components/jobs-create-vehicle-info/predefined-vehicles.js
+++ b/client/src/components/jobs-create-vehicle-info/predefined-vehicles.js
@@ -1,3991 +1,3991 @@
const obj = [
- {
- make: "ACURA",
- model: "1.6 EL",
- },
- {
- make: "ACURA",
- model: "1.7 EL",
- },
- {
- make: "ACURA",
- model: "2.3 CL",
- },
- {
- make: "ACURA",
- model: "2.5TL",
- },
- {
- make: "ACURA",
- model: "3.2TL",
- },
- {
- make: "ACURA",
- model: "3.5RL",
- },
- {
- make: "ACURA",
- model: "CL",
- },
- {
- make: "ACURA",
- model: "CSX",
- },
- {
- make: "ACURA",
- model: "EL",
- },
- {
- make: "ACURA",
- model: "GSR",
- },
- {
- make: "ACURA",
- model: "ILX",
- },
- {
- make: "ACURA",
- model: "INTEGRA",
- },
- {
- make: "ACURA",
- model: "LEGEND",
- },
- {
- make: "ACURA",
- model: "MDX",
- },
- {
- make: "ACURA",
- model: "NSX",
- },
- {
- make: "ACURA",
- model: "RDX",
- },
- {
- make: "ACURA",
- model: "RSX",
- },
- {
- make: "ACURA",
- model: "TL",
- },
- {
- make: "ACURA",
- model: "TL-S",
- },
- {
- make: "ACURA",
- model: "TLX",
- },
- {
- make: "ACURA",
- model: "TSK 4",
- },
- {
- make: "ACURA",
- model: "TSX",
- },
- {
- make: "ACURA",
- model: "VIGOR",
- },
- {
- make: "AMC",
- model: "GENERAL",
- },
- {
- make: "AMC",
- model: "RAMBLER",
- },
- {
- make: "ATLAS",
- model: "CUB",
- },
- {
- make: "AUDI",
- model: "100",
- },
- {
- make: "AUDI",
- model: "A2",
- },
- {
- make: "AUDI",
- model: "A2 QUATTRO",
- },
- {
- make: "AUDI",
- model: "A3",
- },
- {
- make: "AUDI",
- model: "A4",
- },
- {
- make: "AUDI",
- model: "A4 QUATTRO",
- },
- {
- make: "AUDI",
- model: "A5",
- },
- {
- make: "AUDI",
- model: "A6",
- },
- {
- make: "AUDI",
- model: "Q3",
- },
- {
- make: "AUDI",
- model: "Q5",
- },
- {
- make: "AUDI",
- model: "Q7",
- },
- {
- make: "AUDI",
- model: "QUATTRO",
- },
- {
- make: "AUDI",
- model: "RS4",
- },
- {
- make: "AUDI",
- model: "S3",
- },
- {
- make: "AUDI",
- model: "S4",
- },
- {
- make: "AUDI",
- model: "S5",
- },
- {
- make: "AUDI",
- model: "S6",
- },
- {
- make: "AUDI",
- model: "TT",
- },
- {
- make: "AUSTIN",
- model: "HEALY",
- },
- {
- make: "BMW",
- model: "128I",
- },
- {
- make: "BMW",
- model: "135I",
- },
- {
- make: "BMW",
- model: "135IS",
- },
- {
- make: "BMW",
- model: "228I",
- },
- {
- make: "BMW",
- model: "3 SERIES",
- },
- {
- make: "BMW",
- model: "318",
- },
- {
- make: "BMW",
- model: "318 TI",
- },
- {
- make: "BMW",
- model: "318I",
- },
- {
- make: "BMW",
- model: "318IS",
- },
- {
- make: "BMW",
- model: "320CI",
- },
- {
- make: "BMW",
- model: "320I",
- },
- {
- make: "BMW",
- model: "323I",
- },
- {
- make: "BMW",
- model: "325",
- },
- {
- make: "BMW",
- model: "325CI",
- },
- {
- make: "BMW",
- model: "325E",
- },
- {
- make: "BMW",
- model: "325I",
- },
- {
- make: "BMW",
- model: "325IS",
- },
- {
- make: "BMW",
- model: "325XI",
- },
- {
- make: "BMW",
- model: "328CI",
- },
- {
- make: "BMW",
- model: "328D",
- },
- {
- make: "BMW",
- model: "328I",
- },
- {
- make: "BMW",
- model: "328XI",
- },
- {
- make: "BMW",
- model: "330CI",
- },
- {
- make: "BMW",
- model: "330I",
- },
- {
- make: "BMW",
- model: "330XI",
- },
- {
- make: "BMW",
- model: "335I",
- },
- {
- make: "BMW",
- model: "335XI",
- },
- {
- make: "BMW",
- model: "352I",
- },
- {
- make: "BMW",
- model: "428I",
- },
- {
- make: "BMW",
- model: "430I",
- },
- {
- make: "BMW",
- model: "435I",
- },
- {
- make: "BMW",
- model: "440I",
- },
- {
- make: "BMW",
- model: "520I",
- },
- {
- make: "BMW",
- model: "525I",
- },
- {
- make: "BMW",
- model: "528I",
- },
- {
- make: "BMW",
- model: "530",
- },
- {
- make: "BMW",
- model: "530I",
- },
- {
- make: "BMW",
- model: "530IA",
- },
- {
- make: "BMW",
- model: "530XI",
- },
- {
- make: "BMW",
- model: "535I",
- },
- {
- make: "BMW",
- model: "540I",
- },
- {
- make: "BMW",
- model: "640I",
- },
- {
- make: "BMW",
- model: "645CI",
- },
- {
- make: "BMW",
- model: "735",
- },
- {
- make: "BMW",
- model: "740I",
- },
- {
- make: "BMW",
- model: "745LI",
- },
- {
- make: "BMW",
- model: "750I",
- },
- {
- make: "BMW",
- model: "750LI",
- },
- {
- make: "BMW",
- model: "K-1200",
- },
- {
- make: "BMW",
- model: "M3",
- },
- {
- make: "BMW",
- model: "M5",
- },
- {
- make: "BMW",
- model: "X1",
- },
- {
- make: "BMW",
- model: "X3",
- },
- {
- make: "BMW",
- model: "X5",
- },
- {
- make: "BMW",
- model: "X6",
- },
- {
- make: "BMW",
- model: "Z3",
- },
- {
- make: "BMW",
- model: "Z4",
- },
- {
- make: "BUICK",
- model: "ALLURE",
- },
- {
- make: "BUICK",
- model: "CENTURY",
- },
- {
- make: "BUICK",
- model: "ENCLAVE",
- },
- {
- make: "BUICK",
- model: "ENCORE",
- },
- {
- make: "BUICK",
- model: "ENVISION",
- },
- {
- make: "BUICK",
- model: "INVICTA",
- },
- {
- make: "BUICK",
- model: "LACROSSE",
- },
- {
- make: "BUICK",
- model: "LESABRE",
- },
- {
- make: "BUICK",
- model: "LUCERNE",
- },
- {
- make: "BUICK",
- model: "PARK AVENUE",
- },
- {
- make: "BUICK",
- model: "REGAL",
- },
- {
- make: "BUICK",
- model: "RENDEZVOUS",
- },
- {
- make: "BUICK",
- model: "RIVIERA",
- },
- {
- make: "BUICK",
- model: "ROADMASTER",
- },
- {
- make: "BUICK",
- model: "SKYLARK",
- },
- {
- make: "BUICK",
- model: "SOMERSET",
- },
- {
- make: "BUICK",
- model: "SPECIAL",
- },
- {
- make: "BUICK",
- model: "TERRAZA",
- },
- {
- make: "BUICK",
- model: "VERANO",
- },
- {
- make: "CADILLAC",
- model: "ATS",
- },
- {
- make: "CADILLAC",
- model: "CATERA",
- },
- {
- make: "CADILLAC",
- model: "CTS",
- },
- {
- make: "CADILLAC",
- model: "DE VILLE",
- },
- {
- make: "CADILLAC",
- model: "DTS",
- },
- {
- make: "CADILLAC",
- model: "ELDORADO",
- },
- {
- make: "CADILLAC",
- model: "ESCLADE",
- },
- {
- make: "CADILLAC",
- model: "FLEETWOOD",
- },
- {
- make: "CADILLAC",
- model: "SEVILLE",
- },
- {
- make: "CADILLAC",
- model: "SRX",
- },
- {
- make: "CADILLAC",
- model: "STS",
- },
- {
- make: "CADILLAC",
- model: "XLR",
- },
- {
- make: "CHEVROLET",
- model: "1500",
- },
- {
- make: "CHEVROLET",
- model: "2500",
- },
- {
- make: "CHEVROLET",
- model: "2500HD",
- },
- {
- make: "CHEVROLET",
- model: "2WHDR",
- },
- {
- make: "CHEVROLET",
- model: "3500 EXPRESS VAN",
- },
- {
- make: "CHEVROLET",
- model: "3500 HD",
- },
- {
- make: "CHEVROLET",
- model: "ALER",
- },
- {
- make: "CHEVROLET",
- model: "ASTRO",
- },
- {
- make: "CHEVROLET",
- model: "AVALANCHE",
- },
- {
- make: "CHEVROLET",
- model: "AVEO",
- },
- {
- make: "CHEVROLET",
- model: "BEL AIR",
- },
- {
- make: "CHEVROLET",
- model: "BERETTA",
- },
- {
- make: "CHEVROLET",
- model: "BLAZER",
- },
- {
- make: "CHEVROLET",
- model: "BOLT",
- },
- {
- make: "CHEVROLET",
- model: "BOLT EV",
- },
- {
- make: "CHEVROLET",
- model: "C10",
- },
- {
- make: "CHEVROLET",
- model: "C20",
- },
- {
- make: "CHEVROLET",
- model: "C2500",
- },
- {
- make: "CHEVROLET",
- model: "C3500",
- },
- {
- make: "CHEVROLET",
- model: "CAMARO",
- },
- {
- make: "CHEVROLET",
- model: "CAPRICE",
- },
- {
- make: "CHEVROLET",
- model: "CAVALIER",
- },
- {
- make: "CHEVROLET",
- model: "CHEVELLE",
- },
- {
- make: "CHEVROLET",
- model: "CITY EXPRESS",
- },
- {
- make: "CHEVROLET",
- model: "COBALT",
- },
- {
- make: "CHEVROLET",
- model: "COLORADO",
- },
- {
- make: "CHEVROLET",
- model: "CORSICA",
- },
- {
- make: "CHEVROLET",
- model: "CORVETTE",
- },
- {
- make: "CHEVROLET",
- model: "CRUZE",
- },
- {
- make: "CHEVROLET",
- model: "EL CAMINO",
- },
- {
- make: "CHEVROLET",
- model: "EPICA",
- },
- {
- make: "CHEVROLET",
- model: "EQUINOX",
- },
- {
- make: "CHEVROLET",
- model: "EXPRESS",
- },
- {
- make: "CHEVROLET",
- model: "EXPRESS 1500",
- },
- {
- make: "CHEVROLET",
- model: "EXPRESS 2500",
- },
- {
- make: "CHEVROLET",
- model: "EXPRESS 3500",
- },
- {
- make: "CHEVROLET",
- model: "EXPRESS VAN",
- },
- {
- make: "CHEVROLET",
- model: "G1500",
- },
- {
- make: "CHEVROLET",
- model: "G2500",
- },
- {
- make: "CHEVROLET",
- model: "G30",
- },
- {
- make: "CHEVROLET",
- model: "G3500",
- },
- {
- make: "CHEVROLET",
- model: "G4500",
- },
- {
- make: "CHEVROLET",
- model: "GMT-400",
- },
- {
- make: "CHEVROLET",
- model: "HD 2500",
- },
- {
- make: "CHEVROLET",
- model: "HHR",
- },
- {
- make: "CHEVROLET",
- model: "IMPALA",
- },
- {
- make: "CHEVROLET",
- model: "K1500",
- },
- {
- make: "CHEVROLET",
- model: "K2500",
- },
- {
- make: "CHEVROLET",
- model: "K3500",
- },
- {
- make: "CHEVROLET",
- model: "K5500",
- },
- {
- make: "CHEVROLET",
- model: "LUMINA",
- },
- {
- make: "CHEVROLET",
- model: "MALIBU",
- },
- {
- make: "CHEVROLET",
- model: "MALIBU HYBRID",
- },
- {
- make: "CHEVROLET",
- model: "MONTE CARLO",
- },
- {
- make: "CHEVROLET",
- model: "NOMAD",
- },
- {
- make: "CHEVROLET",
- model: "NOVA",
- },
- {
- make: "CHEVROLET",
- model: "OPTRA",
- },
- {
- make: "CHEVROLET",
- model: "ORLANDO",
- },
- {
- make: "CHEVROLET",
- model: "P30",
- },
- {
- make: "CHEVROLET",
- model: "S10",
- },
- {
- make: "CHEVROLET",
- model: "S10 BLAZER",
- },
- {
- make: "CHEVROLET",
- model: "SAVANNA",
- },
- {
- make: "CHEVROLET",
- model: "SILVERADO",
- },
- {
- make: "CHEVROLET",
- model: "SILVERADO 2500 HD",
- },
- {
- make: "CHEVROLET",
- model: "SILVERADO 3500",
- },
- {
- make: "CHEVROLET",
- model: "SILVERADO 3500 HD",
- },
- {
- make: "CHEVROLET",
- model: "SONIC",
- },
- {
- make: "CHEVROLET",
- model: "SPARK",
- },
- {
- make: "CHEVROLET",
- model: "SPORT VAN G20",
- },
- {
- make: "CHEVROLET",
- model: "SPRINT",
- },
- {
- make: "CHEVROLET",
- model: "SUBURBAN",
- },
- {
- make: "CHEVROLET",
- model: "TAHOE",
- },
- {
- make: "CHEVROLET",
- model: "TRACKER",
- },
- {
- make: "CHEVROLET",
- model: "TRAILBLAZER",
- },
- {
- make: "CHEVROLET",
- model: "TRAVERSE",
- },
- {
- make: "CHEVROLET",
- model: "TRAX",
- },
- {
- make: "CHEVROLET",
- model: "TREX",
- },
- {
- make: "CHEVROLET",
- model: "UPLANDER",
- },
- {
- make: "CHEVROLET",
- model: "VENTURE",
- },
- {
- make: "CHEVROLET",
- model: "VOLT",
- },
- {
- make: "CHEVROLET",
- model: "Z24",
- },
- {
- make: "CHEVROLET",
- model: "Z28 IROC",
- },
- {
- make: "CHRYSLER",
- model: "200",
- },
- {
- make: "CHRYSLER",
- model: "300",
- },
- {
- make: "CHRYSLER",
- model: "300C",
- },
- {
- make: "CHRYSLER",
- model: "300M",
- },
- {
- make: "CHRYSLER",
- model: "5TH AVE",
- },
- {
- make: "CHRYSLER",
- model: "ASPEN",
- },
- {
- make: "CHRYSLER",
- model: "CIRRUS",
- },
- {
- make: "CHRYSLER",
- model: "CONCORDE",
- },
- {
- make: "CHRYSLER",
- model: "CROSSFIRE",
- },
- {
- make: "CHRYSLER",
- model: "DAYTONA",
- },
- {
- make: "CHRYSLER",
- model: "E CLASS",
- },
- {
- make: "CHRYSLER",
- model: "INTREPID",
- },
- {
- make: "CHRYSLER",
- model: "LEBARON",
- },
- {
- make: "CHRYSLER",
- model: "LHS",
- },
- {
- make: "CHRYSLER",
- model: "NEON",
- },
- {
- make: "CHRYSLER",
- model: "NEW YORKER",
- },
- {
- make: "CHRYSLER",
- model: "PACIFICA",
- },
- {
- make: "CHRYSLER",
- model: "PT CRUISER",
- },
- {
- make: "CHRYSLER",
- model: "SEBRING",
- },
- {
- make: "CHRYSLER",
- model: "TOWN & COUNTRY",
- },
- {
- make: "DATSUN",
- model: "PICK-UP",
- },
- {
- make: "DODGE",
- model: "1500",
- },
- {
- make: "DODGE",
- model: "250",
- },
- {
- make: "DODGE",
- model: "2500",
- },
- {
- make: "DODGE",
- model: "4500",
- },
- {
- make: "DODGE",
- model: "5500",
- },
- {
- make: "DODGE",
- model: "ARIES",
- },
- {
- make: "DODGE",
- model: "AVENGER",
- },
- {
- make: "DODGE",
- model: "B1500",
- },
- {
- make: "DODGE",
- model: "B200",
- },
- {
- make: "DODGE",
- model: "B250",
- },
- {
- make: "DODGE",
- model: "B350",
- },
- {
- make: "DODGE",
- model: "CALIBER",
- },
- {
- make: "DODGE",
- model: "CAMPERVAN",
- },
- {
- make: "DODGE",
- model: "CARAVAN",
- },
- {
- make: "DODGE",
- model: "CHALLENGER",
- },
- {
- make: "DODGE",
- model: "CHARGER",
- },
- {
- make: "DODGE",
- model: "COLT",
- },
- {
- make: "DODGE",
- model: "CORNET",
- },
- {
- make: "DODGE",
- model: "CV VAN",
- },
- {
- make: "DODGE",
- model: "D100",
- },
- {
- make: "DODGE",
- model: "D200",
- },
- {
- make: "DODGE",
- model: "D250",
- },
- {
- make: "DODGE",
- model: "D300",
- },
- {
- make: "DODGE",
- model: "D350",
- },
- {
- make: "DODGE",
- model: "DAKOTA",
- },
- {
- make: "DODGE",
- model: "DART",
- },
- {
- make: "DODGE",
- model: "DEMON",
- },
- {
- make: "DODGE",
- model: "DURANGO",
- },
- {
- make: "DODGE",
- model: "DYNASTY",
- },
- {
- make: "DODGE",
- model: "GRAND CARAVAN",
- },
- {
- make: "DODGE",
- model: "GRAND CARAVEN SE",
- },
- {
- make: "DODGE",
- model: "JOURNEY",
- },
- {
- make: "DODGE",
- model: "MAGNUM",
- },
- {
- make: "DODGE",
- model: "MOTORHOME",
- },
- {
- make: "DODGE",
- model: "NEON",
- },
- {
- make: "DODGE",
- model: "NITRO",
- },
- {
- make: "DODGE",
- model: "PRO MASTER",
- },
- {
- make: "DODGE",
- model: "PRO MASTER 3500",
- },
- {
- make: "DODGE",
- model: "RAM",
- },
- {
- make: "DODGE",
- model: "RAM 1500",
- },
- {
- make: "DODGE",
- model: "RAM 250",
- },
- {
- make: "DODGE",
- model: "RAM 2500",
- },
- {
- make: "DODGE",
- model: "RAM 3500",
- },
- {
- make: "DODGE",
- model: "RAM 5500",
- },
- {
- make: "DODGE",
- model: "RAM PRO MASTER",
- },
- {
- make: "DODGE",
- model: "RAM SRT10",
- },
- {
- make: "DODGE",
- model: "RAM VAN",
- },
- {
- make: "DODGE",
- model: "RAMPAGE",
- },
- {
- make: "DODGE",
- model: "SHADOW",
- },
- {
- make: "DODGE",
- model: "SPIRIT",
- },
- {
- make: "DODGE",
- model: "SPRINTER 3500",
- },
- {
- make: "DODGE",
- model: "SRT",
- },
- {
- make: "DODGE",
- model: "STEALTH",
- },
- {
- make: "DODGE",
- model: "STRATUS",
- },
- {
- make: "DODGE",
- model: "SWINGER",
- },
- {
- make: "DODGE",
- model: "SX 2.0",
- },
- {
- make: "DODGE",
- model: "W200",
- },
- {
- make: "DODGE",
- model: "W350",
- },
- {
- make: "EAGLE",
- model: "SUMMIT",
- },
- {
- make: "EAGLE",
- model: "TALON",
- },
- {
- make: "EAGLE",
- model: "VISION",
- },
- {
- make: "FIAT",
- model: "500C",
- },
- {
- make: "FIAT",
- model: "500L",
- },
- {
- make: "FORD",
- model: "500",
- },
- {
- make: "FORD",
- model: "AEROSTAR",
- },
- {
- make: "FORD",
- model: "ASPIRE",
- },
- {
- make: "FORD",
- model: "BRONCO",
- },
- {
- make: "FORD",
- model: "CMAX",
- },
- {
- make: "FORD",
- model: "CONTOUR",
- },
- {
- make: "FORD",
- model: "CROWN VIC",
- },
- {
- make: "FORD",
- model: "CUBE VAN",
- },
- {
- make: "FORD",
- model: "DUMP TRUCK",
- },
- {
- make: "FORD",
- model: "E150",
- },
- {
- make: "FORD",
- model: "E250",
- },
- {
- make: "FORD",
- model: "E350",
- },
- {
- make: "FORD",
- model: "E450",
- },
- {
- make: "FORD",
- model: "ECO SPORT",
- },
- {
- make: "FORD",
- model: "ECONOLINE",
- },
- {
- make: "FORD",
- model: "EDGE",
- },
- {
- make: "FORD",
- model: "ESCAPE",
- },
- {
- make: "FORD",
- model: "ESCORT",
- },
- {
- make: "FORD",
- model: "EXCURSION",
- },
- {
- make: "FORD",
- model: "EXPEDITION",
- },
- {
- make: "FORD",
- model: "EXPLORER",
- },
- {
- make: "FORD",
- model: "EXPLORER SPORT",
- },
- {
- make: "FORD",
- model: "EXPLORER SPORT TRAC",
- },
- {
- make: "FORD",
- model: "F-150",
- },
- {
- make: "FORD",
- model: "F-250",
- },
- {
- make: "FORD",
- model: "F-350",
- },
- {
- make: "FORD",
- model: "F-450",
- },
- {
- make: "FORD",
- model: "F-550",
- },
- {
- make: "FORD",
- model: "FAIRLANE",
- },
- {
- make: "FORD",
- model: "FESTIVA",
- },
- {
- make: "FORD",
- model: "FIESTA",
- },
- {
- make: "FORD",
- model: "FLAT DECK",
- },
- {
- make: "FORD",
- model: "FLEX",
- },
- {
- make: "FORD",
- model: "FOCUS",
- },
- {
- make: "FORD",
- model: "FREESTAR",
- },
- {
- make: "FORD",
- model: "FREESTYLE",
- },
- {
- make: "FORD",
- model: "FUSION",
- },
- {
- make: "FORD",
- model: "GALAXIE 500",
- },
- {
- make: "FORD",
- model: "LARIAT",
- },
- {
- make: "FORD",
- model: "LCF",
- },
- {
- make: "FORD",
- model: "LGT",
- },
- {
- make: "FORD",
- model: "MOTORHOME",
- },
- {
- make: "FORD",
- model: "MUSTANG",
- },
- {
- make: "FORD",
- model: "PLEASURE WAY",
- },
- {
- make: "FORD",
- model: "PROBE",
- },
- {
- make: "FORD",
- model: "RANGER",
- },
- {
- make: "FORD",
- model: "RAPTOR",
- },
- {
- make: "FORD",
- model: "SPORT TRAC",
- },
- {
- make: "FORD",
- model: "SUPER DUTY",
- },
- {
- make: "FORD",
- model: "TAURUS",
- },
- {
- make: "FORD",
- model: "T-BIRD",
- },
- {
- make: "FORD",
- model: "T-BUCKET",
- },
- {
- make: "FORD",
- model: "TEMPO",
- },
- {
- make: "FORD",
- model: "THUNDERBIRD",
- },
- {
- make: "FORD",
- model: "TRANSIT",
- },
- {
- make: "FORD",
- model: "TRANSIT 250",
- },
- {
- make: "FORD",
- model: "TRANSIT 350HD",
- },
- {
- make: "FORD",
- model: "TRANSIT CONNECT",
- },
- {
- make: "FORD",
- model: "TRANSIT COONECT",
- },
- {
- make: "FORD",
- model: "WINDSTAR",
- },
- {
- make: "FREIGHTLINER",
- model: "FL70",
- },
- {
- make: "FREIGHTLINER",
- model: "M2",
- },
- {
- make: "GEO",
- model: "METRO",
- },
- {
- make: "GEO",
- model: "STORM",
- },
- {
- make: "GEO",
- model: "TRACKER",
- },
- {
- make: "GMC",
- model: "1500",
- },
- {
- make: "GMC",
- model: "2500 HD",
- },
- {
- make: "GMC",
- model: "3500",
- },
- {
- make: "GMC",
- model: "4000",
- },
- {
- make: "GMC",
- model: "4500HD",
- },
- {
- make: "GMC",
- model: "ACADIA",
- },
- {
- make: "GMC",
- model: "C1500",
- },
- {
- make: "GMC",
- model: "C2500",
- },
- {
- make: "GMC",
- model: "C4500",
- },
- {
- make: "GMC",
- model: "CANYON",
- },
- {
- make: "GMC",
- model: "CARGO",
- },
- {
- make: "GMC",
- model: "DENALI HD",
- },
- {
- make: "GMC",
- model: "ENVOY",
- },
- {
- make: "GMC",
- model: "G2500 VANDURA",
- },
- {
- make: "GMC",
- model: "G35 SAVANNA",
- },
- {
- make: "GMC",
- model: "GEO",
- },
- {
- make: "GMC",
- model: "JIMMY",
- },
- {
- make: "GMC",
- model: "K 2500",
- },
- {
- make: "GMC",
- model: "K1500",
- },
- {
- make: "GMC",
- model: "K3500",
- },
- {
- make: "GMC",
- model: "RALLY",
- },
- {
- make: "GMC",
- model: "S15",
- },
- {
- make: "GMC",
- model: "S1500",
- },
- {
- make: "GMC",
- model: "SAFARI",
- },
- {
- make: "GMC",
- model: "SAVANA",
- },
- {
- make: "GMC",
- model: "SAVANA 3500",
- },
- {
- make: "GMC",
- model: "SIERRA",
- },
- {
- make: "GMC",
- model: "SIERRA 1500",
- },
- {
- make: "GMC",
- model: "SIERRA 2500",
- },
- {
- make: "GMC",
- model: "SIERRA 2500 HD",
- },
- {
- make: "GMC",
- model: "SIERRA 3500",
- },
- {
- make: "GMC",
- model: "SIERRA 3500, DENALI",
- },
- {
- make: "GMC",
- model: "SIERRA K1500",
- },
- {
- make: "GMC",
- model: "SLX",
- },
- {
- make: "GMC",
- model: "SONOMA",
- },
- {
- make: "GMC",
- model: "T7500",
- },
- {
- make: "GMC",
- model: "TERRAIN",
- },
- {
- make: "GMC",
- model: "TOP KICK",
- },
- {
- make: "GMC",
- model: "TOP KICK 6500",
- },
- {
- make: "GMC",
- model: "TOP KICK C4500",
- },
- {
- make: "GMC",
- model: "TRACKER",
- },
- {
- make: "GMC",
- model: "UTILIMASTER CUBE VAN",
- },
- {
- make: "GMC",
- model: "V15",
- },
- {
- make: "GMC",
- model: "VANDURA",
- },
- {
- make: "GMC",
- model: "VIXEN",
- },
- {
- make: "GMC",
- model: "W4500",
- },
- {
- make: "GMC",
- model: "W550",
- },
- {
- make: "GMC",
- model: "W5500",
- },
- {
- make: "GMC",
- model: "YUKON",
- },
- {
- make: "GOLF",
- model: "SPORT WAGON",
- },
- {
- make: "HINO",
- model: "268",
- },
- {
- make: "HINO",
- model: "338",
- },
- {
- make: "HONDA",
- model: "ACCORD",
- },
- {
- make: "HONDA",
- model: "CIVIC",
- },
- {
- make: "HONDA",
- model: "CIVIC HYBRID",
- },
- {
- make: "HONDA",
- model: "CRV",
- },
- {
- make: "HONDA",
- model: "CRX",
- },
- {
- make: "HONDA",
- model: "CR-Z",
- },
- {
- make: "HONDA",
- model: "DEL SOL",
- },
- {
- make: "HONDA",
- model: "ELEMENT",
- },
- {
- make: "HONDA",
- model: "FIT",
- },
- {
- make: "HONDA",
- model: "HR V",
- },
- {
- make: "HONDA",
- model: "INSIGHT",
- },
- {
- make: "HONDA",
- model: "ODYSSEY",
- },
- {
- make: "HONDA",
- model: "PASSPORT",
- },
- {
- make: "HONDA",
- model: "PILOT",
- },
- {
- make: "HONDA",
- model: "PRELUDE",
- },
- {
- make: "HONDA",
- model: "RIDGELINE",
- },
- {
- make: "HONDA",
- model: "S2000",
- },
- {
- make: "HUMMER",
- model: "H2",
- },
- {
- make: "HUMMER",
- model: "H3",
- },
- {
- make: "HYUNDAI",
- model: "ACCENT",
- },
- {
- make: "HYUNDAI",
- model: "AZERA",
- },
- {
- make: "HYUNDAI",
- model: "ELANTRA",
- },
- {
- make: "HYUNDAI",
- model: "ENTOURAGE",
- },
- {
- make: "HYUNDAI",
- model: "GENESIS",
- },
- {
- make: "HYUNDAI",
- model: "IONIQ",
- },
- {
- make: "HYUNDAI",
- model: "KONA",
- },
- {
- make: "HYUNDAI",
- model: "SANTA FE",
- },
- {
- make: "HYUNDAI",
- model: "SANTA FE SPORT",
- },
- {
- make: "HYUNDAI",
- model: "SCOUPE",
- },
- {
- make: "HYUNDAI",
- model: "SONATA",
- },
- {
- make: "HYUNDAI",
- model: "TIBURON",
- },
- {
- make: "HYUNDAI",
- model: "TOURING",
- },
- {
- make: "HYUNDAI",
- model: "TUCSON",
- },
- {
- make: "HYUNDAI",
- model: "VELOSTER",
- },
- {
- make: "HYUNDAI",
- model: "VENUE",
- },
- {
- make: "HYUNDAI",
- model: "VERA CRUZ",
- },
- {
- make: "HYUNDAI",
- model: "XG350",
- },
- {
- make: "HYUNDAI",
- model: "XG7",
- },
- {
- make: "INFINITI",
- model: "DURASTAR",
- },
- {
- make: "INFINITI",
- model: "EX35",
- },
- {
- make: "INFINITI",
- model: "FX35",
- },
- {
- make: "INFINITI",
- model: "FX45",
- },
- {
- make: "INFINITI",
- model: "FX50",
- },
- {
- make: "INFINITI",
- model: "G20",
- },
- {
- make: "INFINITI",
- model: "G35",
- },
- {
- make: "INFINITI",
- model: "G35X",
- },
- {
- make: "INFINITI",
- model: "G37",
- },
- {
- make: "INFINITI",
- model: "G37X",
- },
- {
- make: "INFINITI",
- model: "i30",
- },
- {
- make: "INFINITI",
- model: "I35",
- },
- {
- make: "INFINITI",
- model: "J30",
- },
- {
- make: "INFINITI",
- model: "JX35",
- },
- {
- make: "INFINITI",
- model: "L30",
- },
- {
- make: "INFINITI",
- model: "Q35",
- },
- {
- make: "INFINITI",
- model: "Q45",
- },
- {
- make: "INFINITI",
- model: "Q50",
- },
- {
- make: "INFINITI",
- model: "Q60",
- },
- {
- make: "INFINITI",
- model: "QX4",
- },
- {
- make: "INFINITI",
- model: "QX50",
- },
- {
- make: "INFINITI",
- model: "QX56",
- },
- {
- make: "INFINITI",
- model: "QX60",
- },
- {
- make: "ISUZU",
- model: "BIGHORN",
- },
- {
- make: "ISUZU",
- model: "CAB OVER",
- },
- {
- make: "ISUZU",
- model: "HOMBRE",
- },
- {
- make: "ISUZU",
- model: "NPR",
- },
- {
- make: "ISUZU",
- model: "NPR - HD",
- },
- {
- make: "ISUZU",
- model: "NRR",
- },
- {
- make: "ISUZU",
- model: "NRR - CAB OVER",
- },
- {
- make: "ISUZU",
- model: "RODEO",
- },
- {
- make: "ISUZU",
- model: "TROOPER",
- },
- {
- make: "JAGUAR",
- model: "F-PACE",
- },
- {
- make: "JAGUAR",
- model: "GATOR 850D",
- },
- {
- make: "JAGUAR",
- model: "IPACE",
- },
- {
- make: "JAGUAR",
- model: "S TYPE",
- },
- {
- make: "JAGUAR",
- model: "VANDEN PLAS",
- },
- {
- make: "JAGUAR",
- model: "XJ1",
- },
- {
- make: "JAGUAR",
- model: "XJ6",
- },
- {
- make: "JAGUAR",
- model: "XJ8",
- },
- {
- make: "JAGUAR",
- model: "XJS",
- },
- {
- make: "JAGUAR",
- model: "XK8",
- },
- {
- make: "JAGUAR",
- model: "X-TYPE",
- },
- {
- make: "JEEP",
- model: "CHEROKEE",
- },
- {
- make: "JEEP",
- model: "CJ",
- },
- {
- make: "JEEP",
- model: "CJ7",
- },
- {
- make: "JEEP",
- model: "COMMANCHE",
- },
- {
- make: "JEEP",
- model: "COMMANDER",
- },
- {
- make: "JEEP",
- model: "COMPASS",
- },
- {
- make: "JEEP",
- model: "CP",
- },
- {
- make: "JEEP",
- model: "GRAND CHEROKEE",
- },
- {
- make: "JEEP",
- model: "GRAND WAGONEER",
- },
- {
- make: "JEEP",
- model: "JK",
- },
- {
- make: "JEEP",
- model: "LIBERTY",
- },
- {
- make: "JEEP",
- model: "PATRIOT",
- },
- {
- make: "JEEP",
- model: "PT",
- },
- {
- make: "JEEP",
- model: "RENEGADE",
- },
- {
- make: "JEEP",
- model: "RUBICON",
- },
- {
- make: "JEEP",
- model: "TJ",
- },
- {
- make: "JEEP",
- model: "TJ SPORT",
- },
- {
- make: "JEEP",
- model: "WRANGLER",
- },
- {
- make: "JEEP",
- model: "YJ",
- },
- {
- make: "KIA",
- model: "CADENZA",
- },
- {
- make: "KIA",
- model: "CARNIVAL",
- },
- {
- make: "KIA",
- model: "FORTE",
- },
- {
- make: "KIA",
- model: "FORTE 5",
- },
- {
- make: "KIA",
- model: "MAGENTIS",
- },
- {
- make: "KIA",
- model: "NIRO",
- },
- {
- make: "KIA",
- model: "OPTIMA",
- },
- {
- make: "KIA",
- model: "RIO",
- },
- {
- make: "KIA",
- model: "RIO 5",
- },
- {
- make: "KIA",
- model: "RONDO",
- },
- {
- make: "KIA",
- model: "RX-V",
- },
- {
- make: "KIA",
- model: "SEDONA",
- },
- {
- make: "KIA",
- model: "SELTO",
- },
- {
- make: "KIA",
- model: "SEPHIA",
- },
- {
- make: "KIA",
- model: "SORENTO",
- },
- {
- make: "KIA",
- model: "SOUL",
- },
- {
- make: "KIA",
- model: "SPECTRA",
- },
- {
- make: "KIA",
- model: "SPECTRA 5",
- },
- {
- make: "KIA",
- model: "SPORT",
- },
- {
- make: "KIA",
- model: "SPORTAGE",
- },
- {
- make: "KIA",
- model: "VAN",
- },
- {
- make: "LAND ROVER",
- model: "DISCOVERY SPORT",
- },
- {
- make: "LAND ROVER",
- model: "LR2",
- },
- {
- make: "LAND ROVER",
- model: "RANGE ROVER EVOQUE",
- },
- {
- make: "LAND ROVER",
- model: "RANGE ROVER SPORT",
- },
- {
- make: "LANDROVER",
- model: "40 SE",
- },
- {
- make: "LANDROVER",
- model: "46HSE",
- },
- {
- make: "LANDROVER",
- model: "DEFENDER",
- },
- {
- make: "LANDROVER",
- model: "DISCOVERY",
- },
- {
- make: "LANDROVER",
- model: "DISCOVERY II",
- },
- {
- make: "LANDROVER",
- model: "FREELANDER",
- },
- {
- make: "LANDROVER",
- model: "LR2",
- },
- {
- make: "LANDROVER",
- model: "RANGE ROVER",
- },
- {
- make: "LEXUS",
- model: "ES300",
- },
- {
- make: "LEXUS",
- model: "ES350",
- },
- {
- make: "LEXUS",
- model: "GS250",
- },
- {
- make: "LEXUS",
- model: "GS300",
- },
- {
- make: "LEXUS",
- model: "GS450",
- },
- {
- make: "LEXUS",
- model: "GX470",
- },
- {
- make: "LEXUS",
- model: "HS250",
- },
- {
- make: "LEXUS",
- model: "IS250",
- },
- {
- make: "LEXUS",
- model: "IS300",
- },
- {
- make: "LEXUS",
- model: "IX 330",
- },
- {
- make: "LEXUS",
- model: "LS400",
- },
- {
- make: "LEXUS",
- model: "LS430",
- },
- {
- make: "LEXUS",
- model: "LX450",
- },
- {
- make: "LEXUS",
- model: "LX470",
- },
- {
- make: "LEXUS",
- model: "NX200",
- },
- {
- make: "LEXUS",
- model: "RC F",
- },
- {
- make: "LEXUS",
- model: "RX 300",
- },
- {
- make: "LEXUS",
- model: "RX 330",
- },
- {
- make: "LEXUS",
- model: "RX 350",
- },
- {
- make: "LEXUS",
- model: "RX 400H",
- },
- {
- make: "LEXUS",
- model: "RX300",
- },
- {
- make: "LEXUS",
- model: "RX330",
- },
- {
- make: "LEXUS",
- model: "RX350",
- },
- {
- make: "LEXUS",
- model: "RX400",
- },
- {
- make: "LEXUS",
- model: "RX450H",
- },
- {
- make: "LEXUS",
- model: "SC430",
- },
- {
- make: "LEXUS",
- model: "SOARER",
- },
- {
- make: "LEXUS",
- model: "UX250",
- },
- {
- make: "LINCOLN",
- model: "AVIATOR",
- },
- {
- make: "LINCOLN",
- model: "CONTINENTAL",
- },
- {
- make: "LINCOLN",
- model: "LS",
- },
- {
- make: "LINCOLN",
- model: "MARK",
- },
- {
- make: "LINCOLN",
- model: "MARK 5",
- },
- {
- make: "LINCOLN",
- model: "MARK LT",
- },
- {
- make: "LINCOLN",
- model: "MKC",
- },
- {
- make: "LINCOLN",
- model: "MKS",
- },
- {
- make: "LINCOLN",
- model: "MKX",
- },
- {
- make: "LINCOLN",
- model: "MKZ",
- },
- {
- make: "LINCOLN",
- model: "NAVIGATOR",
- },
- {
- make: "LINCOLN",
- model: "PICKUP",
- },
- {
- make: "LINCOLN",
- model: "TOWN CAR",
- },
- {
- make: "LINCOLN",
- model: "ZEPHER",
- },
- {
- make: "Make",
- model: "Model",
- },
- {
- make: "MARK",
- model: "LT",
- },
- {
- make: "MASERATI",
- model: "GHIBLI",
- },
- {
- make: "MAZDA",
- model: "2",
- },
- {
- make: "MAZDA",
- model: "3",
- },
- {
- make: "MAZDA",
- model: "3 H/B",
- },
- {
- make: "MAZDA",
- model: "3 SPORT",
- },
- {
- make: "MAZDA",
- model: "323",
- },
- {
- make: "MAZDA",
- model: "3GS",
- },
- {
- make: "MAZDA",
- model: "3GT",
- },
- {
- make: "MAZDA",
- model: "5",
- },
- {
- make: "MAZDA",
- model: "6",
- },
- {
- make: "MAZDA",
- model: "626",
- },
- {
- make: "MAZDA",
- model: "626ES",
- },
- {
- make: "MAZDA",
- model: "929",
- },
- {
- make: "MAZDA",
- model: "B2000",
- },
- {
- make: "MAZDA",
- model: "B2200",
- },
- {
- make: "MAZDA",
- model: "B2220",
- },
- {
- make: "MAZDA",
- model: "B2300",
- },
- {
- make: "MAZDA",
- model: "B2500",
- },
- {
- make: "MAZDA",
- model: "B2600",
- },
- {
- make: "MAZDA",
- model: "B2600I",
- },
- {
- make: "MAZDA",
- model: "B3000",
- },
- {
- make: "MAZDA",
- model: "B4000",
- },
- {
- make: "MAZDA",
- model: "B-SERIES",
- },
- {
- make: "MAZDA",
- model: "CX 7",
- },
- {
- make: "MAZDA",
- model: "CX3",
- },
- {
- make: "MAZDA",
- model: "CX-3",
- },
- {
- make: "MAZDA",
- model: "CX5",
- },
- {
- make: "MAZDA",
- model: "CX-5",
- },
- {
- make: "MAZDA",
- model: "CX5 GT",
- },
- {
- make: "MAZDA",
- model: "CX9",
- },
- {
- make: "MAZDA",
- model: "CX-9",
- },
- {
- make: "MAZDA",
- model: "D",
- },
- {
- make: "MAZDA",
- model: "MAZDA 3",
- },
- {
- make: "MAZDA",
- model: "MAZDA 5",
- },
- {
- make: "MAZDA",
- model: "MAZDA 6",
- },
- {
- make: "MAZDA",
- model: "MIATA",
- },
- {
- make: "MAZDA",
- model: "MIATA GX",
- },
- {
- make: "MAZDA",
- model: "MILLENIA",
- },
- {
- make: "MAZDA",
- model: "MPV",
- },
- {
- make: "MAZDA",
- model: "MR 2",
- },
- {
- make: "MAZDA",
- model: "MX-3",
- },
- {
- make: "MAZDA",
- model: "MX-3 PRECIDIA",
- },
- {
- make: "MAZDA",
- model: "MX-5",
- },
- {
- make: "MAZDA",
- model: "MX-6",
- },
- {
- make: "MAZDA",
- model: "PRECIDIA",
- },
- {
- make: "MAZDA",
- model: "PROTEGE",
- },
- {
- make: "MAZDA",
- model: "PROTEGE 5",
- },
- {
- make: "MAZDA",
- model: "RX7",
- },
- {
- make: "MAZDA",
- model: "RX8",
- },
- {
- make: "MAZDA",
- model: "TRIBUTE",
- },
- {
- make: "MERCEDES-BENZ",
- model: "190E",
- },
- {
- make: "MERCEDES-BENZ",
- model: "240D",
- },
- {
- make: "MERCEDES-BENZ",
- model: "245 BCLASS",
- },
- {
- make: "MERCEDES-BENZ",
- model: "300",
- },
- {
- make: "MERCEDES-BENZ",
- model: "300SD",
- },
- {
- make: "MERCEDES-BENZ",
- model: "300SL",
- },
- {
- make: "MERCEDES-BENZ",
- model: "B200",
- },
- {
- make: "MERCEDES-BENZ",
- model: "B250",
- },
- {
- make: "MERCEDES-BENZ",
- model: "C220",
- },
- {
- make: "MERCEDES-BENZ",
- model: "C230",
- },
- {
- make: "MERCEDES-BENZ",
- model: "C230 KOMPRESSOR",
- },
- {
- make: "MERCEDES-BENZ",
- model: "C240",
- },
- {
- make: "MERCEDES-BENZ",
- model: "C300",
- },
- {
- make: "MERCEDES-BENZ",
- model: "C300W",
- },
- {
- make: "MERCEDES-BENZ",
- model: "C320",
- },
- {
- make: "MERCEDES-BENZ",
- model: "C350",
- },
- {
- make: "MERCEDES-BENZ",
- model: "C400",
- },
- {
- make: "MERCEDES-BENZ",
- model: "C43",
- },
- {
- make: "MERCEDES-BENZ",
- model: "C63",
- },
- {
- make: "MERCEDES-BENZ",
- model: "C63 AMG",
- },
- {
- make: "MERCEDES-BENZ",
- model: "CLA25",
- },
- {
- make: "MERCEDES-BENZ",
- model: "CLK",
- },
- {
- make: "MERCEDES-BENZ",
- model: "CLK230",
- },
- {
- make: "MERCEDES-BENZ",
- model: "CLK320",
- },
- {
- make: "MERCEDES-BENZ",
- model: "CLK350",
- },
- {
- make: "MERCEDES-BENZ",
- model: "CLK500",
- },
- {
- make: "MERCEDES-BENZ",
- model: "CLR350",
- },
- {
- make: "MERCEDES-BENZ",
- model: "COMPRESSOR",
- },
- {
- make: "MERCEDES-BENZ",
- model: "E300",
- },
- {
- make: "MERCEDES-BENZ",
- model: "E320",
- },
- {
- make: "MERCEDES-BENZ",
- model: "E400",
- },
- {
- make: "MERCEDES-BENZ",
- model: "E420",
- },
- {
- make: "MERCEDES-BENZ",
- model: "E500W",
- },
- {
- make: "MERCEDES-BENZ",
- model: "E550",
- },
- {
- make: "MERCEDES-BENZ",
- model: "GLA25",
- },
- {
- make: "MERCEDES-BENZ",
- model: "GLC30",
- },
- {
- make: "MERCEDES-BENZ",
- model: "GLE350",
- },
- {
- make: "MERCEDES-BENZ",
- model: "GLK",
- },
- {
- make: "MERCEDES-BENZ",
- model: "GLK25",
- },
- {
- make: "MERCEDES-BENZ",
- model: "GLK250",
- },
- {
- make: "MERCEDES-BENZ",
- model: "GLK35",
- },
- {
- make: "MERCEDES-BENZ",
- model: "GLK35",
- },
- {
- make: "MERCEDES-BENZ",
- model: "M1320",
- },
- {
- make: "MERCEDES-BENZ",
- model: "METRIS",
- },
- {
- make: "MERCEDES-BENZ",
- model: "MI320",
- },
- {
- make: "MERCEDES-BENZ",
- model: "MI350",
- },
- {
- make: "MERCEDES-BENZ",
- model: "MI500",
- },
- {
- make: "MERCEDES-BENZ",
- model: "ML350",
- },
- {
- make: "MERCEDES-BENZ",
- model: "ML400",
- },
- {
- make: "MERCEDES-BENZ",
- model: "ML430",
- },
- {
- make: "MERCEDES-BENZ",
- model: "ML55",
- },
- {
- make: "MERCEDES-BENZ",
- model: "ML63",
- },
- {
- make: "MERCEDES-BENZ",
- model: "R320",
- },
- {
- make: "MERCEDES-BENZ",
- model: "S155",
- },
- {
- make: "MERCEDES-BENZ",
- model: "S450V",
- },
- {
- make: "MERCEDES-BENZ",
- model: "SL500",
- },
- {
- make: "MERCEDES-BENZ",
- model: "SLK230",
- },
- {
- make: "MERCEDES-BENZ",
- model: "SLK350",
- },
- {
- make: "MERCEDES-BENZ",
- model: "SPRINTER",
- },
- {
- make: "MERCEDES-BENZ",
- model: "SPRINTER VAN",
- },
- {
- make: "MERCURY",
- model: "COMET",
- },
- {
- make: "MERCURY",
- model: "COUGAR",
- },
- {
- make: "MERCURY",
- model: "GRAND MARQUIS",
- },
- {
- make: "MERCURY",
- model: "MARQUIS",
- },
- {
- make: "MERCURY",
- model: "MURADER",
- },
- {
- make: "MERCURY",
- model: "MYSTIQUE",
- },
- {
- make: "MERCURY",
- model: "SABLE",
- },
- {
- make: "MERCURY",
- model: "TOPAZ",
- },
- {
- make: "MERCURY",
- model: "VILLAGER",
- },
- {
- make: "MINI",
- model: "COOPER",
- },
- {
- make: "MINI",
- model: "COOPER CLUBMAN",
- },
- {
- make: "MINI",
- model: "COOPER COUNTRYMAN",
- },
- {
- make: "MINI",
- model: "COOPER S",
- },
- {
- make: "MITSUBISHI",
- model: "DELICA",
- },
- {
- make: "MITSUBISHI",
- model: "ECLIPSE",
- },
- {
- make: "MITSUBISHI",
- model: "ECLIPSE CROSS",
- },
- {
- make: "MITSUBISHI",
- model: "ENDVR",
- },
- {
- make: "MITSUBISHI",
- model: "GALANT",
- },
- {
- make: "MITSUBISHI",
- model: "LANCER",
- },
- {
- make: "MITSUBISHI",
- model: "LANCER EVOLUTION",
- },
- {
- make: "MITSUBISHI",
- model: "MIRAGE",
- },
- {
- make: "MITSUBISHI",
- model: "MONTERO",
- },
- {
- make: "MITSUBISHI",
- model: "OUTLANDER",
- },
- {
- make: "MITSUBISHI",
- model: "PJERO",
- },
- {
- make: "MITSUBISHI",
- model: "RVR",
- },
- {
- make: "MITSUBISHI",
- model: "SPYDER",
- },
- {
- make: "NISSAN",
- model: "200",
- },
- {
- make: "NISSAN",
- model: "200SX",
- },
- {
- make: "NISSAN",
- model: "240SX",
- },
- {
- make: "NISSAN",
- model: "240Z",
- },
- {
- make: "NISSAN",
- model: "2500 VAN",
- },
- {
- make: "NISSAN",
- model: "280",
- },
- {
- make: "NISSAN",
- model: "300ZX",
- },
- {
- make: "NISSAN",
- model: "350Z",
- },
- {
- make: "NISSAN",
- model: "370Z",
- },
- {
- make: "NISSAN",
- model: "ALTIMA",
- },
- {
- make: "NISSAN",
- model: "ARMADA",
- },
- {
- make: "NISSAN",
- model: "AXXESS",
- },
- {
- make: "NISSAN",
- model: "CUBE",
- },
- {
- make: "NISSAN",
- model: "D21",
- },
- {
- make: "NISSAN",
- model: "FIGARO",
- },
- {
- make: "NISSAN",
- model: "FRONTIER",
- },
- {
- make: "NISSAN",
- model: "HALFTON DLX",
- },
- {
- make: "NISSAN",
- model: "JUKE",
- },
- {
- make: "NISSAN",
- model: "KICKS",
- },
- {
- make: "NISSAN",
- model: "LEAF",
- },
- {
- make: "NISSAN",
- model: "MAXIMA",
- },
- {
- make: "NISSAN",
- model: "MICRA",
- },
- {
- make: "NISSAN",
- model: "MURANO",
- },
- {
- make: "NISSAN",
- model: "NV200",
- },
- {
- make: "NISSAN",
- model: "NV250",
- },
- {
- make: "NISSAN",
- model: "NV2500",
- },
- {
- make: "NISSAN",
- model: "PATHFINDER",
- },
- {
- make: "NISSAN",
- model: "PULSAR",
- },
- {
- make: "NISSAN",
- model: "QASHQAI",
- },
- {
- make: "NISSAN",
- model: "QSHQI",
- },
- {
- make: "NISSAN",
- model: "QUEST",
- },
- {
- make: "NISSAN",
- model: "ROGUE",
- },
- {
- make: "NISSAN",
- model: "SENTRA",
- },
- {
- make: "NISSAN",
- model: "SILVIA",
- },
- {
- make: "NISSAN",
- model: "SKYLINE",
- },
- {
- make: "NISSAN",
- model: "SKYLINE GTR",
- },
- {
- make: "NISSAN",
- model: "TERRANO",
- },
- {
- make: "NISSAN",
- model: "TITAN",
- },
- {
- make: "NISSAN",
- model: "TRANO - PATHFINDER",
- },
- {
- make: "NISSAN",
- model: "VERS",
- },
- {
- make: "NISSAN",
- model: "VERSA",
- },
- {
- make: "NISSAN",
- model: "X-TERRA",
- },
- {
- make: "NISSAN",
- model: "X-TRAIL",
- },
- {
- make: "OLDSMOBILE",
- model: "ACHIEVA",
- },
- {
- make: "OLDSMOBILE",
- model: "ALERO",
- },
- {
- make: "OLDSMOBILE",
- model: "AURORA",
- },
- {
- make: "OLDSMOBILE",
- model: "BRAVADO",
- },
- {
- make: "OLDSMOBILE",
- model: "CUTLASS",
- },
- {
- make: "OLDSMOBILE",
- model: "DELTA 88",
- },
- {
- make: "OLDSMOBILE",
- model: "DELTA 88 ROYALE BROUGHAM",
- },
- {
- make: "OLDSMOBILE",
- model: "INTRIGUE",
- },
- {
- make: "OLDSMOBILE",
- model: "NINETY EIGHT",
- },
- {
- make: "OLDSMOBILE",
- model: "OMEGA",
- },
- {
- make: "OLDSMOBILE",
- model: "REGENCY",
- },
- {
- make: "OLDSMOBILE",
- model: "SILHOUETTE",
- },
- {
- make: "OLDSMOBILE",
- model: "TORONADO",
- },
- {
- make: "PLYMOUTH",
- model: "ACCLAIM",
- },
- {
- make: "PLYMOUTH",
- model: "BARACUDA",
- },
- {
- make: "PLYMOUTH",
- model: "BREEZE",
- },
- {
- make: "PLYMOUTH",
- model: "CARAVAN",
- },
- {
- make: "PLYMOUTH",
- model: "GR.VOYAGER",
- },
- {
- make: "PLYMOUTH",
- model: "NEON",
- },
- {
- make: "PLYMOUTH",
- model: "RELIANT",
- },
- {
- make: "PLYMOUTH",
- model: "SUNDANCE",
- },
- {
- make: "PLYMOUTH",
- model: "VALANT",
- },
- {
- make: "PLYMOUTH",
- model: "VOYAGER",
- },
- {
- make: "POLARIS",
- model: "570 CREW",
- },
- {
- make: "POLARIS",
- model: "GENERAL 2+2",
- },
- {
- make: "PONTIAC",
- model: "ACADIAN",
- },
- {
- make: "PONTIAC",
- model: "AZTEC",
- },
- {
- make: "PONTIAC",
- model: "BEAUMONT",
- },
- {
- make: "PONTIAC",
- model: "BONNEVILLE",
- },
- {
- make: "PONTIAC",
- model: "FIERO",
- },
- {
- make: "PONTIAC",
- model: "FIREBIRD",
- },
- {
- make: "PONTIAC",
- model: "FIREFLY",
- },
- {
- make: "PONTIAC",
- model: "G3",
- },
- {
- make: "PONTIAC",
- model: "G5",
- },
- {
- make: "PONTIAC",
- model: "G6",
- },
- {
- make: "PONTIAC",
- model: "G8",
- },
- {
- make: "PONTIAC",
- model: "GRAND AM",
- },
- {
- make: "PONTIAC",
- model: "GRAND PRIX",
- },
- {
- make: "PONTIAC",
- model: "GTO",
- },
- {
- make: "PONTIAC",
- model: "MONTANA",
- },
- {
- make: "PONTIAC",
- model: "PARRISSIEN",
- },
- {
- make: "PONTIAC",
- model: "PURSUIT",
- },
- {
- make: "PONTIAC",
- model: "SOLSTICE",
- },
- {
- make: "PONTIAC",
- model: "SUNBIRD",
- },
- {
- make: "PONTIAC",
- model: "SUNFIRE",
- },
- {
- make: "PONTIAC",
- model: "SUNRUNNER",
- },
- {
- make: "PONTIAC",
- model: "TEMPEST",
- },
- {
- make: "PONTIAC",
- model: "TORRENT",
- },
- {
- make: "PONTIAC",
- model: "TRANS-AM",
- },
- {
- make: "PONTIAC",
- model: "TRANSPORT",
- },
- {
- make: "PONTIAC",
- model: "VIBE",
- },
- {
- make: "PONTIAC",
- model: "WAVE",
- },
- {
- make: "PORSCHE",
- model: "911",
- },
- {
- make: "PORSCHE",
- model: "928",
- },
- {
- make: "PORSCHE",
- model: "944",
- },
- {
- make: "PORSCHE",
- model: "944 TURBO",
- },
- {
- make: "PORSCHE",
- model: "BOXSTER",
- },
- {
- make: "PORSCHE",
- model: "CAYENNE",
- },
- {
- make: "RANGE ROVER",
- model: "46SHE",
- },
- {
- make: "RANGE ROVER",
- model: "PROMA",
- },
- {
- make: "RANGE ROVER",
- model: "RANGE",
- },
- {
- make: "SAAB",
- model: "9",
- },
- {
- make: "SAAB",
- model: "900S",
- },
- {
- make: "SAAB",
- model: "9-2X",
- },
- {
- make: "SAAB",
- model: "9-3",
- },
- {
- make: "SAAB",
- model: "93 AREO",
- },
- {
- make: "SAAB",
- model: "9-5",
- },
- {
- make: "SATURN",
- model: "ASTRA",
- },
- {
- make: "SATURN",
- model: "AURA",
- },
- {
- make: "SATURN",
- model: "ION",
- },
- {
- make: "SATURN",
- model: "L100",
- },
- {
- make: "SATURN",
- model: "L200",
- },
- {
- make: "SATURN",
- model: "LS1",
- },
- {
- make: "SATURN",
- model: "LS2",
- },
- {
- make: "SATURN",
- model: "OUTLOOK",
- },
- {
- make: "SATURN",
- model: "RELAY",
- },
- {
- make: "SATURN",
- model: "S SERIES",
- },
- {
- make: "SATURN",
- model: "S11",
- },
- {
- make: "SATURN",
- model: "SC1",
- },
- {
- make: "SATURN",
- model: "SKY",
- },
- {
- make: "SATURN",
- model: "SL1",
- },
- {
- make: "SATURN",
- model: "SL2",
- },
- {
- make: "SATURN",
- model: "SW1",
- },
- {
- make: "SATURN",
- model: "SW2",
- },
- {
- make: "SATURN",
- model: "VUE",
- },
- {
- make: "SATURN",
- model: "WGN",
- },
- {
- make: "SCION",
- model: "FR-S",
- },
- {
- make: "SCION",
- model: "IM",
- },
- {
- make: "SCION",
- model: "SXB",
- },
- {
- make: "SCION",
- model: "TC",
- },
- {
- make: "SCION",
- model: "XB",
- },
- {
- make: "SCION",
- model: "XD",
- },
- {
- make: "SMART",
- model: "FORTWO",
- },
- {
- make: "SUBARU",
- model: "ASENT",
- },
- {
- make: "SUBARU",
- model: "B9 TRIBECA",
- },
- {
- make: "SUBARU",
- model: "BAJA",
- },
- {
- make: "SUBARU",
- model: "BRAT",
- },
- {
- make: "SUBARU",
- model: "BRZ",
- },
- {
- make: "SUBARU",
- model: "CROSSTREK",
- },
- {
- make: "SUBARU",
- model: "DOMINGO",
- },
- {
- make: "SUBARU",
- model: "DOMNGO",
- },
- {
- make: "SUBARU",
- model: "FORESTER",
- },
- {
- make: "SUBARU",
- model: "GL",
- },
- {
- make: "SUBARU",
- model: "IMPREZA",
- },
- {
- make: "SUBARU",
- model: "IMPREZA STI",
- },
- {
- make: "SUBARU",
- model: "JUSTY",
- },
- {
- make: "SUBARU",
- model: "LEGACY",
- },
- {
- make: "SUBARU",
- model: "LOYALE",
- },
- {
- make: "SUBARU",
- model: "OUTBACK",
- },
- {
- make: "SUBARU",
- model: "SVX",
- },
- {
- make: "SUBARU",
- model: "TRIBECA",
- },
- {
- make: "SUBARU",
- model: "WRX",
- },
- {
- make: "SUBARU",
- model: "WRX STI",
- },
- {
- make: "SUBARU",
- model: "XV",
- },
- {
- make: "SUZUKI",
- model: "AERIO",
- },
- {
- make: "SUZUKI",
- model: "CARRY",
- },
- {
- make: "SUZUKI",
- model: "ESTEEM",
- },
- {
- make: "SUZUKI",
- model: "GRAND VITARA",
- },
- {
- make: "SUZUKI",
- model: "MINI-TRUCK",
- },
- {
- make: "SUZUKI",
- model: "SAMURAI",
- },
- {
- make: "SUZUKI",
- model: "SIDEKICK",
- },
- {
- make: "SUZUKI",
- model: "SWIFT",
- },
- {
- make: "SUZUKI",
- model: "SX4",
- },
- {
- make: "SUZUKI",
- model: "VITARA",
- },
- {
- make: "SUZUKI",
- model: "XL7",
- },
- {
- make: "TESLA",
- model: "MODEL 3",
- },
- {
- make: "TOYOTA",
- model: " PRIUS C",
- },
- {
- make: "TOYOTA",
- model: "4 RUNNER",
- },
- {
- make: "TOYOTA",
- model: "4X4",
- },
- {
- make: "TOYOTA",
- model: "ALPHARD",
- },
- {
- make: "TOYOTA",
- model: "ARISTO",
- },
- {
- make: "TOYOTA",
- model: "AVALON",
- },
- {
- make: "TOYOTA",
- model: "CALDI",
- },
- {
- make: "TOYOTA",
- model: "CALDINA",
- },
- {
- make: "TOYOTA",
- model: "CAMRY",
- },
- {
- make: "TOYOTA",
- model: "CANOPY",
- },
- {
- make: "TOYOTA",
- model: "CELICA",
- },
- {
- make: "TOYOTA",
- model: "CELSLOR",
- },
- {
- make: "TOYOTA",
- model: "CHASE",
- },
- {
- make: "TOYOTA",
- model: "CH-R",
- },
- {
- make: "TOYOTA",
- model: "COROLLA",
- },
- {
- make: "TOYOTA",
- model: "COROLLA CE",
- },
- {
- make: "TOYOTA",
- model: "COROLLA.HYBRID",
- },
- {
- make: "TOYOTA",
- model: "CRESSIDA",
- },
- {
- make: "TOYOTA",
- model: "DELICA",
- },
- {
- make: "TOYOTA",
- model: "ECHO",
- },
- {
- make: "TOYOTA",
- model: "FJ",
- },
- {
- make: "TOYOTA",
- model: "HIGHLANDER",
- },
- {
- make: "TOYOTA",
- model: "LAND CRUISER",
- },
- {
- make: "TOYOTA",
- model: "MATRIX",
- },
- {
- make: "TOYOTA",
- model: "MR2",
- },
- {
- make: "TOYOTA",
- model: "PASEO",
- },
- {
- make: "TOYOTA",
- model: "PICK UP",
- },
- {
- make: "TOYOTA",
- model: "PRADA",
- },
- {
- make: "TOYOTA",
- model: "PREVIA",
- },
- {
- make: "TOYOTA",
- model: "PRIUS",
- },
- {
- make: "TOYOTA",
- model: "PRIUS HYBIRD",
- },
- {
- make: "TOYOTA",
- model: "PRIUS V",
- },
- {
- make: "TOYOTA",
- model: "RAV4",
- },
- {
- make: "TOYOTA",
- model: "SCION",
- },
- {
- make: "TOYOTA",
- model: "SEQUOIA",
- },
- {
- make: "TOYOTA",
- model: "SIENNA",
- },
- {
- make: "TOYOTA",
- model: "SOLARA",
- },
- {
- make: "TOYOTA",
- model: "SORER",
- },
- {
- make: "TOYOTA",
- model: "SP & SP",
- },
- {
- make: "TOYOTA",
- model: "SUPRA",
- },
- {
- make: "TOYOTA",
- model: "SURF",
- },
- {
- make: "TOYOTA",
- model: "TACOMA",
- },
- {
- make: "TOYOTA",
- model: "TERCEL",
- },
- {
- make: "TOYOTA",
- model: "TUNDRA",
- },
- {
- make: "TOYOTA",
- model: "VENZA",
- },
- {
- make: "TOYOTA",
- model: "YARIS",
- },
- {
- make: "TRIUMPH",
- model: "TR3",
- },
- {
- make: "VOLKSWAGEN",
- model: "ATLAS",
- },
- {
- make: "VOLKSWAGEN",
- model: "BEETLE",
- },
- {
- make: "VOLKSWAGEN",
- model: "CABRIOLET",
- },
- {
- make: "VOLKSWAGEN",
- model: "CC",
- },
- {
- make: "VOLKSWAGEN",
- model: "CORRADO",
- },
- {
- make: "VOLKSWAGEN",
- model: "DUNEBUGGY",
- },
- {
- make: "VOLKSWAGEN",
- model: "EOS",
- },
- {
- make: "VOLKSWAGEN",
- model: "EUROVAN",
- },
- {
- make: "VOLKSWAGEN",
- model: "GOLF",
- },
- {
- make: "VOLKSWAGEN",
- model: "GOLF CABRIOLET",
- },
- {
- make: "VOLKSWAGEN",
- model: "GOLF CITY",
- },
- {
- make: "VOLKSWAGEN",
- model: "GOLF GTI",
- },
- {
- make: "VOLKSWAGEN",
- model: "GOLF SPORT WAGEN",
- },
- {
- make: "VOLKSWAGEN",
- model: "GTI",
- },
- {
- make: "VOLKSWAGEN",
- model: "JETTA",
- },
- {
- make: "VOLKSWAGEN",
- model: "JETTA TDI",
- },
- {
- make: "VOLKSWAGEN",
- model: "KIT CAR",
- },
- {
- make: "VOLKSWAGEN",
- model: "PASSAT",
- },
- {
- make: "VOLKSWAGEN",
- model: "R32",
- },
- {
- make: "VOLKSWAGEN",
- model: "RABBIT",
- },
- {
- make: "VOLKSWAGEN",
- model: "ROUTAN",
- },
- {
- make: "VOLKSWAGEN",
- model: "TIGUAN",
- },
- {
- make: "VOLKSWAGEN",
- model: "TOUAREG",
- },
- {
- make: "VOLKSWAGEN",
- model: "TRANSPORTER VAN",
- },
- {
- make: "VOLKSWAGEN",
- model: "VANAGON",
- },
- {
- make: "VOLKSWAGEN",
- model: "WESTFALIA",
- },
- {
- make: "VOLKSWAGEN",
- model: "WINNEBAGO",
- },
- {
- make: "VOLVO",
- model: "240",
- },
- {
- make: "VOLVO",
- model: "244",
- },
- {
- make: "VOLVO",
- model: "740",
- },
- {
- make: "VOLVO",
- model: "760",
- },
- {
- make: "VOLVO",
- model: "850",
- },
- {
- make: "VOLVO",
- model: "940",
- },
- {
- make: "VOLVO",
- model: "960",
- },
- {
- make: "VOLVO",
- model: "C30",
- },
- {
- make: "VOLVO",
- model: "C70",
- },
- {
- make: "VOLVO",
- model: "DL",
- },
- {
- make: "VOLVO",
- model: "GLE",
- },
- {
- make: "VOLVO",
- model: "GLT",
- },
- {
- make: "VOLVO",
- model: "GT",
- },
- {
- make: "VOLVO",
- model: "S40",
- },
- {
- make: "VOLVO",
- model: "S60",
- },
- {
- make: "VOLVO",
- model: "S70",
- },
- {
- make: "VOLVO",
- model: "S80",
- },
- {
- make: "VOLVO",
- model: "S90",
- },
- {
- make: "VOLVO",
- model: "V40",
- },
- {
- make: "VOLVO",
- model: "V50",
- },
- {
- make: "VOLVO",
- model: "V70",
- },
- {
- make: "VOLVO",
- model: "V70 - X/C",
- },
- {
- make: "VOLVO",
- model: "XC60",
- },
- {
- make: "VOLVO",
- model: "XC70",
- },
- {
- make: "VOLVO",
- model: "XC90",
- },
+ {
+ make: "ACURA",
+ model: "1.6 EL",
+ },
+ {
+ make: "ACURA",
+ model: "1.7 EL",
+ },
+ {
+ make: "ACURA",
+ model: "2.3 CL",
+ },
+ {
+ make: "ACURA",
+ model: "2.5TL",
+ },
+ {
+ make: "ACURA",
+ model: "3.2TL",
+ },
+ {
+ make: "ACURA",
+ model: "3.5RL",
+ },
+ {
+ make: "ACURA",
+ model: "CL",
+ },
+ {
+ make: "ACURA",
+ model: "CSX",
+ },
+ {
+ make: "ACURA",
+ model: "EL",
+ },
+ {
+ make: "ACURA",
+ model: "GSR",
+ },
+ {
+ make: "ACURA",
+ model: "ILX",
+ },
+ {
+ make: "ACURA",
+ model: "INTEGRA",
+ },
+ {
+ make: "ACURA",
+ model: "LEGEND",
+ },
+ {
+ make: "ACURA",
+ model: "MDX",
+ },
+ {
+ make: "ACURA",
+ model: "NSX",
+ },
+ {
+ make: "ACURA",
+ model: "RDX",
+ },
+ {
+ make: "ACURA",
+ model: "RSX",
+ },
+ {
+ make: "ACURA",
+ model: "TL",
+ },
+ {
+ make: "ACURA",
+ model: "TL-S",
+ },
+ {
+ make: "ACURA",
+ model: "TLX",
+ },
+ {
+ make: "ACURA",
+ model: "TSK 4",
+ },
+ {
+ make: "ACURA",
+ model: "TSX",
+ },
+ {
+ make: "ACURA",
+ model: "VIGOR",
+ },
+ {
+ make: "AMC",
+ model: "GENERAL",
+ },
+ {
+ make: "AMC",
+ model: "RAMBLER",
+ },
+ {
+ make: "ATLAS",
+ model: "CUB",
+ },
+ {
+ make: "AUDI",
+ model: "100",
+ },
+ {
+ make: "AUDI",
+ model: "A2",
+ },
+ {
+ make: "AUDI",
+ model: "A2 QUATTRO",
+ },
+ {
+ make: "AUDI",
+ model: "A3",
+ },
+ {
+ make: "AUDI",
+ model: "A4",
+ },
+ {
+ make: "AUDI",
+ model: "A4 QUATTRO",
+ },
+ {
+ make: "AUDI",
+ model: "A5",
+ },
+ {
+ make: "AUDI",
+ model: "A6",
+ },
+ {
+ make: "AUDI",
+ model: "Q3",
+ },
+ {
+ make: "AUDI",
+ model: "Q5",
+ },
+ {
+ make: "AUDI",
+ model: "Q7",
+ },
+ {
+ make: "AUDI",
+ model: "QUATTRO",
+ },
+ {
+ make: "AUDI",
+ model: "RS4",
+ },
+ {
+ make: "AUDI",
+ model: "S3",
+ },
+ {
+ make: "AUDI",
+ model: "S4",
+ },
+ {
+ make: "AUDI",
+ model: "S5",
+ },
+ {
+ make: "AUDI",
+ model: "S6",
+ },
+ {
+ make: "AUDI",
+ model: "TT",
+ },
+ {
+ make: "AUSTIN",
+ model: "HEALY",
+ },
+ {
+ make: "BMW",
+ model: "128I",
+ },
+ {
+ make: "BMW",
+ model: "135I",
+ },
+ {
+ make: "BMW",
+ model: "135IS",
+ },
+ {
+ make: "BMW",
+ model: "228I",
+ },
+ {
+ make: "BMW",
+ model: "3 SERIES",
+ },
+ {
+ make: "BMW",
+ model: "318",
+ },
+ {
+ make: "BMW",
+ model: "318 TI",
+ },
+ {
+ make: "BMW",
+ model: "318I",
+ },
+ {
+ make: "BMW",
+ model: "318IS",
+ },
+ {
+ make: "BMW",
+ model: "320CI",
+ },
+ {
+ make: "BMW",
+ model: "320I",
+ },
+ {
+ make: "BMW",
+ model: "323I",
+ },
+ {
+ make: "BMW",
+ model: "325",
+ },
+ {
+ make: "BMW",
+ model: "325CI",
+ },
+ {
+ make: "BMW",
+ model: "325E",
+ },
+ {
+ make: "BMW",
+ model: "325I",
+ },
+ {
+ make: "BMW",
+ model: "325IS",
+ },
+ {
+ make: "BMW",
+ model: "325XI",
+ },
+ {
+ make: "BMW",
+ model: "328CI",
+ },
+ {
+ make: "BMW",
+ model: "328D",
+ },
+ {
+ make: "BMW",
+ model: "328I",
+ },
+ {
+ make: "BMW",
+ model: "328XI",
+ },
+ {
+ make: "BMW",
+ model: "330CI",
+ },
+ {
+ make: "BMW",
+ model: "330I",
+ },
+ {
+ make: "BMW",
+ model: "330XI",
+ },
+ {
+ make: "BMW",
+ model: "335I",
+ },
+ {
+ make: "BMW",
+ model: "335XI",
+ },
+ {
+ make: "BMW",
+ model: "352I",
+ },
+ {
+ make: "BMW",
+ model: "428I",
+ },
+ {
+ make: "BMW",
+ model: "430I",
+ },
+ {
+ make: "BMW",
+ model: "435I",
+ },
+ {
+ make: "BMW",
+ model: "440I",
+ },
+ {
+ make: "BMW",
+ model: "520I",
+ },
+ {
+ make: "BMW",
+ model: "525I",
+ },
+ {
+ make: "BMW",
+ model: "528I",
+ },
+ {
+ make: "BMW",
+ model: "530",
+ },
+ {
+ make: "BMW",
+ model: "530I",
+ },
+ {
+ make: "BMW",
+ model: "530IA",
+ },
+ {
+ make: "BMW",
+ model: "530XI",
+ },
+ {
+ make: "BMW",
+ model: "535I",
+ },
+ {
+ make: "BMW",
+ model: "540I",
+ },
+ {
+ make: "BMW",
+ model: "640I",
+ },
+ {
+ make: "BMW",
+ model: "645CI",
+ },
+ {
+ make: "BMW",
+ model: "735",
+ },
+ {
+ make: "BMW",
+ model: "740I",
+ },
+ {
+ make: "BMW",
+ model: "745LI",
+ },
+ {
+ make: "BMW",
+ model: "750I",
+ },
+ {
+ make: "BMW",
+ model: "750LI",
+ },
+ {
+ make: "BMW",
+ model: "K-1200",
+ },
+ {
+ make: "BMW",
+ model: "M3",
+ },
+ {
+ make: "BMW",
+ model: "M5",
+ },
+ {
+ make: "BMW",
+ model: "X1",
+ },
+ {
+ make: "BMW",
+ model: "X3",
+ },
+ {
+ make: "BMW",
+ model: "X5",
+ },
+ {
+ make: "BMW",
+ model: "X6",
+ },
+ {
+ make: "BMW",
+ model: "Z3",
+ },
+ {
+ make: "BMW",
+ model: "Z4",
+ },
+ {
+ make: "BUICK",
+ model: "ALLURE",
+ },
+ {
+ make: "BUICK",
+ model: "CENTURY",
+ },
+ {
+ make: "BUICK",
+ model: "ENCLAVE",
+ },
+ {
+ make: "BUICK",
+ model: "ENCORE",
+ },
+ {
+ make: "BUICK",
+ model: "ENVISION",
+ },
+ {
+ make: "BUICK",
+ model: "INVICTA",
+ },
+ {
+ make: "BUICK",
+ model: "LACROSSE",
+ },
+ {
+ make: "BUICK",
+ model: "LESABRE",
+ },
+ {
+ make: "BUICK",
+ model: "LUCERNE",
+ },
+ {
+ make: "BUICK",
+ model: "PARK AVENUE",
+ },
+ {
+ make: "BUICK",
+ model: "REGAL",
+ },
+ {
+ make: "BUICK",
+ model: "RENDEZVOUS",
+ },
+ {
+ make: "BUICK",
+ model: "RIVIERA",
+ },
+ {
+ make: "BUICK",
+ model: "ROADMASTER",
+ },
+ {
+ make: "BUICK",
+ model: "SKYLARK",
+ },
+ {
+ make: "BUICK",
+ model: "SOMERSET",
+ },
+ {
+ make: "BUICK",
+ model: "SPECIAL",
+ },
+ {
+ make: "BUICK",
+ model: "TERRAZA",
+ },
+ {
+ make: "BUICK",
+ model: "VERANO",
+ },
+ {
+ make: "CADILLAC",
+ model: "ATS",
+ },
+ {
+ make: "CADILLAC",
+ model: "CATERA",
+ },
+ {
+ make: "CADILLAC",
+ model: "CTS",
+ },
+ {
+ make: "CADILLAC",
+ model: "DE VILLE",
+ },
+ {
+ make: "CADILLAC",
+ model: "DTS",
+ },
+ {
+ make: "CADILLAC",
+ model: "ELDORADO",
+ },
+ {
+ make: "CADILLAC",
+ model: "ESCLADE",
+ },
+ {
+ make: "CADILLAC",
+ model: "FLEETWOOD",
+ },
+ {
+ make: "CADILLAC",
+ model: "SEVILLE",
+ },
+ {
+ make: "CADILLAC",
+ model: "SRX",
+ },
+ {
+ make: "CADILLAC",
+ model: "STS",
+ },
+ {
+ make: "CADILLAC",
+ model: "XLR",
+ },
+ {
+ make: "CHEVROLET",
+ model: "1500",
+ },
+ {
+ make: "CHEVROLET",
+ model: "2500",
+ },
+ {
+ make: "CHEVROLET",
+ model: "2500HD",
+ },
+ {
+ make: "CHEVROLET",
+ model: "2WHDR",
+ },
+ {
+ make: "CHEVROLET",
+ model: "3500 EXPRESS VAN",
+ },
+ {
+ make: "CHEVROLET",
+ model: "3500 HD",
+ },
+ {
+ make: "CHEVROLET",
+ model: "ALER",
+ },
+ {
+ make: "CHEVROLET",
+ model: "ASTRO",
+ },
+ {
+ make: "CHEVROLET",
+ model: "AVALANCHE",
+ },
+ {
+ make: "CHEVROLET",
+ model: "AVEO",
+ },
+ {
+ make: "CHEVROLET",
+ model: "BEL AIR",
+ },
+ {
+ make: "CHEVROLET",
+ model: "BERETTA",
+ },
+ {
+ make: "CHEVROLET",
+ model: "BLAZER",
+ },
+ {
+ make: "CHEVROLET",
+ model: "BOLT",
+ },
+ {
+ make: "CHEVROLET",
+ model: "BOLT EV",
+ },
+ {
+ make: "CHEVROLET",
+ model: "C10",
+ },
+ {
+ make: "CHEVROLET",
+ model: "C20",
+ },
+ {
+ make: "CHEVROLET",
+ model: "C2500",
+ },
+ {
+ make: "CHEVROLET",
+ model: "C3500",
+ },
+ {
+ make: "CHEVROLET",
+ model: "CAMARO",
+ },
+ {
+ make: "CHEVROLET",
+ model: "CAPRICE",
+ },
+ {
+ make: "CHEVROLET",
+ model: "CAVALIER",
+ },
+ {
+ make: "CHEVROLET",
+ model: "CHEVELLE",
+ },
+ {
+ make: "CHEVROLET",
+ model: "CITY EXPRESS",
+ },
+ {
+ make: "CHEVROLET",
+ model: "COBALT",
+ },
+ {
+ make: "CHEVROLET",
+ model: "COLORADO",
+ },
+ {
+ make: "CHEVROLET",
+ model: "CORSICA",
+ },
+ {
+ make: "CHEVROLET",
+ model: "CORVETTE",
+ },
+ {
+ make: "CHEVROLET",
+ model: "CRUZE",
+ },
+ {
+ make: "CHEVROLET",
+ model: "EL CAMINO",
+ },
+ {
+ make: "CHEVROLET",
+ model: "EPICA",
+ },
+ {
+ make: "CHEVROLET",
+ model: "EQUINOX",
+ },
+ {
+ make: "CHEVROLET",
+ model: "EXPRESS",
+ },
+ {
+ make: "CHEVROLET",
+ model: "EXPRESS 1500",
+ },
+ {
+ make: "CHEVROLET",
+ model: "EXPRESS 2500",
+ },
+ {
+ make: "CHEVROLET",
+ model: "EXPRESS 3500",
+ },
+ {
+ make: "CHEVROLET",
+ model: "EXPRESS VAN",
+ },
+ {
+ make: "CHEVROLET",
+ model: "G1500",
+ },
+ {
+ make: "CHEVROLET",
+ model: "G2500",
+ },
+ {
+ make: "CHEVROLET",
+ model: "G30",
+ },
+ {
+ make: "CHEVROLET",
+ model: "G3500",
+ },
+ {
+ make: "CHEVROLET",
+ model: "G4500",
+ },
+ {
+ make: "CHEVROLET",
+ model: "GMT-400",
+ },
+ {
+ make: "CHEVROLET",
+ model: "HD 2500",
+ },
+ {
+ make: "CHEVROLET",
+ model: "HHR",
+ },
+ {
+ make: "CHEVROLET",
+ model: "IMPALA",
+ },
+ {
+ make: "CHEVROLET",
+ model: "K1500",
+ },
+ {
+ make: "CHEVROLET",
+ model: "K2500",
+ },
+ {
+ make: "CHEVROLET",
+ model: "K3500",
+ },
+ {
+ make: "CHEVROLET",
+ model: "K5500",
+ },
+ {
+ make: "CHEVROLET",
+ model: "LUMINA",
+ },
+ {
+ make: "CHEVROLET",
+ model: "MALIBU",
+ },
+ {
+ make: "CHEVROLET",
+ model: "MALIBU HYBRID",
+ },
+ {
+ make: "CHEVROLET",
+ model: "MONTE CARLO",
+ },
+ {
+ make: "CHEVROLET",
+ model: "NOMAD",
+ },
+ {
+ make: "CHEVROLET",
+ model: "NOVA",
+ },
+ {
+ make: "CHEVROLET",
+ model: "OPTRA",
+ },
+ {
+ make: "CHEVROLET",
+ model: "ORLANDO",
+ },
+ {
+ make: "CHEVROLET",
+ model: "P30",
+ },
+ {
+ make: "CHEVROLET",
+ model: "S10",
+ },
+ {
+ make: "CHEVROLET",
+ model: "S10 BLAZER",
+ },
+ {
+ make: "CHEVROLET",
+ model: "SAVANNA",
+ },
+ {
+ make: "CHEVROLET",
+ model: "SILVERADO",
+ },
+ {
+ make: "CHEVROLET",
+ model: "SILVERADO 2500 HD",
+ },
+ {
+ make: "CHEVROLET",
+ model: "SILVERADO 3500",
+ },
+ {
+ make: "CHEVROLET",
+ model: "SILVERADO 3500 HD",
+ },
+ {
+ make: "CHEVROLET",
+ model: "SONIC",
+ },
+ {
+ make: "CHEVROLET",
+ model: "SPARK",
+ },
+ {
+ make: "CHEVROLET",
+ model: "SPORT VAN G20",
+ },
+ {
+ make: "CHEVROLET",
+ model: "SPRINT",
+ },
+ {
+ make: "CHEVROLET",
+ model: "SUBURBAN",
+ },
+ {
+ make: "CHEVROLET",
+ model: "TAHOE",
+ },
+ {
+ make: "CHEVROLET",
+ model: "TRACKER",
+ },
+ {
+ make: "CHEVROLET",
+ model: "TRAILBLAZER",
+ },
+ {
+ make: "CHEVROLET",
+ model: "TRAVERSE",
+ },
+ {
+ make: "CHEVROLET",
+ model: "TRAX",
+ },
+ {
+ make: "CHEVROLET",
+ model: "TREX",
+ },
+ {
+ make: "CHEVROLET",
+ model: "UPLANDER",
+ },
+ {
+ make: "CHEVROLET",
+ model: "VENTURE",
+ },
+ {
+ make: "CHEVROLET",
+ model: "VOLT",
+ },
+ {
+ make: "CHEVROLET",
+ model: "Z24",
+ },
+ {
+ make: "CHEVROLET",
+ model: "Z28 IROC",
+ },
+ {
+ make: "CHRYSLER",
+ model: "200",
+ },
+ {
+ make: "CHRYSLER",
+ model: "300",
+ },
+ {
+ make: "CHRYSLER",
+ model: "300C",
+ },
+ {
+ make: "CHRYSLER",
+ model: "300M",
+ },
+ {
+ make: "CHRYSLER",
+ model: "5TH AVE",
+ },
+ {
+ make: "CHRYSLER",
+ model: "ASPEN",
+ },
+ {
+ make: "CHRYSLER",
+ model: "CIRRUS",
+ },
+ {
+ make: "CHRYSLER",
+ model: "CONCORDE",
+ },
+ {
+ make: "CHRYSLER",
+ model: "CROSSFIRE",
+ },
+ {
+ make: "CHRYSLER",
+ model: "DAYTONA",
+ },
+ {
+ make: "CHRYSLER",
+ model: "E CLASS",
+ },
+ {
+ make: "CHRYSLER",
+ model: "INTREPID",
+ },
+ {
+ make: "CHRYSLER",
+ model: "LEBARON",
+ },
+ {
+ make: "CHRYSLER",
+ model: "LHS",
+ },
+ {
+ make: "CHRYSLER",
+ model: "NEON",
+ },
+ {
+ make: "CHRYSLER",
+ model: "NEW YORKER",
+ },
+ {
+ make: "CHRYSLER",
+ model: "PACIFICA",
+ },
+ {
+ make: "CHRYSLER",
+ model: "PT CRUISER",
+ },
+ {
+ make: "CHRYSLER",
+ model: "SEBRING",
+ },
+ {
+ make: "CHRYSLER",
+ model: "TOWN & COUNTRY",
+ },
+ {
+ make: "DATSUN",
+ model: "PICK-UP",
+ },
+ {
+ make: "DODGE",
+ model: "1500",
+ },
+ {
+ make: "DODGE",
+ model: "250",
+ },
+ {
+ make: "DODGE",
+ model: "2500",
+ },
+ {
+ make: "DODGE",
+ model: "4500",
+ },
+ {
+ make: "DODGE",
+ model: "5500",
+ },
+ {
+ make: "DODGE",
+ model: "ARIES",
+ },
+ {
+ make: "DODGE",
+ model: "AVENGER",
+ },
+ {
+ make: "DODGE",
+ model: "B1500",
+ },
+ {
+ make: "DODGE",
+ model: "B200",
+ },
+ {
+ make: "DODGE",
+ model: "B250",
+ },
+ {
+ make: "DODGE",
+ model: "B350",
+ },
+ {
+ make: "DODGE",
+ model: "CALIBER",
+ },
+ {
+ make: "DODGE",
+ model: "CAMPERVAN",
+ },
+ {
+ make: "DODGE",
+ model: "CARAVAN",
+ },
+ {
+ make: "DODGE",
+ model: "CHALLENGER",
+ },
+ {
+ make: "DODGE",
+ model: "CHARGER",
+ },
+ {
+ make: "DODGE",
+ model: "COLT",
+ },
+ {
+ make: "DODGE",
+ model: "CORNET",
+ },
+ {
+ make: "DODGE",
+ model: "CV VAN",
+ },
+ {
+ make: "DODGE",
+ model: "D100",
+ },
+ {
+ make: "DODGE",
+ model: "D200",
+ },
+ {
+ make: "DODGE",
+ model: "D250",
+ },
+ {
+ make: "DODGE",
+ model: "D300",
+ },
+ {
+ make: "DODGE",
+ model: "D350",
+ },
+ {
+ make: "DODGE",
+ model: "DAKOTA",
+ },
+ {
+ make: "DODGE",
+ model: "DART",
+ },
+ {
+ make: "DODGE",
+ model: "DEMON",
+ },
+ {
+ make: "DODGE",
+ model: "DURANGO",
+ },
+ {
+ make: "DODGE",
+ model: "DYNASTY",
+ },
+ {
+ make: "DODGE",
+ model: "GRAND CARAVAN",
+ },
+ {
+ make: "DODGE",
+ model: "GRAND CARAVEN SE",
+ },
+ {
+ make: "DODGE",
+ model: "JOURNEY",
+ },
+ {
+ make: "DODGE",
+ model: "MAGNUM",
+ },
+ {
+ make: "DODGE",
+ model: "MOTORHOME",
+ },
+ {
+ make: "DODGE",
+ model: "NEON",
+ },
+ {
+ make: "DODGE",
+ model: "NITRO",
+ },
+ {
+ make: "DODGE",
+ model: "PRO MASTER",
+ },
+ {
+ make: "DODGE",
+ model: "PRO MASTER 3500",
+ },
+ {
+ make: "DODGE",
+ model: "RAM",
+ },
+ {
+ make: "DODGE",
+ model: "RAM 1500",
+ },
+ {
+ make: "DODGE",
+ model: "RAM 250",
+ },
+ {
+ make: "DODGE",
+ model: "RAM 2500",
+ },
+ {
+ make: "DODGE",
+ model: "RAM 3500",
+ },
+ {
+ make: "DODGE",
+ model: "RAM 5500",
+ },
+ {
+ make: "DODGE",
+ model: "RAM PRO MASTER",
+ },
+ {
+ make: "DODGE",
+ model: "RAM SRT10",
+ },
+ {
+ make: "DODGE",
+ model: "RAM VAN",
+ },
+ {
+ make: "DODGE",
+ model: "RAMPAGE",
+ },
+ {
+ make: "DODGE",
+ model: "SHADOW",
+ },
+ {
+ make: "DODGE",
+ model: "SPIRIT",
+ },
+ {
+ make: "DODGE",
+ model: "SPRINTER 3500",
+ },
+ {
+ make: "DODGE",
+ model: "SRT",
+ },
+ {
+ make: "DODGE",
+ model: "STEALTH",
+ },
+ {
+ make: "DODGE",
+ model: "STRATUS",
+ },
+ {
+ make: "DODGE",
+ model: "SWINGER",
+ },
+ {
+ make: "DODGE",
+ model: "SX 2.0",
+ },
+ {
+ make: "DODGE",
+ model: "W200",
+ },
+ {
+ make: "DODGE",
+ model: "W350",
+ },
+ {
+ make: "EAGLE",
+ model: "SUMMIT",
+ },
+ {
+ make: "EAGLE",
+ model: "TALON",
+ },
+ {
+ make: "EAGLE",
+ model: "VISION",
+ },
+ {
+ make: "FIAT",
+ model: "500C",
+ },
+ {
+ make: "FIAT",
+ model: "500L",
+ },
+ {
+ make: "FORD",
+ model: "500",
+ },
+ {
+ make: "FORD",
+ model: "AEROSTAR",
+ },
+ {
+ make: "FORD",
+ model: "ASPIRE",
+ },
+ {
+ make: "FORD",
+ model: "BRONCO",
+ },
+ {
+ make: "FORD",
+ model: "CMAX",
+ },
+ {
+ make: "FORD",
+ model: "CONTOUR",
+ },
+ {
+ make: "FORD",
+ model: "CROWN VIC",
+ },
+ {
+ make: "FORD",
+ model: "CUBE VAN",
+ },
+ {
+ make: "FORD",
+ model: "DUMP TRUCK",
+ },
+ {
+ make: "FORD",
+ model: "E150",
+ },
+ {
+ make: "FORD",
+ model: "E250",
+ },
+ {
+ make: "FORD",
+ model: "E350",
+ },
+ {
+ make: "FORD",
+ model: "E450",
+ },
+ {
+ make: "FORD",
+ model: "ECO SPORT",
+ },
+ {
+ make: "FORD",
+ model: "ECONOLINE",
+ },
+ {
+ make: "FORD",
+ model: "EDGE",
+ },
+ {
+ make: "FORD",
+ model: "ESCAPE",
+ },
+ {
+ make: "FORD",
+ model: "ESCORT",
+ },
+ {
+ make: "FORD",
+ model: "EXCURSION",
+ },
+ {
+ make: "FORD",
+ model: "EXPEDITION",
+ },
+ {
+ make: "FORD",
+ model: "EXPLORER",
+ },
+ {
+ make: "FORD",
+ model: "EXPLORER SPORT",
+ },
+ {
+ make: "FORD",
+ model: "EXPLORER SPORT TRAC",
+ },
+ {
+ make: "FORD",
+ model: "F-150",
+ },
+ {
+ make: "FORD",
+ model: "F-250",
+ },
+ {
+ make: "FORD",
+ model: "F-350",
+ },
+ {
+ make: "FORD",
+ model: "F-450",
+ },
+ {
+ make: "FORD",
+ model: "F-550",
+ },
+ {
+ make: "FORD",
+ model: "FAIRLANE",
+ },
+ {
+ make: "FORD",
+ model: "FESTIVA",
+ },
+ {
+ make: "FORD",
+ model: "FIESTA",
+ },
+ {
+ make: "FORD",
+ model: "FLAT DECK",
+ },
+ {
+ make: "FORD",
+ model: "FLEX",
+ },
+ {
+ make: "FORD",
+ model: "FOCUS",
+ },
+ {
+ make: "FORD",
+ model: "FREESTAR",
+ },
+ {
+ make: "FORD",
+ model: "FREESTYLE",
+ },
+ {
+ make: "FORD",
+ model: "FUSION",
+ },
+ {
+ make: "FORD",
+ model: "GALAXIE 500",
+ },
+ {
+ make: "FORD",
+ model: "LARIAT",
+ },
+ {
+ make: "FORD",
+ model: "LCF",
+ },
+ {
+ make: "FORD",
+ model: "LGT",
+ },
+ {
+ make: "FORD",
+ model: "MOTORHOME",
+ },
+ {
+ make: "FORD",
+ model: "MUSTANG",
+ },
+ {
+ make: "FORD",
+ model: "PLEASURE WAY",
+ },
+ {
+ make: "FORD",
+ model: "PROBE",
+ },
+ {
+ make: "FORD",
+ model: "RANGER",
+ },
+ {
+ make: "FORD",
+ model: "RAPTOR",
+ },
+ {
+ make: "FORD",
+ model: "SPORT TRAC",
+ },
+ {
+ make: "FORD",
+ model: "SUPER DUTY",
+ },
+ {
+ make: "FORD",
+ model: "TAURUS",
+ },
+ {
+ make: "FORD",
+ model: "T-BIRD",
+ },
+ {
+ make: "FORD",
+ model: "T-BUCKET",
+ },
+ {
+ make: "FORD",
+ model: "TEMPO",
+ },
+ {
+ make: "FORD",
+ model: "THUNDERBIRD",
+ },
+ {
+ make: "FORD",
+ model: "TRANSIT",
+ },
+ {
+ make: "FORD",
+ model: "TRANSIT 250",
+ },
+ {
+ make: "FORD",
+ model: "TRANSIT 350HD",
+ },
+ {
+ make: "FORD",
+ model: "TRANSIT CONNECT",
+ },
+ {
+ make: "FORD",
+ model: "TRANSIT COONECT",
+ },
+ {
+ make: "FORD",
+ model: "WINDSTAR",
+ },
+ {
+ make: "FREIGHTLINER",
+ model: "FL70",
+ },
+ {
+ make: "FREIGHTLINER",
+ model: "M2",
+ },
+ {
+ make: "GEO",
+ model: "METRO",
+ },
+ {
+ make: "GEO",
+ model: "STORM",
+ },
+ {
+ make: "GEO",
+ model: "TRACKER",
+ },
+ {
+ make: "GMC",
+ model: "1500",
+ },
+ {
+ make: "GMC",
+ model: "2500 HD",
+ },
+ {
+ make: "GMC",
+ model: "3500",
+ },
+ {
+ make: "GMC",
+ model: "4000",
+ },
+ {
+ make: "GMC",
+ model: "4500HD",
+ },
+ {
+ make: "GMC",
+ model: "ACADIA",
+ },
+ {
+ make: "GMC",
+ model: "C1500",
+ },
+ {
+ make: "GMC",
+ model: "C2500",
+ },
+ {
+ make: "GMC",
+ model: "C4500",
+ },
+ {
+ make: "GMC",
+ model: "CANYON",
+ },
+ {
+ make: "GMC",
+ model: "CARGO",
+ },
+ {
+ make: "GMC",
+ model: "DENALI HD",
+ },
+ {
+ make: "GMC",
+ model: "ENVOY",
+ },
+ {
+ make: "GMC",
+ model: "G2500 VANDURA",
+ },
+ {
+ make: "GMC",
+ model: "G35 SAVANNA",
+ },
+ {
+ make: "GMC",
+ model: "GEO",
+ },
+ {
+ make: "GMC",
+ model: "JIMMY",
+ },
+ {
+ make: "GMC",
+ model: "K 2500",
+ },
+ {
+ make: "GMC",
+ model: "K1500",
+ },
+ {
+ make: "GMC",
+ model: "K3500",
+ },
+ {
+ make: "GMC",
+ model: "RALLY",
+ },
+ {
+ make: "GMC",
+ model: "S15",
+ },
+ {
+ make: "GMC",
+ model: "S1500",
+ },
+ {
+ make: "GMC",
+ model: "SAFARI",
+ },
+ {
+ make: "GMC",
+ model: "SAVANA",
+ },
+ {
+ make: "GMC",
+ model: "SAVANA 3500",
+ },
+ {
+ make: "GMC",
+ model: "SIERRA",
+ },
+ {
+ make: "GMC",
+ model: "SIERRA 1500",
+ },
+ {
+ make: "GMC",
+ model: "SIERRA 2500",
+ },
+ {
+ make: "GMC",
+ model: "SIERRA 2500 HD",
+ },
+ {
+ make: "GMC",
+ model: "SIERRA 3500",
+ },
+ {
+ make: "GMC",
+ model: "SIERRA 3500, DENALI",
+ },
+ {
+ make: "GMC",
+ model: "SIERRA K1500",
+ },
+ {
+ make: "GMC",
+ model: "SLX",
+ },
+ {
+ make: "GMC",
+ model: "SONOMA",
+ },
+ {
+ make: "GMC",
+ model: "T7500",
+ },
+ {
+ make: "GMC",
+ model: "TERRAIN",
+ },
+ {
+ make: "GMC",
+ model: "TOP KICK",
+ },
+ {
+ make: "GMC",
+ model: "TOP KICK 6500",
+ },
+ {
+ make: "GMC",
+ model: "TOP KICK C4500",
+ },
+ {
+ make: "GMC",
+ model: "TRACKER",
+ },
+ {
+ make: "GMC",
+ model: "UTILIMASTER CUBE VAN",
+ },
+ {
+ make: "GMC",
+ model: "V15",
+ },
+ {
+ make: "GMC",
+ model: "VANDURA",
+ },
+ {
+ make: "GMC",
+ model: "VIXEN",
+ },
+ {
+ make: "GMC",
+ model: "W4500",
+ },
+ {
+ make: "GMC",
+ model: "W550",
+ },
+ {
+ make: "GMC",
+ model: "W5500",
+ },
+ {
+ make: "GMC",
+ model: "YUKON",
+ },
+ {
+ make: "GOLF",
+ model: "SPORT WAGON",
+ },
+ {
+ make: "HINO",
+ model: "268",
+ },
+ {
+ make: "HINO",
+ model: "338",
+ },
+ {
+ make: "HONDA",
+ model: "ACCORD",
+ },
+ {
+ make: "HONDA",
+ model: "CIVIC",
+ },
+ {
+ make: "HONDA",
+ model: "CIVIC HYBRID",
+ },
+ {
+ make: "HONDA",
+ model: "CRV",
+ },
+ {
+ make: "HONDA",
+ model: "CRX",
+ },
+ {
+ make: "HONDA",
+ model: "CR-Z",
+ },
+ {
+ make: "HONDA",
+ model: "DEL SOL",
+ },
+ {
+ make: "HONDA",
+ model: "ELEMENT",
+ },
+ {
+ make: "HONDA",
+ model: "FIT",
+ },
+ {
+ make: "HONDA",
+ model: "HR V",
+ },
+ {
+ make: "HONDA",
+ model: "INSIGHT",
+ },
+ {
+ make: "HONDA",
+ model: "ODYSSEY",
+ },
+ {
+ make: "HONDA",
+ model: "PASSPORT",
+ },
+ {
+ make: "HONDA",
+ model: "PILOT",
+ },
+ {
+ make: "HONDA",
+ model: "PRELUDE",
+ },
+ {
+ make: "HONDA",
+ model: "RIDGELINE",
+ },
+ {
+ make: "HONDA",
+ model: "S2000",
+ },
+ {
+ make: "HUMMER",
+ model: "H2",
+ },
+ {
+ make: "HUMMER",
+ model: "H3",
+ },
+ {
+ make: "HYUNDAI",
+ model: "ACCENT",
+ },
+ {
+ make: "HYUNDAI",
+ model: "AZERA",
+ },
+ {
+ make: "HYUNDAI",
+ model: "ELANTRA",
+ },
+ {
+ make: "HYUNDAI",
+ model: "ENTOURAGE",
+ },
+ {
+ make: "HYUNDAI",
+ model: "GENESIS",
+ },
+ {
+ make: "HYUNDAI",
+ model: "IONIQ",
+ },
+ {
+ make: "HYUNDAI",
+ model: "KONA",
+ },
+ {
+ make: "HYUNDAI",
+ model: "SANTA FE",
+ },
+ {
+ make: "HYUNDAI",
+ model: "SANTA FE SPORT",
+ },
+ {
+ make: "HYUNDAI",
+ model: "SCOUPE",
+ },
+ {
+ make: "HYUNDAI",
+ model: "SONATA",
+ },
+ {
+ make: "HYUNDAI",
+ model: "TIBURON",
+ },
+ {
+ make: "HYUNDAI",
+ model: "TOURING",
+ },
+ {
+ make: "HYUNDAI",
+ model: "TUCSON",
+ },
+ {
+ make: "HYUNDAI",
+ model: "VELOSTER",
+ },
+ {
+ make: "HYUNDAI",
+ model: "VENUE",
+ },
+ {
+ make: "HYUNDAI",
+ model: "VERA CRUZ",
+ },
+ {
+ make: "HYUNDAI",
+ model: "XG350",
+ },
+ {
+ make: "HYUNDAI",
+ model: "XG7",
+ },
+ {
+ make: "INFINITI",
+ model: "DURASTAR",
+ },
+ {
+ make: "INFINITI",
+ model: "EX35",
+ },
+ {
+ make: "INFINITI",
+ model: "FX35",
+ },
+ {
+ make: "INFINITI",
+ model: "FX45",
+ },
+ {
+ make: "INFINITI",
+ model: "FX50",
+ },
+ {
+ make: "INFINITI",
+ model: "G20",
+ },
+ {
+ make: "INFINITI",
+ model: "G35",
+ },
+ {
+ make: "INFINITI",
+ model: "G35X",
+ },
+ {
+ make: "INFINITI",
+ model: "G37",
+ },
+ {
+ make: "INFINITI",
+ model: "G37X",
+ },
+ {
+ make: "INFINITI",
+ model: "i30",
+ },
+ {
+ make: "INFINITI",
+ model: "I35",
+ },
+ {
+ make: "INFINITI",
+ model: "J30",
+ },
+ {
+ make: "INFINITI",
+ model: "JX35",
+ },
+ {
+ make: "INFINITI",
+ model: "L30",
+ },
+ {
+ make: "INFINITI",
+ model: "Q35",
+ },
+ {
+ make: "INFINITI",
+ model: "Q45",
+ },
+ {
+ make: "INFINITI",
+ model: "Q50",
+ },
+ {
+ make: "INFINITI",
+ model: "Q60",
+ },
+ {
+ make: "INFINITI",
+ model: "QX4",
+ },
+ {
+ make: "INFINITI",
+ model: "QX50",
+ },
+ {
+ make: "INFINITI",
+ model: "QX56",
+ },
+ {
+ make: "INFINITI",
+ model: "QX60",
+ },
+ {
+ make: "ISUZU",
+ model: "BIGHORN",
+ },
+ {
+ make: "ISUZU",
+ model: "CAB OVER",
+ },
+ {
+ make: "ISUZU",
+ model: "HOMBRE",
+ },
+ {
+ make: "ISUZU",
+ model: "NPR",
+ },
+ {
+ make: "ISUZU",
+ model: "NPR - HD",
+ },
+ {
+ make: "ISUZU",
+ model: "NRR",
+ },
+ {
+ make: "ISUZU",
+ model: "NRR - CAB OVER",
+ },
+ {
+ make: "ISUZU",
+ model: "RODEO",
+ },
+ {
+ make: "ISUZU",
+ model: "TROOPER",
+ },
+ {
+ make: "JAGUAR",
+ model: "F-PACE",
+ },
+ {
+ make: "JAGUAR",
+ model: "GATOR 850D",
+ },
+ {
+ make: "JAGUAR",
+ model: "IPACE",
+ },
+ {
+ make: "JAGUAR",
+ model: "S TYPE",
+ },
+ {
+ make: "JAGUAR",
+ model: "VANDEN PLAS",
+ },
+ {
+ make: "JAGUAR",
+ model: "XJ1",
+ },
+ {
+ make: "JAGUAR",
+ model: "XJ6",
+ },
+ {
+ make: "JAGUAR",
+ model: "XJ8",
+ },
+ {
+ make: "JAGUAR",
+ model: "XJS",
+ },
+ {
+ make: "JAGUAR",
+ model: "XK8",
+ },
+ {
+ make: "JAGUAR",
+ model: "X-TYPE",
+ },
+ {
+ make: "JEEP",
+ model: "CHEROKEE",
+ },
+ {
+ make: "JEEP",
+ model: "CJ",
+ },
+ {
+ make: "JEEP",
+ model: "CJ7",
+ },
+ {
+ make: "JEEP",
+ model: "COMMANCHE",
+ },
+ {
+ make: "JEEP",
+ model: "COMMANDER",
+ },
+ {
+ make: "JEEP",
+ model: "COMPASS",
+ },
+ {
+ make: "JEEP",
+ model: "CP",
+ },
+ {
+ make: "JEEP",
+ model: "GRAND CHEROKEE",
+ },
+ {
+ make: "JEEP",
+ model: "GRAND WAGONEER",
+ },
+ {
+ make: "JEEP",
+ model: "JK",
+ },
+ {
+ make: "JEEP",
+ model: "LIBERTY",
+ },
+ {
+ make: "JEEP",
+ model: "PATRIOT",
+ },
+ {
+ make: "JEEP",
+ model: "PT",
+ },
+ {
+ make: "JEEP",
+ model: "RENEGADE",
+ },
+ {
+ make: "JEEP",
+ model: "RUBICON",
+ },
+ {
+ make: "JEEP",
+ model: "TJ",
+ },
+ {
+ make: "JEEP",
+ model: "TJ SPORT",
+ },
+ {
+ make: "JEEP",
+ model: "WRANGLER",
+ },
+ {
+ make: "JEEP",
+ model: "YJ",
+ },
+ {
+ make: "KIA",
+ model: "CADENZA",
+ },
+ {
+ make: "KIA",
+ model: "CARNIVAL",
+ },
+ {
+ make: "KIA",
+ model: "FORTE",
+ },
+ {
+ make: "KIA",
+ model: "FORTE 5",
+ },
+ {
+ make: "KIA",
+ model: "MAGENTIS",
+ },
+ {
+ make: "KIA",
+ model: "NIRO",
+ },
+ {
+ make: "KIA",
+ model: "OPTIMA",
+ },
+ {
+ make: "KIA",
+ model: "RIO",
+ },
+ {
+ make: "KIA",
+ model: "RIO 5",
+ },
+ {
+ make: "KIA",
+ model: "RONDO",
+ },
+ {
+ make: "KIA",
+ model: "RX-V",
+ },
+ {
+ make: "KIA",
+ model: "SEDONA",
+ },
+ {
+ make: "KIA",
+ model: "SELTO",
+ },
+ {
+ make: "KIA",
+ model: "SEPHIA",
+ },
+ {
+ make: "KIA",
+ model: "SORENTO",
+ },
+ {
+ make: "KIA",
+ model: "SOUL",
+ },
+ {
+ make: "KIA",
+ model: "SPECTRA",
+ },
+ {
+ make: "KIA",
+ model: "SPECTRA 5",
+ },
+ {
+ make: "KIA",
+ model: "SPORT",
+ },
+ {
+ make: "KIA",
+ model: "SPORTAGE",
+ },
+ {
+ make: "KIA",
+ model: "VAN",
+ },
+ {
+ make: "LAND ROVER",
+ model: "DISCOVERY SPORT",
+ },
+ {
+ make: "LAND ROVER",
+ model: "LR2",
+ },
+ {
+ make: "LAND ROVER",
+ model: "RANGE ROVER EVOQUE",
+ },
+ {
+ make: "LAND ROVER",
+ model: "RANGE ROVER SPORT",
+ },
+ {
+ make: "LANDROVER",
+ model: "40 SE",
+ },
+ {
+ make: "LANDROVER",
+ model: "46HSE",
+ },
+ {
+ make: "LANDROVER",
+ model: "DEFENDER",
+ },
+ {
+ make: "LANDROVER",
+ model: "DISCOVERY",
+ },
+ {
+ make: "LANDROVER",
+ model: "DISCOVERY II",
+ },
+ {
+ make: "LANDROVER",
+ model: "FREELANDER",
+ },
+ {
+ make: "LANDROVER",
+ model: "LR2",
+ },
+ {
+ make: "LANDROVER",
+ model: "RANGE ROVER",
+ },
+ {
+ make: "LEXUS",
+ model: "ES300",
+ },
+ {
+ make: "LEXUS",
+ model: "ES350",
+ },
+ {
+ make: "LEXUS",
+ model: "GS250",
+ },
+ {
+ make: "LEXUS",
+ model: "GS300",
+ },
+ {
+ make: "LEXUS",
+ model: "GS450",
+ },
+ {
+ make: "LEXUS",
+ model: "GX470",
+ },
+ {
+ make: "LEXUS",
+ model: "HS250",
+ },
+ {
+ make: "LEXUS",
+ model: "IS250",
+ },
+ {
+ make: "LEXUS",
+ model: "IS300",
+ },
+ {
+ make: "LEXUS",
+ model: "IX 330",
+ },
+ {
+ make: "LEXUS",
+ model: "LS400",
+ },
+ {
+ make: "LEXUS",
+ model: "LS430",
+ },
+ {
+ make: "LEXUS",
+ model: "LX450",
+ },
+ {
+ make: "LEXUS",
+ model: "LX470",
+ },
+ {
+ make: "LEXUS",
+ model: "NX200",
+ },
+ {
+ make: "LEXUS",
+ model: "RC F",
+ },
+ {
+ make: "LEXUS",
+ model: "RX 300",
+ },
+ {
+ make: "LEXUS",
+ model: "RX 330",
+ },
+ {
+ make: "LEXUS",
+ model: "RX 350",
+ },
+ {
+ make: "LEXUS",
+ model: "RX 400H",
+ },
+ {
+ make: "LEXUS",
+ model: "RX300",
+ },
+ {
+ make: "LEXUS",
+ model: "RX330",
+ },
+ {
+ make: "LEXUS",
+ model: "RX350",
+ },
+ {
+ make: "LEXUS",
+ model: "RX400",
+ },
+ {
+ make: "LEXUS",
+ model: "RX450H",
+ },
+ {
+ make: "LEXUS",
+ model: "SC430",
+ },
+ {
+ make: "LEXUS",
+ model: "SOARER",
+ },
+ {
+ make: "LEXUS",
+ model: "UX250",
+ },
+ {
+ make: "LINCOLN",
+ model: "AVIATOR",
+ },
+ {
+ make: "LINCOLN",
+ model: "CONTINENTAL",
+ },
+ {
+ make: "LINCOLN",
+ model: "LS",
+ },
+ {
+ make: "LINCOLN",
+ model: "MARK",
+ },
+ {
+ make: "LINCOLN",
+ model: "MARK 5",
+ },
+ {
+ make: "LINCOLN",
+ model: "MARK LT",
+ },
+ {
+ make: "LINCOLN",
+ model: "MKC",
+ },
+ {
+ make: "LINCOLN",
+ model: "MKS",
+ },
+ {
+ make: "LINCOLN",
+ model: "MKX",
+ },
+ {
+ make: "LINCOLN",
+ model: "MKZ",
+ },
+ {
+ make: "LINCOLN",
+ model: "NAVIGATOR",
+ },
+ {
+ make: "LINCOLN",
+ model: "PICKUP",
+ },
+ {
+ make: "LINCOLN",
+ model: "TOWN CAR",
+ },
+ {
+ make: "LINCOLN",
+ model: "ZEPHER",
+ },
+ {
+ make: "Make",
+ model: "Model",
+ },
+ {
+ make: "MARK",
+ model: "LT",
+ },
+ {
+ make: "MASERATI",
+ model: "GHIBLI",
+ },
+ {
+ make: "MAZDA",
+ model: "2",
+ },
+ {
+ make: "MAZDA",
+ model: "3",
+ },
+ {
+ make: "MAZDA",
+ model: "3 H/B",
+ },
+ {
+ make: "MAZDA",
+ model: "3 SPORT",
+ },
+ {
+ make: "MAZDA",
+ model: "323",
+ },
+ {
+ make: "MAZDA",
+ model: "3GS",
+ },
+ {
+ make: "MAZDA",
+ model: "3GT",
+ },
+ {
+ make: "MAZDA",
+ model: "5",
+ },
+ {
+ make: "MAZDA",
+ model: "6",
+ },
+ {
+ make: "MAZDA",
+ model: "626",
+ },
+ {
+ make: "MAZDA",
+ model: "626ES",
+ },
+ {
+ make: "MAZDA",
+ model: "929",
+ },
+ {
+ make: "MAZDA",
+ model: "B2000",
+ },
+ {
+ make: "MAZDA",
+ model: "B2200",
+ },
+ {
+ make: "MAZDA",
+ model: "B2220",
+ },
+ {
+ make: "MAZDA",
+ model: "B2300",
+ },
+ {
+ make: "MAZDA",
+ model: "B2500",
+ },
+ {
+ make: "MAZDA",
+ model: "B2600",
+ },
+ {
+ make: "MAZDA",
+ model: "B2600I",
+ },
+ {
+ make: "MAZDA",
+ model: "B3000",
+ },
+ {
+ make: "MAZDA",
+ model: "B4000",
+ },
+ {
+ make: "MAZDA",
+ model: "B-SERIES",
+ },
+ {
+ make: "MAZDA",
+ model: "CX 7",
+ },
+ {
+ make: "MAZDA",
+ model: "CX3",
+ },
+ {
+ make: "MAZDA",
+ model: "CX-3",
+ },
+ {
+ make: "MAZDA",
+ model: "CX5",
+ },
+ {
+ make: "MAZDA",
+ model: "CX-5",
+ },
+ {
+ make: "MAZDA",
+ model: "CX5 GT",
+ },
+ {
+ make: "MAZDA",
+ model: "CX9",
+ },
+ {
+ make: "MAZDA",
+ model: "CX-9",
+ },
+ {
+ make: "MAZDA",
+ model: "D",
+ },
+ {
+ make: "MAZDA",
+ model: "MAZDA 3",
+ },
+ {
+ make: "MAZDA",
+ model: "MAZDA 5",
+ },
+ {
+ make: "MAZDA",
+ model: "MAZDA 6",
+ },
+ {
+ make: "MAZDA",
+ model: "MIATA",
+ },
+ {
+ make: "MAZDA",
+ model: "MIATA GX",
+ },
+ {
+ make: "MAZDA",
+ model: "MILLENIA",
+ },
+ {
+ make: "MAZDA",
+ model: "MPV",
+ },
+ {
+ make: "MAZDA",
+ model: "MR 2",
+ },
+ {
+ make: "MAZDA",
+ model: "MX-3",
+ },
+ {
+ make: "MAZDA",
+ model: "MX-3 PRECIDIA",
+ },
+ {
+ make: "MAZDA",
+ model: "MX-5",
+ },
+ {
+ make: "MAZDA",
+ model: "MX-6",
+ },
+ {
+ make: "MAZDA",
+ model: "PRECIDIA",
+ },
+ {
+ make: "MAZDA",
+ model: "PROTEGE",
+ },
+ {
+ make: "MAZDA",
+ model: "PROTEGE 5",
+ },
+ {
+ make: "MAZDA",
+ model: "RX7",
+ },
+ {
+ make: "MAZDA",
+ model: "RX8",
+ },
+ {
+ make: "MAZDA",
+ model: "TRIBUTE",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "190E",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "240D",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "245 BCLASS",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "300",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "300SD",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "300SL",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "B200",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "B250",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "C220",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "C230",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "C230 KOMPRESSOR",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "C240",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "C300",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "C300W",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "C320",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "C350",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "C400",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "C43",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "C63",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "C63 AMG",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "CLA25",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "CLK",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "CLK230",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "CLK320",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "CLK350",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "CLK500",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "CLR350",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "COMPRESSOR",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "E300",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "E320",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "E400",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "E420",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "E500W",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "E550",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "GLA25",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "GLC30",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "GLE350",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "GLK",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "GLK25",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "GLK250",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "GLK35",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "GLK35",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "M1320",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "METRIS",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "MI320",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "MI350",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "MI500",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "ML350",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "ML400",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "ML430",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "ML55",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "ML63",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "R320",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "S155",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "S450V",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "SL500",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "SLK230",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "SLK350",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "SPRINTER",
+ },
+ {
+ make: "MERCEDES-BENZ",
+ model: "SPRINTER VAN",
+ },
+ {
+ make: "MERCURY",
+ model: "COMET",
+ },
+ {
+ make: "MERCURY",
+ model: "COUGAR",
+ },
+ {
+ make: "MERCURY",
+ model: "GRAND MARQUIS",
+ },
+ {
+ make: "MERCURY",
+ model: "MARQUIS",
+ },
+ {
+ make: "MERCURY",
+ model: "MURADER",
+ },
+ {
+ make: "MERCURY",
+ model: "MYSTIQUE",
+ },
+ {
+ make: "MERCURY",
+ model: "SABLE",
+ },
+ {
+ make: "MERCURY",
+ model: "TOPAZ",
+ },
+ {
+ make: "MERCURY",
+ model: "VILLAGER",
+ },
+ {
+ make: "MINI",
+ model: "COOPER",
+ },
+ {
+ make: "MINI",
+ model: "COOPER CLUBMAN",
+ },
+ {
+ make: "MINI",
+ model: "COOPER COUNTRYMAN",
+ },
+ {
+ make: "MINI",
+ model: "COOPER S",
+ },
+ {
+ make: "MITSUBISHI",
+ model: "DELICA",
+ },
+ {
+ make: "MITSUBISHI",
+ model: "ECLIPSE",
+ },
+ {
+ make: "MITSUBISHI",
+ model: "ECLIPSE CROSS",
+ },
+ {
+ make: "MITSUBISHI",
+ model: "ENDVR",
+ },
+ {
+ make: "MITSUBISHI",
+ model: "GALANT",
+ },
+ {
+ make: "MITSUBISHI",
+ model: "LANCER",
+ },
+ {
+ make: "MITSUBISHI",
+ model: "LANCER EVOLUTION",
+ },
+ {
+ make: "MITSUBISHI",
+ model: "MIRAGE",
+ },
+ {
+ make: "MITSUBISHI",
+ model: "MONTERO",
+ },
+ {
+ make: "MITSUBISHI",
+ model: "OUTLANDER",
+ },
+ {
+ make: "MITSUBISHI",
+ model: "PJERO",
+ },
+ {
+ make: "MITSUBISHI",
+ model: "RVR",
+ },
+ {
+ make: "MITSUBISHI",
+ model: "SPYDER",
+ },
+ {
+ make: "NISSAN",
+ model: "200",
+ },
+ {
+ make: "NISSAN",
+ model: "200SX",
+ },
+ {
+ make: "NISSAN",
+ model: "240SX",
+ },
+ {
+ make: "NISSAN",
+ model: "240Z",
+ },
+ {
+ make: "NISSAN",
+ model: "2500 VAN",
+ },
+ {
+ make: "NISSAN",
+ model: "280",
+ },
+ {
+ make: "NISSAN",
+ model: "300ZX",
+ },
+ {
+ make: "NISSAN",
+ model: "350Z",
+ },
+ {
+ make: "NISSAN",
+ model: "370Z",
+ },
+ {
+ make: "NISSAN",
+ model: "ALTIMA",
+ },
+ {
+ make: "NISSAN",
+ model: "ARMADA",
+ },
+ {
+ make: "NISSAN",
+ model: "AXXESS",
+ },
+ {
+ make: "NISSAN",
+ model: "CUBE",
+ },
+ {
+ make: "NISSAN",
+ model: "D21",
+ },
+ {
+ make: "NISSAN",
+ model: "FIGARO",
+ },
+ {
+ make: "NISSAN",
+ model: "FRONTIER",
+ },
+ {
+ make: "NISSAN",
+ model: "HALFTON DLX",
+ },
+ {
+ make: "NISSAN",
+ model: "JUKE",
+ },
+ {
+ make: "NISSAN",
+ model: "KICKS",
+ },
+ {
+ make: "NISSAN",
+ model: "LEAF",
+ },
+ {
+ make: "NISSAN",
+ model: "MAXIMA",
+ },
+ {
+ make: "NISSAN",
+ model: "MICRA",
+ },
+ {
+ make: "NISSAN",
+ model: "MURANO",
+ },
+ {
+ make: "NISSAN",
+ model: "NV200",
+ },
+ {
+ make: "NISSAN",
+ model: "NV250",
+ },
+ {
+ make: "NISSAN",
+ model: "NV2500",
+ },
+ {
+ make: "NISSAN",
+ model: "PATHFINDER",
+ },
+ {
+ make: "NISSAN",
+ model: "PULSAR",
+ },
+ {
+ make: "NISSAN",
+ model: "QASHQAI",
+ },
+ {
+ make: "NISSAN",
+ model: "QSHQI",
+ },
+ {
+ make: "NISSAN",
+ model: "QUEST",
+ },
+ {
+ make: "NISSAN",
+ model: "ROGUE",
+ },
+ {
+ make: "NISSAN",
+ model: "SENTRA",
+ },
+ {
+ make: "NISSAN",
+ model: "SILVIA",
+ },
+ {
+ make: "NISSAN",
+ model: "SKYLINE",
+ },
+ {
+ make: "NISSAN",
+ model: "SKYLINE GTR",
+ },
+ {
+ make: "NISSAN",
+ model: "TERRANO",
+ },
+ {
+ make: "NISSAN",
+ model: "TITAN",
+ },
+ {
+ make: "NISSAN",
+ model: "TRANO - PATHFINDER",
+ },
+ {
+ make: "NISSAN",
+ model: "VERS",
+ },
+ {
+ make: "NISSAN",
+ model: "VERSA",
+ },
+ {
+ make: "NISSAN",
+ model: "X-TERRA",
+ },
+ {
+ make: "NISSAN",
+ model: "X-TRAIL",
+ },
+ {
+ make: "OLDSMOBILE",
+ model: "ACHIEVA",
+ },
+ {
+ make: "OLDSMOBILE",
+ model: "ALERO",
+ },
+ {
+ make: "OLDSMOBILE",
+ model: "AURORA",
+ },
+ {
+ make: "OLDSMOBILE",
+ model: "BRAVADO",
+ },
+ {
+ make: "OLDSMOBILE",
+ model: "CUTLASS",
+ },
+ {
+ make: "OLDSMOBILE",
+ model: "DELTA 88",
+ },
+ {
+ make: "OLDSMOBILE",
+ model: "DELTA 88 ROYALE BROUGHAM",
+ },
+ {
+ make: "OLDSMOBILE",
+ model: "INTRIGUE",
+ },
+ {
+ make: "OLDSMOBILE",
+ model: "NINETY EIGHT",
+ },
+ {
+ make: "OLDSMOBILE",
+ model: "OMEGA",
+ },
+ {
+ make: "OLDSMOBILE",
+ model: "REGENCY",
+ },
+ {
+ make: "OLDSMOBILE",
+ model: "SILHOUETTE",
+ },
+ {
+ make: "OLDSMOBILE",
+ model: "TORONADO",
+ },
+ {
+ make: "PLYMOUTH",
+ model: "ACCLAIM",
+ },
+ {
+ make: "PLYMOUTH",
+ model: "BARACUDA",
+ },
+ {
+ make: "PLYMOUTH",
+ model: "BREEZE",
+ },
+ {
+ make: "PLYMOUTH",
+ model: "CARAVAN",
+ },
+ {
+ make: "PLYMOUTH",
+ model: "GR.VOYAGER",
+ },
+ {
+ make: "PLYMOUTH",
+ model: "NEON",
+ },
+ {
+ make: "PLYMOUTH",
+ model: "RELIANT",
+ },
+ {
+ make: "PLYMOUTH",
+ model: "SUNDANCE",
+ },
+ {
+ make: "PLYMOUTH",
+ model: "VALANT",
+ },
+ {
+ make: "PLYMOUTH",
+ model: "VOYAGER",
+ },
+ {
+ make: "POLARIS",
+ model: "570 CREW",
+ },
+ {
+ make: "POLARIS",
+ model: "GENERAL 2+2",
+ },
+ {
+ make: "PONTIAC",
+ model: "ACADIAN",
+ },
+ {
+ make: "PONTIAC",
+ model: "AZTEC",
+ },
+ {
+ make: "PONTIAC",
+ model: "BEAUMONT",
+ },
+ {
+ make: "PONTIAC",
+ model: "BONNEVILLE",
+ },
+ {
+ make: "PONTIAC",
+ model: "FIERO",
+ },
+ {
+ make: "PONTIAC",
+ model: "FIREBIRD",
+ },
+ {
+ make: "PONTIAC",
+ model: "FIREFLY",
+ },
+ {
+ make: "PONTIAC",
+ model: "G3",
+ },
+ {
+ make: "PONTIAC",
+ model: "G5",
+ },
+ {
+ make: "PONTIAC",
+ model: "G6",
+ },
+ {
+ make: "PONTIAC",
+ model: "G8",
+ },
+ {
+ make: "PONTIAC",
+ model: "GRAND AM",
+ },
+ {
+ make: "PONTIAC",
+ model: "GRAND PRIX",
+ },
+ {
+ make: "PONTIAC",
+ model: "GTO",
+ },
+ {
+ make: "PONTIAC",
+ model: "MONTANA",
+ },
+ {
+ make: "PONTIAC",
+ model: "PARRISSIEN",
+ },
+ {
+ make: "PONTIAC",
+ model: "PURSUIT",
+ },
+ {
+ make: "PONTIAC",
+ model: "SOLSTICE",
+ },
+ {
+ make: "PONTIAC",
+ model: "SUNBIRD",
+ },
+ {
+ make: "PONTIAC",
+ model: "SUNFIRE",
+ },
+ {
+ make: "PONTIAC",
+ model: "SUNRUNNER",
+ },
+ {
+ make: "PONTIAC",
+ model: "TEMPEST",
+ },
+ {
+ make: "PONTIAC",
+ model: "TORRENT",
+ },
+ {
+ make: "PONTIAC",
+ model: "TRANS-AM",
+ },
+ {
+ make: "PONTIAC",
+ model: "TRANSPORT",
+ },
+ {
+ make: "PONTIAC",
+ model: "VIBE",
+ },
+ {
+ make: "PONTIAC",
+ model: "WAVE",
+ },
+ {
+ make: "PORSCHE",
+ model: "911",
+ },
+ {
+ make: "PORSCHE",
+ model: "928",
+ },
+ {
+ make: "PORSCHE",
+ model: "944",
+ },
+ {
+ make: "PORSCHE",
+ model: "944 TURBO",
+ },
+ {
+ make: "PORSCHE",
+ model: "BOXSTER",
+ },
+ {
+ make: "PORSCHE",
+ model: "CAYENNE",
+ },
+ {
+ make: "RANGE ROVER",
+ model: "46SHE",
+ },
+ {
+ make: "RANGE ROVER",
+ model: "PROMA",
+ },
+ {
+ make: "RANGE ROVER",
+ model: "RANGE",
+ },
+ {
+ make: "SAAB",
+ model: "9",
+ },
+ {
+ make: "SAAB",
+ model: "900S",
+ },
+ {
+ make: "SAAB",
+ model: "9-2X",
+ },
+ {
+ make: "SAAB",
+ model: "9-3",
+ },
+ {
+ make: "SAAB",
+ model: "93 AREO",
+ },
+ {
+ make: "SAAB",
+ model: "9-5",
+ },
+ {
+ make: "SATURN",
+ model: "ASTRA",
+ },
+ {
+ make: "SATURN",
+ model: "AURA",
+ },
+ {
+ make: "SATURN",
+ model: "ION",
+ },
+ {
+ make: "SATURN",
+ model: "L100",
+ },
+ {
+ make: "SATURN",
+ model: "L200",
+ },
+ {
+ make: "SATURN",
+ model: "LS1",
+ },
+ {
+ make: "SATURN",
+ model: "LS2",
+ },
+ {
+ make: "SATURN",
+ model: "OUTLOOK",
+ },
+ {
+ make: "SATURN",
+ model: "RELAY",
+ },
+ {
+ make: "SATURN",
+ model: "S SERIES",
+ },
+ {
+ make: "SATURN",
+ model: "S11",
+ },
+ {
+ make: "SATURN",
+ model: "SC1",
+ },
+ {
+ make: "SATURN",
+ model: "SKY",
+ },
+ {
+ make: "SATURN",
+ model: "SL1",
+ },
+ {
+ make: "SATURN",
+ model: "SL2",
+ },
+ {
+ make: "SATURN",
+ model: "SW1",
+ },
+ {
+ make: "SATURN",
+ model: "SW2",
+ },
+ {
+ make: "SATURN",
+ model: "VUE",
+ },
+ {
+ make: "SATURN",
+ model: "WGN",
+ },
+ {
+ make: "SCION",
+ model: "FR-S",
+ },
+ {
+ make: "SCION",
+ model: "IM",
+ },
+ {
+ make: "SCION",
+ model: "SXB",
+ },
+ {
+ make: "SCION",
+ model: "TC",
+ },
+ {
+ make: "SCION",
+ model: "XB",
+ },
+ {
+ make: "SCION",
+ model: "XD",
+ },
+ {
+ make: "SMART",
+ model: "FORTWO",
+ },
+ {
+ make: "SUBARU",
+ model: "ASENT",
+ },
+ {
+ make: "SUBARU",
+ model: "B9 TRIBECA",
+ },
+ {
+ make: "SUBARU",
+ model: "BAJA",
+ },
+ {
+ make: "SUBARU",
+ model: "BRAT",
+ },
+ {
+ make: "SUBARU",
+ model: "BRZ",
+ },
+ {
+ make: "SUBARU",
+ model: "CROSSTREK",
+ },
+ {
+ make: "SUBARU",
+ model: "DOMINGO",
+ },
+ {
+ make: "SUBARU",
+ model: "DOMNGO",
+ },
+ {
+ make: "SUBARU",
+ model: "FORESTER",
+ },
+ {
+ make: "SUBARU",
+ model: "GL",
+ },
+ {
+ make: "SUBARU",
+ model: "IMPREZA",
+ },
+ {
+ make: "SUBARU",
+ model: "IMPREZA STI",
+ },
+ {
+ make: "SUBARU",
+ model: "JUSTY",
+ },
+ {
+ make: "SUBARU",
+ model: "LEGACY",
+ },
+ {
+ make: "SUBARU",
+ model: "LOYALE",
+ },
+ {
+ make: "SUBARU",
+ model: "OUTBACK",
+ },
+ {
+ make: "SUBARU",
+ model: "SVX",
+ },
+ {
+ make: "SUBARU",
+ model: "TRIBECA",
+ },
+ {
+ make: "SUBARU",
+ model: "WRX",
+ },
+ {
+ make: "SUBARU",
+ model: "WRX STI",
+ },
+ {
+ make: "SUBARU",
+ model: "XV",
+ },
+ {
+ make: "SUZUKI",
+ model: "AERIO",
+ },
+ {
+ make: "SUZUKI",
+ model: "CARRY",
+ },
+ {
+ make: "SUZUKI",
+ model: "ESTEEM",
+ },
+ {
+ make: "SUZUKI",
+ model: "GRAND VITARA",
+ },
+ {
+ make: "SUZUKI",
+ model: "MINI-TRUCK",
+ },
+ {
+ make: "SUZUKI",
+ model: "SAMURAI",
+ },
+ {
+ make: "SUZUKI",
+ model: "SIDEKICK",
+ },
+ {
+ make: "SUZUKI",
+ model: "SWIFT",
+ },
+ {
+ make: "SUZUKI",
+ model: "SX4",
+ },
+ {
+ make: "SUZUKI",
+ model: "VITARA",
+ },
+ {
+ make: "SUZUKI",
+ model: "XL7",
+ },
+ {
+ make: "TESLA",
+ model: "MODEL 3",
+ },
+ {
+ make: "TOYOTA",
+ model: " PRIUS C",
+ },
+ {
+ make: "TOYOTA",
+ model: "4 RUNNER",
+ },
+ {
+ make: "TOYOTA",
+ model: "4X4",
+ },
+ {
+ make: "TOYOTA",
+ model: "ALPHARD",
+ },
+ {
+ make: "TOYOTA",
+ model: "ARISTO",
+ },
+ {
+ make: "TOYOTA",
+ model: "AVALON",
+ },
+ {
+ make: "TOYOTA",
+ model: "CALDI",
+ },
+ {
+ make: "TOYOTA",
+ model: "CALDINA",
+ },
+ {
+ make: "TOYOTA",
+ model: "CAMRY",
+ },
+ {
+ make: "TOYOTA",
+ model: "CANOPY",
+ },
+ {
+ make: "TOYOTA",
+ model: "CELICA",
+ },
+ {
+ make: "TOYOTA",
+ model: "CELSLOR",
+ },
+ {
+ make: "TOYOTA",
+ model: "CHASE",
+ },
+ {
+ make: "TOYOTA",
+ model: "CH-R",
+ },
+ {
+ make: "TOYOTA",
+ model: "COROLLA",
+ },
+ {
+ make: "TOYOTA",
+ model: "COROLLA CE",
+ },
+ {
+ make: "TOYOTA",
+ model: "COROLLA.HYBRID",
+ },
+ {
+ make: "TOYOTA",
+ model: "CRESSIDA",
+ },
+ {
+ make: "TOYOTA",
+ model: "DELICA",
+ },
+ {
+ make: "TOYOTA",
+ model: "ECHO",
+ },
+ {
+ make: "TOYOTA",
+ model: "FJ",
+ },
+ {
+ make: "TOYOTA",
+ model: "HIGHLANDER",
+ },
+ {
+ make: "TOYOTA",
+ model: "LAND CRUISER",
+ },
+ {
+ make: "TOYOTA",
+ model: "MATRIX",
+ },
+ {
+ make: "TOYOTA",
+ model: "MR2",
+ },
+ {
+ make: "TOYOTA",
+ model: "PASEO",
+ },
+ {
+ make: "TOYOTA",
+ model: "PICK UP",
+ },
+ {
+ make: "TOYOTA",
+ model: "PRADA",
+ },
+ {
+ make: "TOYOTA",
+ model: "PREVIA",
+ },
+ {
+ make: "TOYOTA",
+ model: "PRIUS",
+ },
+ {
+ make: "TOYOTA",
+ model: "PRIUS HYBIRD",
+ },
+ {
+ make: "TOYOTA",
+ model: "PRIUS V",
+ },
+ {
+ make: "TOYOTA",
+ model: "RAV4",
+ },
+ {
+ make: "TOYOTA",
+ model: "SCION",
+ },
+ {
+ make: "TOYOTA",
+ model: "SEQUOIA",
+ },
+ {
+ make: "TOYOTA",
+ model: "SIENNA",
+ },
+ {
+ make: "TOYOTA",
+ model: "SOLARA",
+ },
+ {
+ make: "TOYOTA",
+ model: "SORER",
+ },
+ {
+ make: "TOYOTA",
+ model: "SP & SP",
+ },
+ {
+ make: "TOYOTA",
+ model: "SUPRA",
+ },
+ {
+ make: "TOYOTA",
+ model: "SURF",
+ },
+ {
+ make: "TOYOTA",
+ model: "TACOMA",
+ },
+ {
+ make: "TOYOTA",
+ model: "TERCEL",
+ },
+ {
+ make: "TOYOTA",
+ model: "TUNDRA",
+ },
+ {
+ make: "TOYOTA",
+ model: "VENZA",
+ },
+ {
+ make: "TOYOTA",
+ model: "YARIS",
+ },
+ {
+ make: "TRIUMPH",
+ model: "TR3",
+ },
+ {
+ make: "VOLKSWAGEN",
+ model: "ATLAS",
+ },
+ {
+ make: "VOLKSWAGEN",
+ model: "BEETLE",
+ },
+ {
+ make: "VOLKSWAGEN",
+ model: "CABRIOLET",
+ },
+ {
+ make: "VOLKSWAGEN",
+ model: "CC",
+ },
+ {
+ make: "VOLKSWAGEN",
+ model: "CORRADO",
+ },
+ {
+ make: "VOLKSWAGEN",
+ model: "DUNEBUGGY",
+ },
+ {
+ make: "VOLKSWAGEN",
+ model: "EOS",
+ },
+ {
+ make: "VOLKSWAGEN",
+ model: "EUROVAN",
+ },
+ {
+ make: "VOLKSWAGEN",
+ model: "GOLF",
+ },
+ {
+ make: "VOLKSWAGEN",
+ model: "GOLF CABRIOLET",
+ },
+ {
+ make: "VOLKSWAGEN",
+ model: "GOLF CITY",
+ },
+ {
+ make: "VOLKSWAGEN",
+ model: "GOLF GTI",
+ },
+ {
+ make: "VOLKSWAGEN",
+ model: "GOLF SPORT WAGEN",
+ },
+ {
+ make: "VOLKSWAGEN",
+ model: "GTI",
+ },
+ {
+ make: "VOLKSWAGEN",
+ model: "JETTA",
+ },
+ {
+ make: "VOLKSWAGEN",
+ model: "JETTA TDI",
+ },
+ {
+ make: "VOLKSWAGEN",
+ model: "KIT CAR",
+ },
+ {
+ make: "VOLKSWAGEN",
+ model: "PASSAT",
+ },
+ {
+ make: "VOLKSWAGEN",
+ model: "R32",
+ },
+ {
+ make: "VOLKSWAGEN",
+ model: "RABBIT",
+ },
+ {
+ make: "VOLKSWAGEN",
+ model: "ROUTAN",
+ },
+ {
+ make: "VOLKSWAGEN",
+ model: "TIGUAN",
+ },
+ {
+ make: "VOLKSWAGEN",
+ model: "TOUAREG",
+ },
+ {
+ make: "VOLKSWAGEN",
+ model: "TRANSPORTER VAN",
+ },
+ {
+ make: "VOLKSWAGEN",
+ model: "VANAGON",
+ },
+ {
+ make: "VOLKSWAGEN",
+ model: "WESTFALIA",
+ },
+ {
+ make: "VOLKSWAGEN",
+ model: "WINNEBAGO",
+ },
+ {
+ make: "VOLVO",
+ model: "240",
+ },
+ {
+ make: "VOLVO",
+ model: "244",
+ },
+ {
+ make: "VOLVO",
+ model: "740",
+ },
+ {
+ make: "VOLVO",
+ model: "760",
+ },
+ {
+ make: "VOLVO",
+ model: "850",
+ },
+ {
+ make: "VOLVO",
+ model: "940",
+ },
+ {
+ make: "VOLVO",
+ model: "960",
+ },
+ {
+ make: "VOLVO",
+ model: "C30",
+ },
+ {
+ make: "VOLVO",
+ model: "C70",
+ },
+ {
+ make: "VOLVO",
+ model: "DL",
+ },
+ {
+ make: "VOLVO",
+ model: "GLE",
+ },
+ {
+ make: "VOLVO",
+ model: "GLT",
+ },
+ {
+ make: "VOLVO",
+ model: "GT",
+ },
+ {
+ make: "VOLVO",
+ model: "S40",
+ },
+ {
+ make: "VOLVO",
+ model: "S60",
+ },
+ {
+ make: "VOLVO",
+ model: "S70",
+ },
+ {
+ make: "VOLVO",
+ model: "S80",
+ },
+ {
+ make: "VOLVO",
+ model: "S90",
+ },
+ {
+ make: "VOLVO",
+ model: "V40",
+ },
+ {
+ make: "VOLVO",
+ model: "V50",
+ },
+ {
+ make: "VOLVO",
+ model: "V70",
+ },
+ {
+ make: "VOLVO",
+ model: "V70 - X/C",
+ },
+ {
+ make: "VOLVO",
+ model: "XC60",
+ },
+ {
+ make: "VOLVO",
+ model: "XC70",
+ },
+ {
+ make: "VOLVO",
+ model: "XC90",
+ },
];
export default obj;
diff --git a/client/src/components/jobs-detail-change-estimator/jobs-detail-change-estimator.component.jsx b/client/src/components/jobs-detail-change-estimator/jobs-detail-change-estimator.component.jsx
index 61035b23e..dd5d527d0 100644
--- a/client/src/components/jobs-detail-change-estimator/jobs-detail-change-estimator.component.jsx
+++ b/client/src/components/jobs-detail-change-estimator/jobs-detail-change-estimator.component.jsx
@@ -1,43 +1,40 @@
-import { DownOutlined } from "@ant-design/icons";
-import { Dropdown, Menu } from "antd";
+import {DownOutlined} from "@ant-design/icons";
+import {Dropdown} from "antd";
import React from "react";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { selectBodyshop } from "../../redux/user/user.selectors";
+import {connect} from "react-redux";
+import {createStructuredSelector} from "reselect";
+import {selectBodyshop} from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
- bodyshop: selectBodyshop,
+ bodyshop: selectBodyshop,
});
-export function JobsDetailChangeEstimator({ disabled, form, bodyshop }) {
- const handleClick = ({ item, key, keyPath }) => {
- const est = item.props.value;
- form.setFieldsValue(est);
- };
+export function JobsDetailChangeEstimator({disabled, form, bodyshop}) {
+ const handleClick = ({item, key, keyPath}) => {
+ const est = item.props.value;
+ form.setFieldsValue(est);
+ };
- const menu = (
-
-
-
- );
+ const menu = {
+ items: bodyshop.md_estimators.map((est, idx) => ({
+ key: idx,
+ label: `${est.est_ct_fn} ${est.est_ct_ln}`,
+ value: est,
+ })),
+ onClick: handleClick
+ }
- return (
-
- e.preventDefault()}
- >
-
-
-
- );
+ return (
+
+ e.preventDefault()}
+ >
+
+
+
+ );
}
export default connect(mapStateToProps, null)(JobsDetailChangeEstimator);
diff --git a/client/src/components/jobs-detail-change-filehandler/jobs-detail-change-filehandler.component.jsx b/client/src/components/jobs-detail-change-filehandler/jobs-detail-change-filehandler.component.jsx
index ee684994b..f582b9e41 100644
--- a/client/src/components/jobs-detail-change-filehandler/jobs-detail-change-filehandler.component.jsx
+++ b/client/src/components/jobs-detail-change-filehandler/jobs-detail-change-filehandler.component.jsx
@@ -1,46 +1,44 @@
-import { DownOutlined } from "@ant-design/icons";
-import { Dropdown, Menu } from "antd";
+import {DownOutlined} from "@ant-design/icons";
+import {Dropdown} from "antd";
import React from "react";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { selectBodyshop } from "../../redux/user/user.selectors";
+import {connect} from "react-redux";
+import {createStructuredSelector} from "reselect";
+import {selectBodyshop} from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
- bodyshop: selectBodyshop,
+ bodyshop: selectBodyshop,
});
-export function JobsDetailChangeFilehandler({ disabled, form, bodyshop }) {
- const handleClick = ({ item, key, keyPath }) => {
- const est = item.props.value;
- form.setFieldsValue(est);
- };
+export function JobsDetailChangeFilehandler({disabled, form, bodyshop}) {
+ const handleClick = ({item, key, keyPath}) => {
+ const est = item.props.value;
+ form.setFieldsValue(est);
+ };
- const menu = (
-
- );
+ const menu = {
+ items: bodyshop.md_filehandlers.map((est, idx) => ({
+ key: idx,
+ label: `${est.ins_ct_fn} ${est.ins_ct_ln}`,
+ value: est,
+ style: {breakInside: "avoid"},
+ })),
+ style: {
+ columnCount: Math.floor(bodyshop.md_filehandlers.length / 10) + 1,
+ },
+ onClick: handleClick
+ }
- return (
-
- e.preventDefault()}
- >
-
-
-
- );
+ return (
+
+ e.preventDefault()}
+ >
+
+
+
+ );
}
export default connect(mapStateToProps, null)(JobsDetailChangeFilehandler);
diff --git a/client/src/components/jobs-detail-checklists/jobs-detail-checklists.component.jsx b/client/src/components/jobs-detail-checklists/jobs-detail-checklists.component.jsx
index 0cd08467d..f862a094d 100644
--- a/client/src/components/jobs-detail-checklists/jobs-detail-checklists.component.jsx
+++ b/client/src/components/jobs-detail-checklists/jobs-detail-checklists.component.jsx
@@ -1,20 +1,20 @@
import React from "react";
-import { Row, Col } from "antd";
+import {Col, Row} from "antd";
import JobChecklistDisplay from "../job-checklist/job-checklist-display.component";
-const colSpan = { sm: { span: 24 }, md: { span: 12 } };
-export default function JobsDetailChecklists({ job }) {
- return (
-
-
-
-
-
-
-
-
-
-
-
- );
+const colSpan = {sm: {span: 24}, md: {span: 12}};
+export default function JobsDetailChecklists({job}) {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ );
}
diff --git a/client/src/components/jobs-detail-dates/jobs-detail-dates.component.jsx b/client/src/components/jobs-detail-dates/jobs-detail-dates.component.jsx
index dcd6fd941..35a0a39c5 100644
--- a/client/src/components/jobs-detail-dates/jobs-detail-dates.component.jsx
+++ b/client/src/components/jobs-detail-dates/jobs-detail-dates.component.jsx
@@ -1,159 +1,160 @@
-import { Form, Statistic, Tooltip } from "antd";
-import React, { useMemo } 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 {Form, Statistic, Tooltip} from "antd";
+import React, {useMemo} 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 FormDatePicker from "../form-date-picker/form-date-picker.component";
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component";
import FormRow from "../layout-form-row/layout-form-row.component";
const mapStateToProps = createStructuredSelector({
- jobRO: selectJobReadOnly,
- bodyshop: selectBodyshop,
+ jobRO: selectJobReadOnly,
+ bodyshop: selectBodyshop,
});
-export function JobsDetailDatesComponent({ jobRO, job, bodyshop }) {
- const { t } = useTranslation();
+export function JobsDetailDatesComponent({jobRO, job, bodyshop}) {
+ const {t} = useTranslation();
- const jobInPostProduction = useMemo(() => {
- return bodyshop.md_ro_statuses.post_production_statuses.includes(
- job.status
+ const jobInPostProduction = useMemo(() => {
+ return bodyshop.md_ro_statuses.post_production_statuses.includes(
+ job.status
+ );
+ }, [job.status, bodyshop.md_ro_statuses.post_production_statuses]);
+
+ const calcRepairDays =
+ job.joblines.reduce((acc, val) => acc + val.mod_lb_hrs, 0) /
+ (bodyshop.target_touchtime === 0 ? 1 : bodyshop.target_touchtime);
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {() => {
+ return (
+
+
+
+ );
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
);
- }, [job.status, bodyshop.md_ro_statuses.post_production_statuses]);
-
- const calcRepairDays =
- job.joblines.reduce((acc, val) => acc + val.mod_lb_hrs, 0) /
- (bodyshop.target_touchtime === 0 ? 1 : bodyshop.target_touchtime);
-
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {() => {
- return (
-
-
-
- );
- }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
}
+
export default connect(mapStateToProps, null)(JobsDetailDatesComponent);
diff --git a/client/src/components/jobs-detail-general/jobs-detail-general.component.jsx b/client/src/components/jobs-detail-general/jobs-detail-general.component.jsx
index e2cecb4f5..99358d805 100644
--- a/client/src/components/jobs-detail-general/jobs-detail-general.component.jsx
+++ b/client/src/components/jobs-detail-general/jobs-detail-general.component.jsx
@@ -1,302 +1,294 @@
-import {
- Col,
- Form,
- Input,
- InputNumber,
- Row,
- Select,
- Space,
- Switch,
-} from "antd";
+import {Col, Form, Input, InputNumber, Row, Select, Space, 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 { selectBodyshop } from "../../redux/user/user.selectors";
+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 FormDatePicker from "../form-date-picker/form-date-picker.component";
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
import FormItemEmail from "../form-items-formatted/email-form-item.component";
-import FormItemPhone, {
- PhoneItemFormatterValidation,
-} from "../form-items-formatted/phone-form-item.component";
+import FormItemPhone, {PhoneItemFormatterValidation,} from "../form-items-formatted/phone-form-item.component";
import Car from "../job-damage-visual/job-damage-visual.component";
import JobsDetailChangeEstimator from "../jobs-detail-change-estimator/jobs-detail-change-estimator.component";
import JobsDetailChangeFileHandler from "../jobs-detail-change-filehandler/jobs-detail-change-filehandler.component";
import FormRow from "../layout-form-row/layout-form-row.component";
+
const mapStateToProps = createStructuredSelector({
- jobRO: selectJobReadOnly,
- bodyshop: selectBodyshop,
+ jobRO: selectJobReadOnly,
+ bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
- //setUserLanguage: language => dispatch(setUserLanguage(language))
+ //setUserLanguage: language => dispatch(setUserLanguage(language))
});
-const lossColFields = { sm: { span: 24 }, md: { span: 18 }, lg: { span: 20 } };
-const lossColDamage = { sm: { span: 24 }, md: { span: 6 }, lg: { span: 4 } };
-export function JobsDetailGeneral({ bodyshop, jobRO, job, form }) {
- const { getFieldValue } = form;
- const { t } = useTranslation();
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+const lossColFields = {sm: {span: 24}, md: {span: 18}, lg: {span: 20}};
+const lossColDamage = {sm: {span: 24}, md: {span: 6}, lg: {span: 4}};
-
-
-
-
-
-
-
-
-
-
- {t("jobs.fields.ins_ct_ln")}
-
-
- }
- name="ins_ct_ln"
- >
-
-
-
-
-
-
- PhoneItemFormatterValidation(getFieldValue, "ins_ph1"),
- ]}
- >
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {job.area_of_damage ? (
-
- ) : (
- t("jobs.errors.nodamage")
- )}
-
-
+export function JobsDetailGeneral({bodyshop, jobRO, job, form}) {
+ const {getFieldValue} = form;
+ const {t} = useTranslation();
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
- {t("jobs.fields.est_ct_fn")}
-
-
- }
- name="est_ct_fn"
- >
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+ {t("jobs.fields.ins_ct_ln")}
+
+
+ }
+ name="ins_ct_ln"
+ >
+
+
+
+
+
+
+ PhoneItemFormatterValidation(getFieldValue, "ins_ph1"),
+ ]}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {job.area_of_damage ? (
+
+ ) : (
+ t("jobs.errors.nodamage")
+ )}
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
+
+
+
+
+
+ {t("jobs.fields.est_ct_fn")}
+
+
+ }
+ name="est_ct_fn"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
}
+
export default connect(mapStateToProps, mapDispatchToProps)(JobsDetailGeneral);
diff --git a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.addevent.jsx b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.addevent.jsx
deleted file mode 100644
index 0c7ad08dc..000000000
--- a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.addevent.jsx
+++ /dev/null
@@ -1,163 +0,0 @@
-import { useMutation } from "@apollo/client";
-import {
- Button,
- Card,
- Form,
- Input,
- Menu,
- notification,
- Popover,
- Select,
- Space,
-} from "antd";
-import moment from "moment";
-import React, { useState } from "react";
-import { useTranslation } from "react-i18next";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { logImEXEvent } from "../../firebase/firebase.utils";
-import { INSERT_MANUAL_APPT } from "../../graphql/appointments.queries";
-import { selectBodyshop } from "../../redux/user/user.selectors";
-import FormDateTimePickerComponent from "../form-date-time-picker/form-date-time-picker.component";
-
-const mapStateToProps = createStructuredSelector({
- bodyshop: selectBodyshop,
-});
-const mapDispatchToProps = (dispatch) => ({
- //setUserLanguage: language => dispatch(setUserLanguage(language))
-});
-export default connect(
- mapStateToProps,
- mapDispatchToProps
-)(JobsDetailHeaderAddEvent);
-
-export function JobsDetailHeaderAddEvent({ bodyshop, jobid, ...props }) {
- const { t } = useTranslation();
- const [insertAppointment] = useMutation(INSERT_MANUAL_APPT);
-
- const [loading, setLoading] = useState(false);
- const [form] = Form.useForm();
- const [visibility, setVisibility] = useState(false);
-
- const handleFinish = async (values) => {
- logImEXEvent("schedule_manual_event");
-
- setLoading(true);
- try {
- insertAppointment({
- variables: {
- apt: { ...values, isintake: false, jobid, bodyshopid: bodyshop.id },
- },
- refetchQueries: ["QUERY_ALL_ACTIVE_APPOINTMENTS"],
- });
- notification.open({
- type: "success",
- message: t("appointments.successes.created"),
- });
- } catch (error) {
- console.log(error);
- } finally {
- setLoading(false);
- setVisibility(false);
- }
- };
-
- const overlay = (
-
-
-
-
-
-
-
-
-
- {
- const start = form.getFieldValue("start");
- form.setFieldsValue({ end: start.add(30, "minutes") });
- }}
- />
-
- ({
- async validator(rule, value) {
- if (value) {
- const { start } = form.getFieldsValue();
- if (moment(start).isAfter(moment(value))) {
- return Promise.reject(
- t("employees.labels.endmustbeafterstart")
- );
- } else {
- return Promise.resolve();
- }
- } else {
- return Promise.resolve();
- }
- },
- }),
- ]}
- >
-
-
-
-
-
-
-
-
- {t("general.actions.save")}
-
- setVisibility(false)}>
- {t("general.actions.cancel")}
-
-
-
-
-
- );
-
- const handleClick = (e) => {
- setVisibility(true);
- };
-
- return (
-
-
- {t("appointments.labels.manualevent")}
-
-
- );
-}
diff --git a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.addtoproduction.util.jsx b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.addtoproduction.util.jsx
index 90c8ebd8b..91ee42257 100644
--- a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.addtoproduction.util.jsx
+++ b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.addtoproduction.util.jsx
@@ -1,47 +1,47 @@
-import { notification } from "antd";
+import {notification} from "antd";
import i18n from "i18next";
-import { logImEXEvent } from "../../firebase/firebase.utils";
-import { UPDATE_JOB } from "../../graphql/jobs.queries";
-import { insertAuditTrail } from "../../redux/application/application.actions";
-import { store } from "../../redux/store";
+import {logImEXEvent} from "../../firebase/firebase.utils";
+import {UPDATE_JOB} from "../../graphql/jobs.queries";
+import {insertAuditTrail} from "../../redux/application/application.actions";
+import {store} from "../../redux/store";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
export default function AddToProduction(
- apolloClient,
- jobId,
- completionCallback,
- remove = false
+ apolloClient,
+ jobId,
+ completionCallback,
+ remove = false
) {
- logImEXEvent("job_add_to_production");
+ logImEXEvent("job_add_to_production");
- //get a list of all fields on the job
- apolloClient
- .mutate({
- mutation: UPDATE_JOB,
- variables: { jobId: jobId, job: { inproduction: !remove } },
- })
- .then((res) => {
- notification["success"]({
- message: i18n.t("jobs.successes.save"),
- });
-
- store.dispatch(
- insertAuditTrail({
- jobid: jobId,
- operation: AuditTrailMapping.jobinproductionchange(!remove),
+ //get a list of all fields on the job
+ apolloClient
+ .mutate({
+ mutation: UPDATE_JOB,
+ variables: {jobId: jobId, job: {inproduction: !remove}},
})
- );
- if (completionCallback) completionCallback();
- })
- .catch((error) => {
- notification["errors"]({
- message: i18n.t("jobs.errors.saving", {
- error: JSON.stringify(error),
- }),
- });
- });
+ .then((res) => {
+ notification["success"]({
+ message: i18n.t("jobs.successes.save"),
+ });
+
+ store.dispatch(
+ insertAuditTrail({
+ jobid: jobId,
+ operation: AuditTrailMapping.jobinproductionchange(!remove),
+ })
+ );
+ if (completionCallback) completionCallback();
+ })
+ .catch((error) => {
+ notification["errors"]({
+ message: i18n.t("jobs.errors.saving", {
+ error: JSON.stringify(error),
+ }),
+ });
+ });
+
+ //insert the new job. call the callback with the returned ID when done.
- //insert the new job. call the callback with the returned ID when done.
- return;
}
diff --git a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx
index e3f78ef69..c15c1e217 100644
--- a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx
+++ b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx
@@ -1,596 +1,1065 @@
-import { DownCircleFilled } from "@ant-design/icons";
-import { useApolloClient, useMutation } from "@apollo/client";
-import {
- Button,
- Dropdown,
- Form,
- Menu,
- Popconfirm,
- Popover,
- Select,
- notification,
-} from "antd";
-import React, { useMemo } from "react";
-import { useTranslation } from "react-i18next";
-import { connect } from "react-redux";
-import { Link, useHistory } from "react-router-dom";
-import { createStructuredSelector } from "reselect";
-import { logImEXEvent } from "../../firebase/firebase.utils";
-import { CANCEL_APPOINTMENTS_BY_JOB_ID } from "../../graphql/appointments.queries";
-import { DELETE_JOB, UPDATE_JOB, VOID_JOB } from "../../graphql/jobs.queries";
-import { insertAuditTrail } from "../../redux/application/application.actions";
-import { selectJobReadOnly } from "../../redux/application/application.selectors";
-import { setModalContext } from "../../redux/modals/modals.actions";
-import {
- selectBodyshop,
- selectCurrentUser,
-} from "../../redux/user/user.selectors";
+import {DownCircleFilled} from "@ant-design/icons";
+import {useApolloClient, useMutation} from "@apollo/client";
+import {Button, Card, Dropdown, Form, Input, Modal, notification, Popconfirm, Popover, Select, Space,} from "antd";
+import React, {useMemo, useState} from "react";
+import {useTranslation} from "react-i18next";
+import {connect} from "react-redux";
+import {Link, useNavigate} from "react-router-dom";
+import {createStructuredSelector} from "reselect";
+import {auth, logImEXEvent} from "../../firebase/firebase.utils";
+import {CANCEL_APPOINTMENTS_BY_JOB_ID, INSERT_MANUAL_APPT} from "../../graphql/appointments.queries";
+import {DELETE_JOB, UPDATE_JOB, VOID_JOB} from "../../graphql/jobs.queries";
+import {insertAuditTrail} from "../../redux/application/application.actions";
+import {selectJobReadOnly} from "../../redux/application/application.selectors";
+import {setModalContext} from "../../redux/modals/modals.actions";
+import {selectBodyshop, selectCurrentUser,} from "../../redux/user/user.selectors";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
import RbacWrapper from "../rbac-wrapper/rbac-wrapper.component";
-import JobsDetailHeaderActionsAddevent from "./jobs-detail-header-actions.addevent";
import AddToProduction from "./jobs-detail-header-actions.addtoproduction.util";
-import JobsDetaiLheaderCsi from "./jobs-detail-header-actions.csi.component";
import DuplicateJob from "./jobs-detail-header-actions.duplicate.util";
-import JobsDetailHeaderActionsExportcustdataComponent from "./jobs-detail-header-actions.exportcustdata.component";
+import axios from "axios";
+import {setEmailOptions} from "../../redux/email/email.actions";
+import {openChatByPhone, setMessage} from "../../redux/messaging/messaging.actions";
+import {GET_CURRENT_QUESTIONSET_ID, INSERT_CSI} from "../../graphql/csi.queries";
+import {TemplateList} from "../../utils/TemplateConstants";
+import parsePhoneNumber from "libphonenumber-js";
+import {HasFeatureAccess} from "../feature-wrapper/feature-wrapper.component";
+import {DateTimeFormatter} from "../../utils/DateFormatter";
+import FormDateTimePickerComponent from "../form-date-time-picker/form-date-time-picker.component";
+import dayjs from "../../utils/day";
+import {useSplitTreatments} from "@splitsoftware/splitio-react";
const mapStateToProps = createStructuredSelector({
- bodyshop: selectBodyshop,
- jobRO: selectJobReadOnly,
- currentUser: selectCurrentUser,
+ bodyshop: selectBodyshop,
+ jobRO: selectJobReadOnly,
+ currentUser: selectCurrentUser,
});
const mapDispatchToProps = (dispatch) => ({
- setScheduleContext: (context) =>
- dispatch(setModalContext({ context: context, modal: "schedule" })),
- setBillEnterContext: (context) =>
- dispatch(setModalContext({ context: context, modal: "billEnter" })),
- setPaymentContext: (context) =>
- dispatch(setModalContext({ context: context, modal: "payment" })),
- setJobCostingContext: (context) =>
- dispatch(setModalContext({ context: context, modal: "jobCosting" })),
- setTimeTicketContext: (context) =>
- dispatch(setModalContext({ context: context, modal: "timeTicket" })),
- setTimeTicketTaskContext: (context) =>
- dispatch(setModalContext({ context: context, modal: "timeTicketTask" })),
- setCardPaymentContext: (context) =>
- dispatch(setModalContext({ context: context, modal: "cardPayment" })),
- insertAuditTrail: ({ jobid, operation }) =>
- dispatch(insertAuditTrail({ jobid, operation })),
+ setScheduleContext: (context) =>
+ dispatch(setModalContext({context: context, modal: "schedule"})),
+ setBillEnterContext: (context) =>
+ dispatch(setModalContext({context: context, modal: "billEnter"})),
+ setPaymentContext: (context) =>
+ dispatch(setModalContext({context: context, modal: "payment"})),
+ setJobCostingContext: (context) =>
+ dispatch(setModalContext({context: context, modal: "jobCosting"})),
+ setTimeTicketContext: (context) =>
+ dispatch(setModalContext({context: context, modal: "timeTicket"})),
+ setCardPaymentContext: (context) =>
+ dispatch(setModalContext({context: context, modal: "cardPayment"})),
+ insertAuditTrail: ({jobid, operation}) =>
+ dispatch(insertAuditTrail({jobid, operation})),
+ setTimeTicketTaskContext: (context) =>
+ dispatch(setModalContext({context: context, modal: "timeTicketTask"})),
+ setEmailOptions: (e) => dispatch(setEmailOptions(e)),
+ openChatByPhone: (phone) => dispatch(openChatByPhone(phone)),
+ setMessage: (text) => dispatch(setMessage(text)),
});
export function JobsDetailHeaderActions({
- job,
- bodyshop,
- currentUser,
- refetch,
- setScheduleContext,
- setBillEnterContext,
- setPaymentContext,
- setJobCostingContext,
- jobRO,
- setTimeTicketContext,
- setTimeTicketTaskContext,
- setCardPaymentContext,
- insertAuditTrail,
-}) {
- const { t } = useTranslation();
- const client = useApolloClient();
- const history = useHistory();
- const [deleteJob] = useMutation(DELETE_JOB);
- const [updateJob] = useMutation(UPDATE_JOB);
- const [voidJob] = useMutation(VOID_JOB);
- const [cancelAllAppointments] = useMutation(CANCEL_APPOINTMENTS_BY_JOB_ID);
- const jobInProduction = useMemo(() => {
- return bodyshop.md_ro_statuses.production_statuses.includes(job.status);
- }, [job, bodyshop.md_ro_statuses.production_statuses]);
+ job,
+ bodyshop,
+ currentUser,
+ refetch,
+ setScheduleContext,
+ setBillEnterContext,
+ setPaymentContext,
+ setJobCostingContext,
+ jobRO,
+ setTimeTicketContext,
+ setCardPaymentContext,
+ insertAuditTrail,
+ setEmailOptions,
+ openChatByPhone,
+ setMessage,
+ setTimeTicketTaskContext,
+ }) {
+ const {t} = useTranslation();
+ const client = useApolloClient();
+ const history = useNavigate();
+ const [form] = Form.useForm();
+ const [loading, setLoading] = useState(false);
+ const [isCancelScheduleModalVisible, setIsCancelScheduleModalVisible] = useState(false);
+ const [insertAppointment] = useMutation(INSERT_MANUAL_APPT);
+ const [deleteJob] = useMutation(DELETE_JOB);
+ const [insertCsi] = useMutation(INSERT_CSI);
+ const [updateJob] = useMutation(UPDATE_JOB);
+ const [voidJob] = useMutation(VOID_JOB);
+ const [cancelAllAppointments] = useMutation(CANCEL_APPOINTMENTS_BY_JOB_ID);
- const jobInPreProduction = useMemo(() => {
- return bodyshop.md_ro_statuses.pre_production_statuses.includes(job.status);
- }, [job.status, bodyshop.md_ro_statuses.pre_production_statuses]);
-
- const jobInPostProduction = useMemo(() => {
- return bodyshop.md_ro_statuses.post_production_statuses.includes(
- job.status
- );
- }, [job.status, bodyshop.md_ro_statuses.post_production_statuses]);
-
- const handleAlertToggle = (e) => {
- logImEXEvent("production_toggle_alert");
- //e.stopPropagation();
- updateJob({
- variables: {
- jobId: job.id,
- job: {
- production_vars: {
- ...job.production_vars,
- alert:
- !!job.production_vars && !!job.production_vars.alert
- ? !job.production_vars.alert
- : true,
- },
- },
- },
+ const {treatments: {ImEXPay}} = useSplitTreatments({
+ attributes: {},
+ names: ["ImEXPay"],
+ splitKey: bodyshop && bodyshop.imexshopid,
});
- insertAuditTrail({
- jobid: job.id,
- operation: AuditTrailMapping.alertToggle(
- !!job.production_vars && !!job.production_vars.alert
- ? !job.production_vars.alert
- : true
- ),
- });
- };
- const handleSuspend = (e) => {
- logImEXEvent("production_toggle_alert");
- //e.stopPropagation();
- updateJob({
- variables: {
- jobId: job.id,
- job: {
- suspended: !job.suspended,
- },
- },
- });
- };
- const statusmenu = (
-
- );
- return (
-
-
- {t("general.labels.actions")}
+ {t("menus.jobsactions.admin")}
+
+ }
+ );
-
-
-
- );
+ menuItems.push(
+ {
+ key: 'exportcustdata',
+ disabled: !job.converted,
+ label: t("jobs.actions.exportcustdata"),
+ onClick: handleExportCustData
+ }
+ );
+
+ if (HasFeatureAccess({featureName: "csi", bodyshop})) {
+ const children = [
+ {
+ key: 'email',
+ disabled: !!!job.ownr_ea,
+ label: t("general.labels.email"),
+ onClick: handleCreateCsi
+ },
+ {
+ key: 'text',
+ disabled: !!!job.ownr_ph1,
+ label: t("general.labels.text"),
+ onClick: handleCreateCsi
+ },
+ {
+ key: 'generate',
+ disabled: job.csiinvites && job.csiinvites.length > 0,
+ label: t("jobs.actions.generatecsi"),
+ onClick: handleCreateCsi
+ },
+ ];
+
+ if (job.csiinvites.length) {
+ children.push(
+ {
+ type: "divider"
+ },
+ ...job.csiinvites.map((item, idx) => {
+ return item.completedon ?
+ {
+ key: idx,
+ label:
+ {item.completedon}
+
+ } :
+ {
+ key: idx,
+ onClick: () => {
+ navigator.clipboard.writeText(
+ `${window.location.protocol}//${window.location.host}/csi/${item.id}`
+ );
+ },
+ label: t("general.actions.copylink")
+ }
+ }),
+ )
+ }
+ menuItems.push(
+ {
+ key: 'sendcsi',
+ label: t("jobs.actions.sendcsi"),
+ disabled: !job.converted,
+ children
+ }
+ );
+ }
+
+ menuItems.push({
+ key: 'jobcosting',
+ disabled: !job.converted,
+ label: t("jobs.labels.jobcosting"),
+ onClick: () => {
+ logImEXEvent("job_header_job_costing");
+
+ setJobCostingContext({
+ actions: {refetch: refetch},
+ context: {
+ jobId: job.id,
+ },
+ });
+ }
+ }
+ );
+
+ if (job && !job.converted) {
+ menuItems.push(
+ {
+ key: 'deletejob',
+ label: e.stopPropagation()}
+ onConfirm={handleDeleteJob}
+ >
+ {t("menus.jobsactions.deletejob")}
+
+ }
+ );
+ }
+
+ menuItems.push(
+ {
+ key: 'manualevent',
+ onClick: (e) => {
+ setVisibility(true);
+ },
+ label: t("appointments.labels.manualevent")
+ }
+ )
+
+ if (!jobRO && job.converted) {
+ menuItems.push({
+ key: 'voidjob',
+ label:
+ e.stopPropagation()}
+ onConfirm={handleVoidJob}
+ >
+ {t("menus.jobsactions.void")}
+
+
+ });
+ }
+
+ const menu = {
+ items: menuItems,
+ key: 'popovermenu'
+ }
+
+ return (
+ <>
+
+ {t("general.actions.cancel")}
+ ,
+
+ {t("appointments.actions.cancel")}
+ ,
+ ]}
+ >
+
+
+
+
+
+
+ {t("general.labels.actions")}
+
+
+
+
+ >
+ );
}
+
export default connect(
- mapStateToProps,
- mapDispatchToProps
+ mapStateToProps,
+ mapDispatchToProps
)(JobsDetailHeaderActions);
diff --git a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.csi.component.jsx b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.csi.component.jsx
deleted file mode 100644
index bb35f3475..000000000
--- a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.csi.component.jsx
+++ /dev/null
@@ -1,240 +0,0 @@
-import { useApolloClient, useMutation } from "@apollo/client";
-import { Menu, notification } from "antd";
-import parsePhoneNumber from "libphonenumber-js";
-import React from "react";
-import { useTranslation } from "react-i18next";
-import { connect } from "react-redux";
-import { Link } from "react-router-dom";
-import { createStructuredSelector } from "reselect";
-import { logImEXEvent } from "../../firebase/firebase.utils";
-import {
- GET_CURRENT_QUESTIONSET_ID,
- INSERT_CSI,
-} from "../../graphql/csi.queries";
-import { setEmailOptions } from "../../redux/email/email.actions";
-import {
- openChatByPhone,
- setMessage,
-} from "../../redux/messaging/messaging.actions";
-import { selectBodyshop } from "../../redux/user/user.selectors";
-import { DateTimeFormatter } from "../../utils/DateFormatter";
-import { TemplateList } from "../../utils/TemplateConstants";
-import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
-
-const mapStateToProps = createStructuredSelector({
- //currentUser: selectCurrentUser'
- bodyshop: selectBodyshop,
-});
-const mapDispatchToProps = (dispatch) => ({
- setEmailOptions: (e) => dispatch(setEmailOptions(e)),
- openChatByPhone: (phone) => dispatch(openChatByPhone(phone)),
- setMessage: (text) => dispatch(setMessage(text)),
-});
-
-export function JobsDetailHeaderCsi({
- setEmailOptions,
- bodyshop,
- job,
- openChatByPhone,
- setMessage,
- ...props
-}) {
- const { t } = useTranslation();
- const [insertCsi] = useMutation(INSERT_CSI);
- const client = useApolloClient();
-
- const handleCreateCsi = async (e) => {
- logImEXEvent("job_create_csi");
-
- //Is tehre already a CSI?
- if (!job.csiinvites || job.csiinvites.length === 0) {
- const questionSetResult = await client.query({
- query: GET_CURRENT_QUESTIONSET_ID,
- });
-
- if (questionSetResult.data.csiquestions.length > 0) {
- const result = await insertCsi({
- variables: {
- csiInput: {
- jobid: job.id,
- bodyshopid: bodyshop.id,
- questionset: questionSetResult.data.csiquestions[0].id,
- relateddata: {
- job: {
- id: job.id,
- ownr_fn: job.ownr_fn,
- ro_number: job.ro_number,
- v_model_yr: job.v_model_yr,
- v_make_desc: job.v_make_desc,
- v_model_desc: job.v_model_desc,
- },
- bodyshop: {
- city: bodyshop.city,
- email: bodyshop.email,
- state: bodyshop.state,
- country: bodyshop.country,
- address1: bodyshop.address1,
- address2: bodyshop.address2,
- shopname: bodyshop.shopname,
- zip_post: bodyshop.zip_post,
- logo_img_path: bodyshop.logo_img_path,
- },
- },
- },
- },
- refetchQueries: ["GET_JOB_BY_PK"],
- awaitRefetchQueries: true,
- });
-
- if (!!!result.errors) {
- notification["success"]({ message: t("csi.successes.created") });
- } else {
- notification["error"]({
- message: t("csi.errors.creating", {
- message: JSON.stringify(result.errors),
- }),
- });
- return;
- }
- if (e.key === "email")
- setEmailOptions({
- jobid: job.id,
- messageOptions: {
- to: [job.ownr_ea],
- replyTo: bodyshop.email,
- },
- template: {
- name: TemplateList("job_special").csi_invitation_action.key,
- variables: {
- id: result.data.insert_csi.returning[0].id,
- },
- },
- });
-
- if (e.key === "text") {
- const p = parsePhoneNumber(job.ownr_ph1, "CA");
- if (p && p.isValid()) {
- openChatByPhone({
- phone_num: p.formatInternational(),
- jobid: job.id,
- });
- setMessage(
- `${window.location.protocol}//${window.location.host}/csi/${result.data.insert_csi.returning[0].id}`
- );
- } else {
- notification["error"]({
- message: t("messaging.error.invalidphone"),
- });
- }
- }
- if (e.key === "generate") {
- //copy it to clipboard.
- navigator.clipboard.writeText(
- `${window.location.protocol}//${window.location.host}/csi/${result.data.insert_csi.returning[0].id}`
- );
- }
- } else {
- notification["error"]({
- message: t("csi.errors.notconfigured"),
- });
- }
- } else {
- if (e.key === "email")
- setEmailOptions({
- jobid: job.id,
- messageOptions: {
- to: [job.ownr_ea],
- replyTo: bodyshop.email,
- },
- template: {
- name: TemplateList("job_special").csi_invitation_action.key,
- variables: {
- id: job.csiinvites[0].id,
- },
- },
- });
-
- if (e.key === "text") {
- const p = parsePhoneNumber(job.ownr_ph1, "CA");
- if (p && p.isValid()) {
- openChatByPhone({
- phone_num: p.formatInternational(),
- jobid: job.id,
- });
- setMessage(
- `${window.location.protocol}//${window.location.host}/csi/${job.csiinvites[0].id}`
- );
- } else {
- notification["error"]({
- message: t("messaging.error.invalidphone"),
- });
- }
- }
-
- if (e.key === "generate") {
- //copy it to clipboard.
- navigator.clipboard.writeText(
- `${window.location.protocol}//${window.location.host}/csi/${job.csiinvites[0].id}`
- );
- }
- }
- };
-
- if (!HasFeatureAccess({ featureName: "csi", bodyshop })) return <>>;
-
- return (
-
-
- {t("general.labels.email")}
-
-
- {t("general.labels.text")}
-
- 0}
- >
- {t("jobs.actions.generatecsi")}
-
-
- {job.csiinvites.map((item, idx) => {
- return item.completedon ? (
-
-
- {item.completedon}
-
-
- ) : (
- {
- navigator.clipboard.writeText(
- `${window.location.protocol}//${window.location.host}/csi/${item.id}`
- );
- }}
- >
- {t("general.actions.copylink")}
-
- );
- })}
-
- );
-}
-export default connect(
- mapStateToProps,
- mapDispatchToProps
-)(JobsDetailHeaderCsi);
diff --git a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.duplicate.util.js b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.duplicate.util.js
index 503bcc740..ae01c4f5e 100644
--- a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.duplicate.util.js
+++ b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.duplicate.util.js
@@ -1,138 +1,138 @@
import Axios from "axios";
import _ from "lodash";
-import { logImEXEvent } from "../../firebase/firebase.utils";
-import { INSERT_NEW_JOB, QUERY_JOB_FOR_DUPE } from "../../graphql/jobs.queries";
-import moment from "moment";
+import {logImEXEvent} from "../../firebase/firebase.utils";
+import {INSERT_NEW_JOB, QUERY_JOB_FOR_DUPE} from "../../graphql/jobs.queries";
+import dayjs from "../../utils/day";
import i18n from "i18next";
export default async function DuplicateJob(
- apolloClient,
- jobId,
- config,
- completionCallback,
- keepJobLines = false
+ apolloClient,
+ jobId,
+ config,
+ completionCallback,
+ keepJobLines = false
) {
- logImEXEvent("job_duplicate");
+ logImEXEvent("job_duplicate");
- const { defaultOpenStatus } = config;
- //get a list of all fields on the job
- const res = await apolloClient.query({
- query: QUERY_JOB_FOR_DUPE,
- variables: { id: jobId },
- });
+ const {defaultOpenStatus} = config;
+ //get a list of all fields on the job
+ const res = await apolloClient.query({
+ query: QUERY_JOB_FOR_DUPE,
+ variables: {id: jobId},
+ });
- const { jobs_by_pk } = res.data;
- const existingJob = _.cloneDeep(jobs_by_pk);
- delete existingJob.__typename;
- delete existingJob.id;
- delete existingJob.createdat;
- delete existingJob.updatedat;
- delete existingJob.cieca_stl;
- delete existingJob.cieca_ttl;
+ const {jobs_by_pk} = res.data;
+ const existingJob = _.cloneDeep(jobs_by_pk);
+ delete existingJob.__typename;
+ delete existingJob.id;
+ delete existingJob.createdat;
+ delete existingJob.updatedat;
+ delete existingJob.cieca_stl;
+ delete existingJob.cieca_ttl;
- const newJob = {
- ...existingJob,
- status: defaultOpenStatus,
- };
+ const newJob = {
+ ...existingJob,
+ status: defaultOpenStatus,
+ };
- const _tempLines = _.cloneDeep(existingJob.joblines);
- _tempLines.forEach((line) => {
- delete line.id;
- delete line.__typename;
- line.manual_line = true;
- });
- newJob.joblines = keepJobLines ? _tempLines : [];
+ const _tempLines = _.cloneDeep(existingJob.joblines);
+ _tempLines.forEach((line) => {
+ delete line.id;
+ delete line.__typename;
+ line.manual_line = true;
+ });
+ newJob.joblines = keepJobLines ? _tempLines : [];
- delete newJob.joblines;
- newJob.joblines = keepJobLines ? { data: _tempLines } : null;
+ delete newJob.joblines;
+ newJob.joblines = keepJobLines ? {data: _tempLines} : null;
- const res2 = await apolloClient.mutate({
- mutation: INSERT_NEW_JOB,
- variables: { job: [newJob] },
- });
- await Axios.post("/job/totalsssu", {
- id: res2.data.insert_jobs.returning[0].id,
- });
+ const res2 = await apolloClient.mutate({
+ mutation: INSERT_NEW_JOB,
+ variables: {job: [newJob]},
+ });
+ await Axios.post("/job/totalsssu", {
+ id: res2.data.insert_jobs.returning[0].id,
+ });
- if (completionCallback)
- completionCallback(res2.data.insert_jobs.returning[0].id);
+ if (completionCallback)
+ completionCallback(res2.data.insert_jobs.returning[0].id);
+
+ //insert the new job. call the callback with the returned ID when done.
- //insert the new job. call the callback with the returned ID when done.
- return;
}
export async function CreateIouForJob(
- apolloClient,
- jobId,
- config,
- jobLinesToKeep
+ apolloClient,
+ jobId,
+ config,
+ jobLinesToKeep
) {
- logImEXEvent("job_create_iou");
+ logImEXEvent("job_create_iou");
- const { status } = config;
- //get a list of all fields on the job
- const res = await apolloClient.query({
- query: QUERY_JOB_FOR_DUPE,
- variables: { id: jobId },
- });
+ const {status} = config;
+ //get a list of all fields on the job
+ const res = await apolloClient.query({
+ query: QUERY_JOB_FOR_DUPE,
+ variables: {id: jobId},
+ });
- const { jobs_by_pk } = res.data;
- const existingJob = _.cloneDeep(jobs_by_pk);
- delete existingJob.__typename;
- delete existingJob.id;
- delete existingJob.createdat;
- delete existingJob.updatedat;
- delete existingJob.cieca_stl;
- delete existingJob.cieca_ttl;
+ const {jobs_by_pk} = res.data;
+ const existingJob = _.cloneDeep(jobs_by_pk);
+ delete existingJob.__typename;
+ delete existingJob.id;
+ delete existingJob.createdat;
+ delete existingJob.updatedat;
+ delete existingJob.cieca_stl;
+ delete existingJob.cieca_ttl;
- const newJob = {
- ...existingJob,
+ const newJob = {
+ ...existingJob,
- converted: true,
- status: status,
- iouparent: jobId,
- date_open: moment(),
- audit_trails: {
- data: [
- {
- useremail: config.useremail,
- bodyshopid: config.bodyshopid,
- operation: i18n.t("audit_trail.messages.jobioucreated"),
+ converted: true,
+ status: status,
+ iouparent: jobId,
+ date_open: dayjs(),
+ audit_trails: {
+ data: [
+ {
+ useremail: config.useremail,
+ bodyshopid: config.bodyshopid,
+ operation: i18n.t("audit_trail.messages.jobioucreated"),
+ },
+ ],
},
- ],
- },
- };
+ };
- const selectedJoblinesIds = jobLinesToKeep.map((l) => l.id);
+ const selectedJoblinesIds = jobLinesToKeep.map((l) => l.id);
- const _tempLines = _.cloneDeep(existingJob.joblines).filter((l) =>
- selectedJoblinesIds.includes(l.id)
- );
- _tempLines.forEach((line) => {
- delete line.id;
- delete line.__typename;
- line.oem_partno = `${line.oem_partno ? `${line.oem_partno} - ` : ``}IOU $${
- (line.act_price && line.act_price.toFixed(2)) || 0
- }/${line.mod_lb_hrs || 0}hrs`;
- line.act_price = 0;
- line.mod_lb_hrs = 0;
- line.manual_line = true;
- });
+ const _tempLines = _.cloneDeep(existingJob.joblines).filter((l) =>
+ selectedJoblinesIds.includes(l.id)
+ );
+ _tempLines.forEach((line) => {
+ delete line.id;
+ delete line.__typename;
+ line.oem_partno = `${line.oem_partno ? `${line.oem_partno} - ` : ``}IOU $${
+ (line.act_price && line.act_price.toFixed(2)) || 0
+ }/${line.mod_lb_hrs || 0}hrs`;
+ line.act_price = 0;
+ line.mod_lb_hrs = 0;
+ line.manual_line = true;
+ });
- delete newJob.joblines;
- newJob.joblines = { data: _tempLines };
+ delete newJob.joblines;
+ newJob.joblines = {data: _tempLines};
- const res2 = await apolloClient.mutate({
- mutation: INSERT_NEW_JOB,
- variables: { job: [newJob] },
- });
+ const res2 = await apolloClient.mutate({
+ mutation: INSERT_NEW_JOB,
+ variables: {job: [newJob]},
+ });
- Axios.post("/job/totalsssu", {
- id: res2.data.insert_jobs.returning[0].id,
- });
+ Axios.post("/job/totalsssu", {
+ id: res2.data.insert_jobs.returning[0].id,
+ });
- //insert the new job. call the callback with the returned ID when done.
+ //insert the new job. call the callback with the returned ID when done.
- return res2.data.insert_jobs.returning[0].id;
+ return res2.data.insert_jobs.returning[0].id;
}
diff --git a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.exportcustdata.component.jsx b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.exportcustdata.component.jsx
deleted file mode 100644
index 671d49929..000000000
--- a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.exportcustdata.component.jsx
+++ /dev/null
@@ -1,117 +0,0 @@
-import { Menu, notification } from "antd";
-import axios from "axios";
-import React from "react";
-import { useTranslation } from "react-i18next";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { auth, logImEXEvent } from "../../firebase/firebase.utils";
-import { selectBodyshop } from "../../redux/user/user.selectors";
-
-const mapStateToProps = createStructuredSelector({
- bodyshop: selectBodyshop,
-});
-const mapDispatchToProps = (dispatch) => ({});
-
-export function JobsDetailHeaderActionexportCustomerData({
- bodyshop,
- job,
- ...props
-}) {
- const { t } = useTranslation();
-
- const handleExportCustData = async (e) => {
- logImEXEvent("job_export_cust_data");
- let PartnerResponse;
- if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) {
- PartnerResponse = await axios.post(`/qbo/receivables`, {
- jobIds: [job.id],
- custDataOnly: true,
- });
- } else {
- //Default is QBD
-
- let QbXmlResponse;
- try {
- QbXmlResponse = await axios.post(
- "/accounting/qbxml/receivables",
- { jobIds: [job.id], custDataOnly: true },
- {
- headers: {
- Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
- },
- }
- );
- console.log("handle -> XML", QbXmlResponse);
- } catch (error) {
- console.log("Error getting QBXML from Server.", error);
- notification["error"]({
- message: t("jobs.errors.exporting", {
- error: "Unable to retrieve QBXML. " + JSON.stringify(error.message),
- }),
- });
-
- return;
- }
-
- //let PartnerResponse;
- try {
- PartnerResponse = await axios.post(
- "http://localhost:1337/qb/",
- QbXmlResponse.data,
- {
- headers: {
- Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
- },
- }
- );
- } catch (error) {
- console.log("Error connecting to quickbooks or partner.", error);
- notification["error"]({
- message: t("jobs.errors.exporting-partner"),
- });
-
- return;
- }
- }
- //Check to see if any of them failed. If they didn't don't execute the update.
- const failedTransactions = PartnerResponse.data.filter((r) => !r.success);
- if (failedTransactions.length > 0) {
- //Uh oh. At least one was no good.
- failedTransactions.forEach((ft) => {
- //insert failed export log
- notification.open({
- // key: "failedexports",
- type: "error",
- message: t("jobs.errors.exporting", {
- error: ft.errorMessage || "",
- }),
- });
- });
-
- //Handle Failures.
- } else {
- //Insert success export log.
-
- notification.open({
- type: "success",
- key: "jobsuccessexport",
- message: t("jobs.successes.exported"),
- });
- }
- };
-
- return (
-
- {t("jobs.actions.exportcustdata")}
-
- );
-}
-export default connect(
- mapStateToProps,
- mapDispatchToProps
-)(JobsDetailHeaderActionexportCustomerData);
diff --git a/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx b/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx
index 9ae08588d..49d4a45e7 100644
--- a/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx
+++ b/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx
@@ -1,281 +1,302 @@
-import {
- BranchesOutlined,
- ExclamationCircleFilled,
- PauseCircleOutlined,
- WarningFilled,
-} from "@ant-design/icons";
-import { Card, Col, Row, Space, Tag, Tooltip } from "antd";
-import React, { useState } from "react";
-import { useTranslation } from "react-i18next";
-import { connect } from "react-redux";
-import { Link } from "react-router-dom";
-import { createStructuredSelector } from "reselect";
-import { selectJobReadOnly } from "../../redux/application/application.selectors";
-import { setModalContext } from "../../redux/modals/modals.actions";
-import { selectBodyshop } from "../../redux/user/user.selectors";
+import {BranchesOutlined, ExclamationCircleFilled, PauseCircleOutlined, WarningFilled,} from "@ant-design/icons";
+import {Card, Col, Row, Space, Tag, Tooltip} from "antd";
+import React, {useState} from "react";
+import {useTranslation} from "react-i18next";
+import {connect} from "react-redux";
+import {Link} from "react-router-dom";
+import {createStructuredSelector} from "reselect";
+import {selectJobReadOnly} from "../../redux/application/application.selectors";
+import {setModalContext} from "../../redux/modals/modals.actions";
+import {selectBodyshop} from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
-import { DateTimeFormatter } from "../../utils/DateFormatter";
+import {DateTimeFormatter} from "../../utils/DateFormatter";
+import PhoneNumberFormatter from "../../utils/PhoneFormatter";
import ChatOpenButton from "../chat-open-button/chat-open-button.component";
import DataLabel from "../data-label/data-label.component";
import JobAltTransportChange from "../job-at-change/job-at-change.component";
import JobEmployeeAssignments from "../job-employee-assignments/job-employee-assignments.container";
import JobsRelatedRos from "../jobs-related-ros/jobs-related-ros.component";
-import { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
+import {OwnerNameDisplayFunction} from "../owner-name-display/owner-name-display.component";
import ProductionListColumnComment from "../production-list-columns/production-list-columns.comment.component";
-import ProductionListColumnProductionNote from "../production-list-columns/production-list-columns.productionnote.component";
+import ProductionListColumnProductionNote
+ from "../production-list-columns/production-list-columns.productionnote.component";
import VehicleVinDisplay from "../vehicle-vin-display/vehicle-vin-display.component";
import "./jobs-detail-header.styles.scss";
const mapStateToProps = createStructuredSelector({
- jobRO: selectJobReadOnly,
- bodyshop: selectBodyshop,
+ jobRO: selectJobReadOnly,
+ bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
- setPrintCenterContext: (context) =>
- dispatch(setModalContext({ context: context, modal: "printCenter" })),
+ setPrintCenterContext: (context) =>
+ dispatch(setModalContext({context: context, modal: "printCenter"})),
});
const colSpan = {
- xs: {
- span: 24,
- },
- sm: {
- span: 24,
- },
- md: {
- span: 12,
- },
- lg: {
- span: 6,
- },
- xl: {
- span: 6,
- },
+ xs: {
+ span: 24,
+ },
+ sm: {
+ span: 24,
+ },
+ md: {
+ span: 12,
+ },
+ lg: {
+ span: 6,
+ },
+ xl: {
+ span: 6,
+ },
};
-export function JobsDetailHeader({ job, bodyshop, disabled }) {
- const { t } = useTranslation();
- const [notesClamped, setNotesClamped] = useState(true);
- const vehicleTitle = `${job.v_model_yr || ""} ${job.v_color || ""}
+export function JobsDetailHeader({job, bodyshop, disabled}) {
+ const {t} = useTranslation();
+ const [notesClamped, setNotesClamped] = useState(true);
+ const vehicleTitle = `${job.v_model_yr || ""} ${job.v_color || ""}
${job.v_make_desc || ""}
${job.v_model_desc || ""}`.trim();
- const ownerTitle = OwnerNameDisplayFunction(job).trim();
+ const ownerTitle = OwnerNameDisplayFunction(job).trim();
- return (
-
-
-
-
-
-
- {job.status}
- {job.inproduction && (
-
- {t("jobs.labels.inproduction")}
-
- )}
- {job.suspended && (
-
- )}
- {job.iouparent && (
-
-
-
-
-
- )}
- {job.production_vars && job.production_vars.alert ? (
-
- ) : null}
- {job.status === bodyshop.md_ro_statuses.default_scheduled &&
- job.scheduled_in ? (
-
- {job.scheduled_in}
-
- ) : null}
-
-
-
-
-
-
- {job.ins_co_nm}
-
-
{job.clm_no}
-
- {job.po_number}
-
-
- {job.clm_total}
- /
- {job.owner_owing}
-
+ return (
+
+
+
+
+
+
+ {job.status}
+ {job.inproduction && (
+
+ {t("jobs.labels.inproduction")}
+
+ )}
+ {job.suspended && (
+
+ )}
+ {job.iouparent && (
+
+
+
+
+
+ )}
+ {job.production_vars && job.production_vars.alert ? (
+
+ ) : null}
+ {job.status === bodyshop.md_ro_statuses.default_scheduled &&
+ job.scheduled_in ? (
+
+ {job.scheduled_in}
+
+ ) : null}
+
+
+
+
+
+
+ {job.ins_co_nm}
+
+
{job.clm_no}
+
+ {job.po_number}
+
+
+ {job.clm_total}
+ /
+ {job.owner_owing}
+
-
- {job.alt_transport}
-
-
- {job.cccontracts.length > 0 && (
-
- {job.cccontracts.map((c) => (
- {`${c.agreementnumber} - ${c.courtesycar.fleetnumber} ${c.courtesycar.year} ${c.courtesycar.make} ${c.courtesycar.model}`}
- ))}
-
- )}
+
+ {job.alt_transport}
+
+
+ {job.cccontracts.length > 0 && (
+
+ {job.cccontracts.map((c) => (
+ {`${c.agreementnumber} - ${c.courtesycar.fleetnumber} ${c.courtesycar.year} ${c.courtesycar.make} ${c.courtesycar.model}`}
+ ))}
+
+ )}
-
-
-
+
+
+
-
- {job.special_coverage_policy && (
-
-
-
- {t("jobs.labels.specialcoveragepolicy")}
-
-
- )}
- {job.ca_gst_registrant && (
-
-
-
- {t("jobs.fields.ca_gst_registrant")}
-
-
- )}
-
-
-
-
-
-
- {ownerTitle.length > 0
- ? ownerTitle
- : t("owner.labels.noownerinfo")}
-
- }
- >
-
-
-
-
-
-
-
-
- {`${job.ownr_addr1 || ""} ${job.ownr_addr2 || ""} ${
- job.ownr_city || ""
- } ${job.ownr_st || ""} ${job.ownr_zip || ""}`}
-
-
- {job.ownr_ea || ""}
-
- {job.owner?.tax_number && (
-
- {job.owner?.tax_number || ""}
-
- )}
-
-
-
-
-
- {vehicleTitle.length > 0
- ? vehicleTitle
- : t("vehicles.labels.novehinfo")}
-
- ) : (
-
- )
- }
- >
-
-
- {`${job.plate_no || t("general.labels.na")} (${`${
- job.plate_st || t("general.labels.na")
- }`})`}
-
-
-
- {`${job.v_vin || t("general.labels.na")}`}
-
- {bodyshop.pbs_serialnumber || bodyshop.cdk_dealerid ? (
- job.v_vin.length !== 17 ? (
-
- ) : null
- ) : null}
-
-
- {job.regie_number || t("general.labels.na")}
-
-
-
-
- {job.vehicle && job.vehicle.notes && (
- setNotesClamped(!notesClamped)}
- >
- {job.vehicle.notes}
-
- )}
- {job.vehicle && job.vehicle.v_paint_codes && (
-
-
+
+ {job.special_coverage_policy && (
+
+
+
+ {t("jobs.labels.specialcoveragepolicy")}
+
+
+ )}
+ {job.ca_gst_registrant && (
+
+
+
+ {t("jobs.fields.ca_gst_registrant")}
+
+
+ )}
+
+
+
+
+
+
+ {ownerTitle.length > 0
+ ? ownerTitle
+ : t("owner.labels.noownerinfo")}
+ >
+ ) : (
+
+ {ownerTitle.length > 0
+ ? ownerTitle
+ : t("owner.labels.noownerinfo")}
+
+ )
+ }
+ >
+
+
+ {disabled ? (
+ {job.ownr_ph1}
+ ) : (
+
+ )}
+
+
+ {disabled ? (
+ {job.ownr_ph2}
+ ) : (
+
+ )}
+
+
+ {`${job.ownr_addr1 || ""} ${job.ownr_addr2 || ""} ${
+ job.ownr_city || ""
+ } ${job.ownr_st || ""} ${job.ownr_zip || ""}`}
+
+
+ {disabled ? (
+ <>{job.ownr_ea || ""}>
+ ) : job.ownr_ea ? (
+ {job.ownr_ea}
+ ) : null}
+
+ {job.owner?.tax_number && (
+
+ {job.owner?.tax_number || ""}
+
+ )}
+
+
+
+
+
+ {vehicleTitle.length > 0
+ ? vehicleTitle
+ : t("vehicles.labels.novehinfo")}{" "}
+ >
+ ) : (
+
+ {vehicleTitle.length > 0
+ ? vehicleTitle
+ : t("vehicles.labels.novehinfo")}
+
+ )
+ ) : (
+
+ )
+ }
+ >
+
+
+ {`${job.plate_no || t("general.labels.na")} (${`${
+ job.plate_st || t("general.labels.na")
+ }`})`}
+
+
+
+ {`${job.v_vin || t("general.labels.na")}`}
+
+ {bodyshop.pbs_serialnumber || bodyshop.cdk_dealerid ? (
+ job.v_vin?.length !== 17 ? (
+
+ ) : null
+ ) : null}
+
+
+ {job.regie_number || t("general.labels.na")}
+
+
+
+
+ {job.vehicle && job.vehicle.notes && (
+ setNotesClamped(!notesClamped)}
+ >
+ {job.vehicle.notes}
+
+ )}
+ {job.vehicle && job.vehicle.v_paint_codes && (
+
+
{Object.keys(job.vehicle.v_paint_codes)
- .filter(
- (key) =>
- job.vehicle.v_paint_codes[key] !== "" &&
- job.vehicle.v_paint_codes[key] !== null &&
- job.vehicle.v_paint_codes[key] !== undefined
- )
- .map((key, idx) => (
- {job.vehicle.v_paint_codes[key]}
- ))}
+ .filter(
+ (key) =>
+ job.vehicle.v_paint_codes[key] !== "" &&
+ job.vehicle.v_paint_codes[key] !== null &&
+ job.vehicle.v_paint_codes[key] !== undefined
+ )
+ .map((key, idx) => (
+ {job.vehicle.v_paint_codes[key]}
+ ))}
-
- )}
-
-
-
-
-
-
-
-
-
-
-
- );
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
+ );
}
export default connect(mapStateToProps, mapDispatchToProps)(JobsDetailHeader);
diff --git a/client/src/components/jobs-detail-labor/jobs-detail-labor.component.jsx b/client/src/components/jobs-detail-labor/jobs-detail-labor.component.jsx
index c03d9d2d4..10a16449f 100644
--- a/client/src/components/jobs-detail-labor/jobs-detail-labor.component.jsx
+++ b/client/src/components/jobs-detail-labor/jobs-detail-labor.component.jsx
@@ -1,108 +1,109 @@
-import { Col, Row } from "antd";
+import {Col, Row} from "antd";
import React from "react";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { selectJobReadOnly } from "../../redux/application/application.selectors";
+import {connect} from "react-redux";
+import {createStructuredSelector} from "reselect";
+import {selectJobReadOnly} from "../../redux/application/application.selectors";
import LaborAllocationsTableComponent from "../labor-allocations-table/labor-allocations-table.component";
import TimeTicketList from "../time-ticket-list/time-ticket-list.component";
import PayrollLaborAllocationsTable from "../labor-allocations-table/labor-allocations-table.payroll.component";
-import { selectBodyshop } from "../../redux/user/user.selectors";
-import { useTreatments } from "@splitsoftware/splitio-react";
+import {selectBodyshop} from "../../redux/user/user.selectors";
+import {useSplitTreatments} from "@splitsoftware/splitio-react";
const mapStateToProps = createStructuredSelector({
- jobRO: selectJobReadOnly,
- bodyshop: selectBodyshop,
+ jobRO: selectJobReadOnly,
+ bodyshop: selectBodyshop,
});
export default connect(mapStateToProps, null)(JobsDetailLaborContainer);
const ticketSpan = {
- xs: {
- span: 24,
- },
- sm: {
- span: 24,
- },
- md: {
- span: 24,
- },
- lg: {
- span: 24,
- },
- xl: {
- span: 16,
- },
+ xs: {
+ span: 24,
+ },
+ sm: {
+ span: 24,
+ },
+ md: {
+ span: 24,
+ },
+ lg: {
+ span: 24,
+ },
+ xl: {
+ span: 16,
+ },
};
const adjSpan = {
- xs: {
- span: 24,
- },
- sm: {
- span: 24,
- },
- md: {
- span: 24,
- },
- lg: {
- span: 24,
- },
- xl: {
- span: 8,
- },
+ xs: {
+ span: 24,
+ },
+ sm: {
+ span: 24,
+ },
+ md: {
+ span: 24,
+ },
+ lg: {
+ span: 24,
+ },
+ xl: {
+ span: 8,
+ },
};
export function JobsDetailLaborContainer({
- bodyshop,
- jobRO,
- job,
- jobId,
- joblines,
- timetickets,
- refetch,
- loading,
- techConsole,
- adjustments,
-}) {
- const { Enhanced_Payroll } = useTreatments(
- ["Enhanced_Payroll"],
- {},
- bodyshop.imexshopid
- );
+ bodyshop,
+ jobRO,
+ job,
+ jobId,
+ joblines,
+ timetickets,
+ refetch,
+ loading,
+ techConsole,
+ adjustments,
+ }) {
+ const {treatments: {Enhanced_Payroll}} = useSplitTreatments({
+ attributes: {},
+ names: ["Enhanced_Payroll"],
+ splitKey: bodyshop.imexshopid,
+ });
- return (
-
-
-
-
- {Enhanced_Payroll.treatment === "on" ? (
-
-
-
- ) : (
-
-
-
- )}
-
- );
+ return (
+
+
+
+
+
+ {Enhanced_Payroll.treatment === "on" ? (
+
+
+
+ ) : (
+
+
+
+ )}
+
+ );
}
diff --git a/client/src/components/jobs-detail-labor/jobs-detail-labor.container.jsx b/client/src/components/jobs-detail-labor/jobs-detail-labor.container.jsx
index 8434f3c22..8416ace4c 100644
--- a/client/src/components/jobs-detail-labor/jobs-detail-labor.container.jsx
+++ b/client/src/components/jobs-detail-labor/jobs-detail-labor.container.jsx
@@ -1,29 +1,29 @@
-import { useQuery } from "@apollo/client";
+import {useQuery} from "@apollo/client";
import React from "react";
-import { GET_LINE_TICKET_BY_PK } from "../../graphql/jobs-lines.queries";
+import {GET_LINE_TICKET_BY_PK} from "../../graphql/jobs-lines.queries";
import AlertComponent from "../alert/alert.component";
import JobsDetailLaborComponent from "./jobs-detail-labor.component";
-export default function JobsDetailLaborContainer({ jobId, techConsole, job }) {
- const { loading, error, data, refetch } = useQuery(GET_LINE_TICKET_BY_PK, {
- variables: { id: jobId },
- skip: !!!jobId,
- fetchPolicy: "network-only",
- nextFetchPolicy: "network-only",
- });
+export default function JobsDetailLaborContainer({jobId, techConsole, job}) {
+ const {loading, error, data, refetch} = useQuery(GET_LINE_TICKET_BY_PK, {
+ variables: {id: jobId},
+ skip: !!!jobId,
+ fetchPolicy: "network-only",
+ nextFetchPolicy: "network-only",
+ });
- if (error) return ;
+ if (error) return ;
- return (
-
- );
+ return (
+
+ );
}
diff --git a/client/src/components/jobs-detail-pli/jobs-detail-pli.component.jsx b/client/src/components/jobs-detail-pli/jobs-detail-pli.component.jsx
index ee73cd488..3ac2c0bcb 100644
--- a/client/src/components/jobs-detail-pli/jobs-detail-pli.component.jsx
+++ b/client/src/components/jobs-detail-pli/jobs-detail-pli.component.jsx
@@ -1,4 +1,4 @@
-import { Col, Row } from "antd";
+import {Col, Row} from "antd";
import React from "react";
import AlertComponent from "../alert/alert.component";
import BillDetailEditcontainer from "../bill-detail-edit/bill-detail-edit.container";
@@ -9,50 +9,50 @@ import PartsOrderModal from "../parts-order-modal/parts-order-modal.container";
import PartsDispatchTable from "../parts-dispatch-table/parts-dispatch-table.component";
export default function JobsDetailPliComponent({
- job,
- billsQuery,
- handleBillOnRowClick,
- handlePartsOrderOnRowClick,
- handlePartsDispatchOnRowClick,
-}) {
- return (
-
-
- {billsQuery.error ? (
-
- ) : null}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
+ job,
+ billsQuery,
+ handleBillOnRowClick,
+ handlePartsOrderOnRowClick,
+ handlePartsDispatchOnRowClick,
+ }) {
+ return (
+
+
+ {billsQuery.error ? (
+
+ ) : null}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
}
diff --git a/client/src/components/jobs-detail-pli/jobs-detail-pli.container.jsx b/client/src/components/jobs-detail-pli/jobs-detail-pli.container.jsx
index 99cf8c126..f932f9c7d 100644
--- a/client/src/components/jobs-detail-pli/jobs-detail-pli.container.jsx
+++ b/client/src/components/jobs-detail-pli/jobs-detail-pli.container.jsx
@@ -1,62 +1,62 @@
-import { useQuery } from "@apollo/client";
+import {useQuery} from "@apollo/client";
import queryString from "query-string";
import React from "react";
-import { useHistory, useLocation } from "react-router-dom";
-import { QUERY_BILLS_BY_JOBID } from "../../graphql/bills.queries";
+import {useLocation, useNavigate} from "react-router-dom";
+import {QUERY_BILLS_BY_JOBID} from "../../graphql/bills.queries";
import JobsDetailPliComponent from "./jobs-detail-pli.component";
-export default function JobsDetailPliContainer({ job }) {
- const billsQuery = useQuery(QUERY_BILLS_BY_JOBID, {
- variables: { jobid: job.id },
- fetchPolicy: "network-only",
- nextFetchPolicy: "network-only",
- });
+export default function JobsDetailPliContainer({job}) {
+ const billsQuery = useQuery(QUERY_BILLS_BY_JOBID, {
+ variables: {jobid: job.id},
+ fetchPolicy: "network-only",
+ nextFetchPolicy: "network-only",
+ });
- const search = queryString.parse(useLocation().search);
- const history = useHistory();
+ const search = queryString.parse(useLocation().search);
+ const history = useNavigate();
- const handleBillOnRowClick = (record) => {
- if (record) {
- if (record.id) {
- search.billid = record.id;
- history.push({ search: queryString.stringify(search) });
- }
- } else {
- delete search.billid;
- history.push({ search: queryString.stringify(search) });
- }
- };
+ const handleBillOnRowClick = (record) => {
+ if (record) {
+ if (record.id) {
+ search.billid = record.id;
+ history({search: queryString.stringify(search)});
+ }
+ } else {
+ delete search.billid;
+ history({search: queryString.stringify(search)});
+ }
+ };
- const handlePartsOrderOnRowClick = (record) => {
- if (record) {
- if (record.id) {
- search.partsorderid = record.id;
- history.push({ search: queryString.stringify(search) });
- }
- } else {
- delete search.partsorderid;
- history.push({ search: queryString.stringify(search) });
- }
- };
+ const handlePartsOrderOnRowClick = (record) => {
+ if (record) {
+ if (record.id) {
+ search.partsorderid = record.id;
+ history({search: queryString.stringify(search)});
+ }
+ } else {
+ delete search.partsorderid;
+ history({search: queryString.stringify(search)});
+ }
+ };
- 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 (
-
- );
+ 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 (
+
+ );
}
diff --git a/client/src/components/jobs-detail-rates-change-button/jobs-detail-rates-change-button.component.jsx b/client/src/components/jobs-detail-rates-change-button/jobs-detail-rates-change-button.component.jsx
index d83869b48..ab0e33e95 100644
--- a/client/src/components/jobs-detail-rates-change-button/jobs-detail-rates-change-button.component.jsx
+++ b/client/src/components/jobs-detail-rates-change-button/jobs-detail-rates-change-button.component.jsx
@@ -1,46 +1,43 @@
-import { DownOutlined } from "@ant-design/icons";
-import { Dropdown, Menu } from "antd";
+import {DownOutlined} from "@ant-design/icons";
+import {Dropdown} from "antd";
import React from "react";
-import { useTranslation } from "react-i18next";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { selectBodyshop } from "../../redux/user/user.selectors";
+import {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,
+ bodyshop: selectBodyshop,
});
-export function JobsDetailRatesChangeButton({ disabled, form, bodyshop }) {
- const { t } = useTranslation();
+export function JobsDetailRatesChangeButton({disabled, form, bodyshop}) {
+ const {t} = useTranslation();
- const handleClick = ({ item, key, keyPath }) => {
- const rate = item.props.value;
- form.setFieldsValue({ ...rate, labor_rate_desc: rate.rate_label });
- };
+ const handleClick = ({item, key, keyPath}) => {
+ const rate = item.props.value;
+ form.setFieldsValue({...rate, labor_rate_desc: rate.rate_label});
+ };
- const menu = (
-
-
-
- );
+ const menu = {
+ items: bodyshop.md_labor_rates.map((rate, idx) => ({
+ key: idx,
+ label: rate.rate_label,
+ value: rate,
+ })),
+ onClick: handleClick
+ }
- return (
-
- e.preventDefault()}
- >
- {t("jobs.actions.changelaborrate")}
-
-
- );
+ return (
+
+ e.preventDefault()}
+ >
+ {t("jobs.actions.changelaborrate")}
+
+
+ );
}
export default connect(mapStateToProps, null)(JobsDetailRatesChangeButton);
diff --git a/client/src/components/jobs-detail-rates/jobs-detail-rates.component.jsx b/client/src/components/jobs-detail-rates/jobs-detail-rates.component.jsx
index d66b30b41..f5b8bfea3 100644
--- a/client/src/components/jobs-detail-rates/jobs-detail-rates.component.jsx
+++ b/client/src/components/jobs-detail-rates/jobs-detail-rates.component.jsx
@@ -1,10 +1,10 @@
-import { Divider, Form, Input, Select, Space, Switch, Tooltip } from "antd";
+import {Divider, Form, Input, Select, Space, Switch, Tooltip} from "antd";
import React from "react";
-import { useTranslation } from "react-i18next";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { selectJobReadOnly } from "../../redux/application/application.selectors";
-import { selectBodyshop } from "../../redux/user/user.selectors";
+import {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 CurrencyInput from "../form-items-formatted/currency-form-item.component";
import JobsDetailRatesChangeButton from "../jobs-detail-rates-change-button/jobs-detail-rates-change-button.component";
@@ -18,195 +18,196 @@ import JobsDetailRatesTaxes from "./jobs-detail-rates.taxes.component";
import JobsDetailRatesProfileOVerride from "./jobs-detail-rates.profile-override.component";
const mapStateToProps = createStructuredSelector({
- jobRO: selectJobReadOnly,
- bodyshop: selectBodyshop,
+ jobRO: selectJobReadOnly,
+ bodyshop: selectBodyshop,
});
-export function JobsDetailRates({ jobRO, form, job, bodyshop }) {
- const { t } = useTranslation();
- return (
-
-
-
-
-
-
-
-
- {bodyshop.region_config.toLowerCase().startsWith("ca") && (
-
-
-
-
-
- )}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- prev.auto_add_ats !== cur.auto_add_ats}
- >
- {() => {
- if (form.getFieldValue("auto_add_ats"))
- return (
-
-
+export function JobsDetailRates({jobRO, form, job, bodyshop}) {
+ const {t} = useTranslation();
+ return (
+
+
+
+
+
+
+
+ {bodyshop.region_config.toLowerCase().startsWith("ca") && (
+
+
+
+
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
- );
- return null;
- }}
-
-
+
+
+
-
- {t("jobs.forms.laborrates")}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {
- //
- //
- //
- //
- //
- //
- }
-
-
-
-
-
Tax Profile
+
prev.auto_add_ats !== cur.auto_add_ats}
+ >
+ {() => {
+ if (form.getFieldValue("auto_add_ats"))
+ return (
+
+
+
+ );
-
+ return null;
+ }}
+
+
-
-
-
-
-
-
- );
+
+ {t("jobs.forms.laborrates")}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ //
+ //
+ //
+ //
+ //
+ //
+ }
+
+
+
+
+ Tax Profile
+
+
+
+
+
+
+
+
+
+ );
}
+
export default connect(mapStateToProps, null)(JobsDetailRates);
diff --git a/client/src/components/jobs-detail-rates/jobs-detail-rates.labor.component.jsx b/client/src/components/jobs-detail-rates/jobs-detail-rates.labor.component.jsx
index 75e80d4a1..cdef71c8e 100644
--- a/client/src/components/jobs-detail-rates/jobs-detail-rates.labor.component.jsx
+++ b/client/src/components/jobs-detail-rates/jobs-detail-rates.labor.component.jsx
@@ -1,427 +1,429 @@
-import { Collapse, Form, Switch } from "antd";
+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 {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,
+ jobRO: selectJobReadOnly,
});
export function JobsDetailRatesLabor({
- jobRO,
- expanded,
- required = true,
- form,
-}) {
- const { t } = useTranslation();
+ jobRO,
+ expanded,
+ required = true,
+ form,
+ }) {
+ const {t} = useTranslation();
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
}
+
export default connect(mapStateToProps, null)(JobsDetailRatesLabor);
diff --git a/client/src/components/jobs-detail-rates/jobs-detail-rates.materials.component.jsx b/client/src/components/jobs-detail-rates/jobs-detail-rates.materials.component.jsx
index d9e641531..e3e312fb3 100644
--- a/client/src/components/jobs-detail-rates/jobs-detail-rates.materials.component.jsx
+++ b/client/src/components/jobs-detail-rates/jobs-detail-rates.materials.component.jsx
@@ -1,145 +1,147 @@
-import { Collapse, Form, Input, InputNumber, Switch } from "antd";
+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 {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,
+ jobRO: selectJobReadOnly,
});
export function JobsDetailRatesMaterials({
- jobRO,
- expanded,
- required = true,
- form,
-}) {
- const { t } = useTranslation();
+ jobRO,
+ expanded,
+ required = true,
+ form,
+ }) {
+ const {t} = useTranslation();
- return (
-
-
-
-
-
-
-
-
-
+ return (
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
}
+
export default connect(mapStateToProps, null)(JobsDetailRatesMaterials);
diff --git a/client/src/components/jobs-detail-rates/jobs-detail-rates.other.component.jsx b/client/src/components/jobs-detail-rates/jobs-detail-rates.other.component.jsx
index 9d52c75bc..0617a8fea 100644
--- a/client/src/components/jobs-detail-rates/jobs-detail-rates.other.component.jsx
+++ b/client/src/components/jobs-detail-rates/jobs-detail-rates.other.component.jsx
@@ -1,104 +1,106 @@
-import { Collapse, Form, Switch } from "antd";
+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 {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,
+ jobRO: selectJobReadOnly,
});
export function JobsDetailRatesOther({
- jobRO,
- expanded,
- required = true,
- form,
-}) {
- const { t } = useTranslation();
+ jobRO,
+ expanded,
+ required = true,
+ form,
+ }) {
+ const {t} = useTranslation();
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
}
+
export default connect(mapStateToProps, null)(JobsDetailRatesOther);
diff --git a/client/src/components/jobs-detail-rates/jobs-detail-rates.parts.component.jsx b/client/src/components/jobs-detail-rates/jobs-detail-rates.parts.component.jsx
index 2cd2b8917..241327a3d 100644
--- a/client/src/components/jobs-detail-rates/jobs-detail-rates.parts.component.jsx
+++ b/client/src/components/jobs-detail-rates/jobs-detail-rates.parts.component.jsx
@@ -1,1223 +1,1225 @@
-import { Collapse, Form, InputNumber, Switch } from "antd";
+import {Collapse, Form, 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 {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,
+ jobRO: selectJobReadOnly,
});
export function JobsDetailRatesParts({
- jobRO,
- expanded,
- required = true,
- form,
-}) {
- const { t } = useTranslation();
+ jobRO,
+ expanded,
+ required = true,
+ form,
+ }) {
+ const {t} = useTranslation();
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {() => {
- return (
-
-
-
- );
- }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {() => {
- return (
-
-
-
- );
- }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {() => {
- return (
-
-
-
- );
- }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {() => {
- return (
-
-
-
- );
- }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {() => {
- return (
-
-
-
- );
- }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {() => {
- return (
-
-
-
- );
- }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {() => {
- return (
-
-
-
- );
- }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {() => {
- return (
-
-
-
- );
- }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {() => {
- return (
-
-
-
- );
- }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {() => {
- return (
-
-
-
- );
- }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {() => {
- return (
-
-
-
- );
- }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {() => {
+ return (
+
+
+
+ );
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {() => {
+ return (
+
+
+
+ );
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {() => {
+ return (
+
+
+
+ );
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {() => {
+ return (
+
+
+
+ );
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {() => {
+ return (
+
+
+
+ );
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {() => {
+ return (
+
+
+
+ );
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {() => {
+ return (
+
+
+
+ );
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {() => {
+ return (
+
+
+
+ );
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {() => {
+ return (
+
+
+
+ );
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {() => {
+ return (
+
+
+
+ );
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {() => {
+ return (
+
+
+
+ );
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
}
+
export default connect(mapStateToProps, null)(JobsDetailRatesParts);
diff --git a/client/src/components/jobs-detail-rates/jobs-detail-rates.profile-override.component.jsx b/client/src/components/jobs-detail-rates/jobs-detail-rates.profile-override.component.jsx
index e046a4afa..a127cd9c7 100644
--- a/client/src/components/jobs-detail-rates/jobs-detail-rates.profile-override.component.jsx
+++ b/client/src/components/jobs-detail-rates/jobs-detail-rates.profile-override.component.jsx
@@ -1,42 +1,43 @@
-import { Button, Popconfirm } from "antd";
+import {Button, Popconfirm} from "antd";
import React from "react";
-import { useTranslation } from "react-i18next";
+import {useTranslation} from "react-i18next";
+
+import {connect} from "react-redux";
+import {createStructuredSelector} from "reselect";
+import {selectBodyshop} from "../../redux/user/user.selectors";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { selectBodyshop } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
- bodyshop: selectBodyshop,
+ bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
- //setUserLanguage: language => dispatch(setUserLanguage(language))
+ //setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(
- mapStateToProps,
- mapDispatchToProps
+ mapStateToProps,
+ mapDispatchToProps
)(JobsDetailRatesProfileOVerride);
-export function JobsDetailRatesProfileOVerride({ bodyshop, form }) {
- const { t } = useTranslation();
- return (
- {
- 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")}
- >
- {t("jobs.actions.taxprofileoverride")}
-
- );
+export function JobsDetailRatesProfileOVerride({bodyshop, form}) {
+ const {t} = useTranslation();
+ return (
+ {
+ 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")}
+ >
+ {t("jobs.actions.taxprofileoverride")}
+
+ );
}
diff --git a/client/src/components/jobs-detail-rates/jobs-detail-rates.taxes.component.jsx b/client/src/components/jobs-detail-rates/jobs-detail-rates.taxes.component.jsx
index 31d5b7213..0a6e85e3e 100644
--- a/client/src/components/jobs-detail-rates/jobs-detail-rates.taxes.component.jsx
+++ b/client/src/components/jobs-detail-rates/jobs-detail-rates.taxes.component.jsx
@@ -1,155 +1,157 @@
-import { Collapse, Divider, Form, Input, InputNumber, Space } from "antd";
+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";
+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,
+ 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 = [];
+ 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,
- })
- );
+ 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,
- })
- );
+ 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();
}
- formItems.push(Space({ children: section, wrap: true }));
- formItems.push();
- }
- return (
-
-
- {formItems}
-
-
- );
+ return (
+
+
+ {formItems}
+
+
+ );
}
+
export default connect(mapStateToProps, null)(JobsDetailRatesTaxes);
function TaxFormItems({
- typeNum,
- typeNumIterator,
- rootElements,
- bodyshopjobRO,
- jobRO,
-}) {
- const { t } = useTranslation();
+ typeNum,
+ typeNumIterator,
+ rootElements,
+ bodyshopjobRO,
+ jobRO,
+ }) {
+ const {t} = useTranslation();
+
+ if (rootElements)
+ return (
+ <>
+
+
+
+ >
+ );
- if (rootElements)
return (
- <>
-
-
-
- >
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+ >
);
-
- return (
- <>
-
-
-
-
-
-
-
-
-
-
-
-
- >
- );
}
diff --git a/client/src/components/jobs-detail-totals/jobs-detail-totals.component.jsx b/client/src/components/jobs-detail-totals/jobs-detail-totals.component.jsx
index 8a52d28ba..c38f5e619 100644
--- a/client/src/components/jobs-detail-totals/jobs-detail-totals.component.jsx
+++ b/client/src/components/jobs-detail-totals/jobs-detail-totals.component.jsx
@@ -1,15 +1,16 @@
-import { Divider } from "antd";
+import {Divider} from "antd";
import React from "react";
import JobPayments from "../job-payments/job-payments.component";
import JobTotalsTable from "../job-totals-table/job-totals-table.component";
-export function JobsDetailTotals({ job, refetch }) {
- return (
-
- );
+export function JobsDetailTotals({job, refetch}) {
+ return (
+
+ );
}
+
export default JobsDetailTotals;
diff --git a/client/src/components/jobs-documents-gallery/job-documents.utility.js b/client/src/components/jobs-documents-gallery/job-documents.utility.js
index ce5a3bcb4..b954c2081 100644
--- a/client/src/components/jobs-documents-gallery/job-documents.utility.js
+++ b/client/src/components/jobs-documents-gallery/job-documents.utility.js
@@ -1,26 +1,26 @@
-import { DetermineFileType } from "../documents-upload/documents-upload.utility";
+import {DetermineFileType} from "../documents-upload/documents-upload.utility";
export const GenerateSrcUrl = (value) => {
- let extension = value.extension;
- if (extension && extension.toLowerCase().includes("heic")) extension = "jpg";
+ let extension = value.extension;
+ if (extension && extension.toLowerCase().includes("heic")) extension = "jpg";
- return `${process.env.REACT_APP_CLOUDINARY_ENDPOINT}/${DetermineFileType(
- value.type
- )}/upload/${value.key}${extension ? `.${extension}` : ""}`;
+ return `${process.env.REACT_APP_CLOUDINARY_ENDPOINT}/${DetermineFileType(
+ value.type
+ )}/upload/${value.key}${extension ? `.${extension}` : ""}`;
};
export const GenerateThumbUrl = (value) => {
- let extension = value.extension;
- if (extension && extension.toLowerCase().includes("heic")) extension = "jpg";
- else if (
- DetermineFileType(value.type) !== "image" ||
- (value.type && value.type.includes("application"))
- )
- extension = "jpg";
+ let extension = value.extension;
+ if (extension && extension.toLowerCase().includes("heic")) extension = "jpg";
+ else if (
+ DetermineFileType(value.type) !== "image" ||
+ (value.type && value.type.includes("application"))
+ )
+ extension = "jpg";
- return `${process.env.REACT_APP_CLOUDINARY_ENDPOINT}/${DetermineFileType(
- value.type
- )}/upload/${process.env.REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS}/${
- value.key
- }${extension ? `.${extension}` : ""}`;
+ return `${process.env.REACT_APP_CLOUDINARY_ENDPOINT}/${DetermineFileType(
+ value.type
+ )}/upload/${process.env.REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS}/${
+ value.key
+ }${extension ? `.${extension}` : ""}`;
};
diff --git a/client/src/components/jobs-documents-gallery/jobs-document-gallery.download.component.jsx b/client/src/components/jobs-documents-gallery/jobs-document-gallery.download.component.jsx
index 2ed2e3ec4..6ee486a4f 100644
--- a/client/src/components/jobs-documents-gallery/jobs-document-gallery.download.component.jsx
+++ b/client/src/components/jobs-documents-gallery/jobs-document-gallery.download.component.jsx
@@ -1,145 +1,145 @@
-import { Button, Space } from "antd";
+import {Button, Space} from "antd";
import axios from "axios";
-import React, { useState } from "react";
-import { useTranslation } from "react-i18next";
-import { logImEXEvent } from "../../firebase/firebase.utils";
+import React, {useState} from "react";
+import {useTranslation} from "react-i18next";
+import {logImEXEvent} from "../../firebase/firebase.utils";
import cleanAxios from "../../utils/CleanAxios";
import formatBytes from "../../utils/formatbytes";
//import yauzl from "yauzl";
-import { useTreatments } from "@splitsoftware/splitio-react";
+import {useSplitTreatments} from "@splitsoftware/splitio-react";
+
+import {connect} from "react-redux";
+import {createStructuredSelector} from "reselect";
+import {selectBodyshop} from "../../redux/user/user.selectors";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { selectBodyshop } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
- bodyshop: selectBodyshop,
+ bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
- //setUserLanguage: language => dispatch(setUserLanguage(language))
+ //setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(
- mapStateToProps,
- mapDispatchToProps
+ mapStateToProps,
+ mapDispatchToProps
)(JobsDocumentsDownloadButton);
-export function JobsDocumentsDownloadButton({
- bodyshop,
- galleryImages,
- identifier,
-}) {
- const { t } = useTranslation();
- const [download, setDownload] = useState(null);
- const { Direct_Media_Download } = useTreatments(
- ["Direct_Media_Download"],
- {},
- bodyshop.imexshopid
- );
- const imagesToDownload = [
- ...galleryImages.images.filter((image) => image.isSelected),
- ...galleryImages.other.filter((image) => image.isSelected),
- ];
+export function JobsDocumentsDownloadButton({bodyshop, galleryImages, identifier}) {
- function downloadProgress(progressEvent) {
- setDownload((currentDownloadState) => {
- return {
- downloaded: progressEvent.loaded || 0,
- speed:
- (progressEvent.loaded || 0) -
- ((currentDownloadState && currentDownloadState.downloaded) || 0),
- };
- });
- }
+ const {t} = useTranslation();
+ const [download, setDownload] = useState(null);
- const handleDownload = async () => {
- logImEXEvent("jobs_documents_download");
-
- const zipUrl = await axios({
- url: "/media/download",
- method: "POST",
- //responseType: "arraybuffer", // Important
- data: { ids: imagesToDownload.map((_) => _.key) },
+ const {treatments: {Direct_Media_Download}} = useSplitTreatments({
+ attributes: {},
+ names: ["Direct_Media_Download"],
+ splitKey: bodyshop.imexshopid,
});
- const theDownloadedZip = await cleanAxios({
- url: zipUrl.data,
- method: "GET",
- responseType: "arraybuffer",
- onDownloadProgress: downloadProgress,
- });
- setDownload(null);
- if (Direct_Media_Download.treatment === "on") {
- try {
- // const parentDir = await window.showDirectoryPicker({
- // id: "media",
- // startIn: "downloads",
- // });
+ const imagesToDownload = [
+ ...galleryImages.images.filter((image) => image.isSelected),
+ ...galleryImages.other.filter((image) => image.isSelected),
+ ];
- // const directory = await parentDir.getDirectoryHandle(identifier, {
- // create: true,
- // });
-
- // yauzl.fromBuffer(
- // Buffer.from(theDownloadedZip.data),
- // {},
- // (err, zipFile) => {
- // if (err) throw err;
- // zipFile.on("entry", (entry) => {
- // zipFile.openReadStream(entry, async (readErr, readStream) => {
- // if (readErr) {
- // zipFile.close();
- // throw readErr;
- // }
- // if (err) throw err;
- // let fileSystemHandle = await directory.getFileHandle(
- // entry.fileName,
- // {
- // create: true,
- // }
- // );
- // const writable = await fileSystemHandle.createWritable();
- // readStream.on("data", async function (chunk) {
- // await writable.write(chunk);
- // });
- // readStream.on("end", async function () {
- // await writable.close();
- // });
- // });
- // });
- // }
- // );
- } catch (e) {
- console.log(e);
- standardMediaDownload(theDownloadedZip.data);
- }
- } else {
- standardMediaDownload(theDownloadedZip.data);
+ function downloadProgress(progressEvent) {
+ setDownload((currentDownloadState) => {
+ return {
+ downloaded: progressEvent.loaded || 0,
+ speed:
+ (progressEvent.loaded || 0) -
+ ((currentDownloadState && currentDownloadState.downloaded) || 0),
+ };
+ });
}
- function standardMediaDownload(bufferData) {
- const a = document.createElement("a");
- const url = window.URL.createObjectURL(new Blob([bufferData]));
- a.href = url;
- a.download = `${identifier || "documents"}.zip`;
- a.click();
- }
- };
-
- return (
- <>
-
-
- {t("documents.actions.download")}
- {download && (
- {`(${formatBytes(download.downloaded)} @ ${formatBytes(
- download.speed
- )} / second)`}
- )}
-
-
- >
- );
+ const handleDownload = async () => {
+ logImEXEvent("jobs_documents_download");
+
+ const zipUrl = await axios({
+ url: "/media/download",
+ method: "POST",
+ //responseType: "arraybuffer", // Important
+ data: {ids: imagesToDownload.map((_) => _.key)},
+ });
+
+ const theDownloadedZip = await cleanAxios({
+ url: zipUrl.data,
+ method: "GET",
+ responseType: "arraybuffer",
+ onDownloadProgress: downloadProgress,
+ });
+ setDownload(null);
+ if (Direct_Media_Download.treatment === "on") {
+ try {
+ // const parentDir = await window.showDirectoryPicker({
+ // id: "media",
+ // startIn: "downloads",
+ // });
+
+ // const directory = await parentDir.getDirectoryHandle(identifier, {
+ // create: true,
+ // });
+
+ // yauzl.fromBuffer(
+ // Buffer.from(theDownloadedZip.data),
+ // {},
+ // (err, zipFile) => {
+ // if (err) throw err;
+ // zipFile.on("entry", (entry) => {
+ // zipFile.openReadStream(entry, async (readErr, readStream) => {
+ // if (readErr) {
+ // zipFile.close();
+ // throw readErr;
+ // }
+ // if (err) throw err;
+ // let fileSystemHandle = await directory.getFileHandle(
+ // entry.fileName,
+ // {
+ // create: true,
+ // }
+ // );
+ // const writable = await fileSystemHandle.createWritable();
+ // readStream.on("data", async function (chunk) {
+ // await writable.write(chunk);
+ // });
+ // readStream.on("end", async function () {
+ // await writable.close();
+ // });
+ // });
+ // });
+ // }
+ // );
+ } catch (e) {
+ console.log(e);
+ standardMediaDownload(theDownloadedZip.data);
+ }
+ } else {
+ standardMediaDownload(theDownloadedZip.data);
+ }
+
+ function standardMediaDownload(bufferData) {
+ const a = document.createElement("a");
+ const url = window.URL.createObjectURL(new Blob([bufferData]));
+ a.href = url;
+ a.download = `${identifier || "documents"}.zip`;
+ a.click();
+ }
+ };
+
+ return (
+ <>
+
+
+ {t("documents.actions.download")}
+ {download && (
+ {`(${formatBytes(download.downloaded)} @ ${formatBytes(
+ download.speed
+ )} / second)`}
+ )}
+
+
+ >
+ );
}
diff --git a/client/src/components/jobs-documents-gallery/jobs-document-gallery.reassign.component.jsx b/client/src/components/jobs-documents-gallery/jobs-document-gallery.reassign.component.jsx
index 18be6fb62..376ac8f4d 100644
--- a/client/src/components/jobs-documents-gallery/jobs-document-gallery.reassign.component.jsx
+++ b/client/src/components/jobs-documents-gallery/jobs-document-gallery.reassign.component.jsx
@@ -1,172 +1,172 @@
-import { useApolloClient } from "@apollo/client";
-import { Button, Form, notification, Popover, Space } from "antd";
+import {useApolloClient} from "@apollo/client";
+import {Button, Form, notification, Popover, Space} from "antd";
import axios from "axios";
-import React, { useMemo, useState } from "react";
-import { useTranslation } from "react-i18next";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { GET_DOC_SIZE_BY_JOB } from "../../graphql/documents.queries";
-import { selectBodyshop } from "../../redux/user/user.selectors";
+import React, {useMemo, useState} from "react";
+import {useTranslation} from "react-i18next";
+import {connect} from "react-redux";
+import {createStructuredSelector} from "reselect";
+import {GET_DOC_SIZE_BY_JOB} from "../../graphql/documents.queries";
+import {selectBodyshop} from "../../redux/user/user.selectors";
import JobSearchSelect from "../job-search-select/job-search-select.component";
const mapStateToProps = createStructuredSelector({
- bodyshop: selectBodyshop,
+ bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
- //setUserLanguage: language => dispatch(setUserLanguage(language))
+ //setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(
- mapStateToProps,
- mapDispatchToProps
+ mapStateToProps,
+ mapDispatchToProps
)(JobsDocumentsGalleryReassign);
export function JobsDocumentsGalleryReassign({
- bodyshop,
- galleryImages,
- callback,
-}) {
- const { t } = useTranslation();
- const [form] = Form.useForm();
+ bodyshop,
+ galleryImages,
+ callback,
+ }) {
+ const {t} = useTranslation();
+ const [form] = Form.useForm();
- const selectedImages = useMemo(() => {
- return [
- ...galleryImages.images.filter((image) => image.isSelected),
- ...galleryImages.other.filter((image) => image.isSelected),
- ];
- }, [galleryImages]);
- const client = useApolloClient();
- const [visible, setVisible] = useState(false);
- const [loading, setLoading] = useState(false);
+ const selectedImages = useMemo(() => {
+ return [
+ ...galleryImages.images.filter((image) => image.isSelected),
+ ...galleryImages.other.filter((image) => image.isSelected),
+ ];
+ }, [galleryImages]);
+ const client = useApolloClient();
+ const [open, setOpen] = useState(false);
+ const [loading, setLoading] = useState(false);
- // const updateImage = async (i, jobid) => {
- // //Move the cloudinary image
+ // const updateImage = async (i, jobid) => {
+ // //Move the cloudinary image
- // //Update it in the database.
- // const result = await updateDocument({
- // variables: {
- // id: i.id,
- // document: {
- // key: i.public_id,
- // jobid: jobid,
- // },
- // },
- // });
+ // //Update it in the database.
+ // const result = await updateDocument({
+ // variables: {
+ // id: i.id,
+ // document: {
+ // key: i.public_id,
+ // jobid: jobid,
+ // },
+ // },
+ // });
- // if (!!result.errors) {
- // notification["error"]({
- // message: t("documents.errors.updating", {
- // message: JSON.stringify(result.errors),
- // }),
- // });
- // } else {
- // notification["success"]({
- // message: t("documents.successes.updated"),
- // });
- // }
- // };
+ // if (!!result.errors) {
+ // notification["error"]({
+ // message: t("documents.errors.updating", {
+ // message: JSON.stringify(result.errors),
+ // }),
+ // });
+ // } else {
+ // notification["success"]({
+ // message: t("documents.successes.updated"),
+ // });
+ // }
+ // };
- const handleFinish = async ({ jobid }) => {
- setLoading(true);
+ const handleFinish = async ({jobid}) => {
+ setLoading(true);
- //Check to see if the space remaining on the new job is sufficient. If it isn't cancel this.
- const newJobData = await client.query({
- query: GET_DOC_SIZE_BY_JOB,
- variables: { jobId: jobid },
- });
+ //Check to see if the space remaining on the new job is sufficient. If it isn't cancel this.
+ const newJobData = await client.query({
+ query: GET_DOC_SIZE_BY_JOB,
+ variables: {jobId: jobid},
+ });
- const transferedDocSizeTotal = selectedImages.reduce(
- (acc, val) => acc + val.size,
- 0
+ const transferedDocSizeTotal = selectedImages.reduce(
+ (acc, val) => acc + val.size,
+ 0
+ );
+
+ const shouldPreventTransfer =
+ bodyshop.jobsizelimit -
+ newJobData.data.documents_aggregate.aggregate.sum.size <
+ transferedDocSizeTotal;
+
+ if (shouldPreventTransfer) {
+ notification.open({
+ key: "cannotuploaddocuments",
+ type: "error",
+ message: t("documents.labels.reassign_limitexceeded_title"),
+ description: t("documents.labels.reassign_limitexceeded"),
+ });
+ setLoading(false);
+ return;
+ }
+
+ const res = await axios.post("/media/rename", {
+ tojobid: jobid,
+ documents: selectedImages.map((i) => {
+ //Need to check if the current key folder is null, or another job.
+ const currentKeys = i.key.split("/");
+ currentKeys[1] = jobid;
+ currentKeys.join("/");
+ return {
+ id: i.id,
+ from: i.key,
+ to: currentKeys.join("/"),
+ extension: i.extension,
+ type: i.type,
+ };
+ }),
+ });
+ //Add in confirmation & errors.
+ if (callback) callback();
+
+ if (res.errors) {
+ notification["error"]({
+ message: t("documents.errors.updating", {
+ message: JSON.stringify(res.errors),
+ }),
+ });
+ }
+ if (!res.mutationResult?.errors) {
+ notification["success"]({
+ message: t("documents.successes.updated"),
+ });
+ }
+ setOpen(false);
+ setLoading(false);
+ };
+
+ const popContent = (
+
+
+
+
+
+
+ form.submit()}>
+ {t("general.actions.submit")}
+
+ setOpen(false)}>
+ {t("general.actions.cancel")}
+
+
+
);
- const shouldPreventTransfer =
- bodyshop.jobsizelimit -
- newJobData.data.documents_aggregate.aggregate.sum.size <
- transferedDocSizeTotal;
-
- if (shouldPreventTransfer) {
- notification.open({
- key: "cannotuploaddocuments",
- type: "error",
- message: t("documents.labels.reassign_limitexceeded_title"),
- description: t("documents.labels.reassign_limitexceeded"),
- });
- setLoading(false);
- return;
- }
-
- const res = await axios.post("/media/rename", {
- tojobid: jobid,
- documents: selectedImages.map((i) => {
- //Need to check if the current key folder is null, or another job.
- const currentKeys = i.key.split("/");
- currentKeys[1] = jobid;
- currentKeys.join("/");
- return {
- id: i.id,
- from: i.key,
- to: currentKeys.join("/"),
- extension: i.extension,
- type: i.type,
- };
- }),
- });
- //Add in confirmation & errors.
- if (callback) callback();
-
- if (res.errors) {
- notification["error"]({
- message: t("documents.errors.updating", {
- message: JSON.stringify(res.errors),
- }),
- });
- }
- if (!res.mutationResult?.errors) {
- notification["success"]({
- message: t("documents.successes.updated"),
- });
- }
- setVisible(false);
- setLoading(false);
- };
-
- const popContent = (
-
-
-
-
-
-
- form.submit()}>
- {t("general.actions.submit")}
-
- setVisible(false)}>
- {t("general.actions.cancel")}
-
-
-
- );
-
- return (
-
- setVisible(true)}
- loading={loading}
- >
- {t("documents.actions.reassign")}
-
-
- );
+ return (
+
+ setOpen(true)}
+ loading={loading}
+ >
+ {t("documents.actions.reassign")}
+
+
+ );
}
diff --git a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx
index d7e930e8b..fd9be8f23 100644
--- a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx
+++ b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx
@@ -1,11 +1,11 @@
-import { EditFilled, FileExcelFilled, SyncOutlined } from "@ant-design/icons";
-import { Button, Card, Col, Row, Space } from "antd";
-import React, { useEffect, useState } from "react";
-import { Gallery } from "react-grid-gallery";
-import { useTranslation } from "react-i18next";
+import {EditFilled, FileExcelFilled, SyncOutlined} from "@ant-design/icons";
+import {Button, Card, Col, Row, Space} from "antd";
+import React, {useEffect, useState} from "react";
+import {Gallery} from "react-grid-gallery";
+import {useTranslation} from "react-i18next";
import DocumentsUploadComponent from "../documents-upload/documents-upload.component";
-import { DetermineFileType } from "../documents-upload/documents-upload.utility";
-import { GenerateSrcUrl, GenerateThumbUrl } from "./job-documents.utility";
+import {DetermineFileType} from "../documents-upload/documents-upload.utility";
+import {GenerateSrcUrl, GenerateThumbUrl} from "./job-documents.utility";
import JobsDocumentsDownloadButton from "./jobs-document-gallery.download.component";
import JobsDocumentsGalleryReassign from "./jobs-document-gallery.reassign.component";
import JobsDocumentsDeleteButton from "./jobs-documents-gallery.delete.component";
@@ -15,237 +15,238 @@ import Lightbox from "react-image-lightbox";
import "react-image-lightbox/style.css";
function JobsDocumentsComponent({
- data,
- jobId,
- refetch,
- billId,
- billsCallback,
- totalSize,
- downloadIdentifier,
- ignoreSizeLimit,
-}) {
- const [galleryImages, setgalleryImages] = useState({ images: [], other: [] });
- const { t } = useTranslation();
- const [modalState, setModalState] = useState({ open: false, index: 0 });
+ data,
+ jobId,
+ refetch,
+ billId,
+ billsCallback,
+ totalSize,
+ downloadIdentifier,
+ ignoreSizeLimit,
+ }) {
+ const [galleryImages, setgalleryImages] = useState({images: [], other: []});
+ const {t} = useTranslation();
+ const [modalState, setModalState] = useState({open: false, index: 0});
- useEffect(() => {
- let documents = data.reduce(
- (acc, value) => {
- const fileType = DetermineFileType(value.type);
- if (value.type.startsWith("image")) {
- acc.images.push({
- // src: GenerateSrcUrl(value),
- src: GenerateThumbUrl(value),
- // src: GenerateSrcUrl(value),
- // thumbnail: GenerateThumbUrl(value),
- fullsize: GenerateSrcUrl(value),
- height: 225,
- width: 225,
- isSelected: false,
- key: value.key,
- extension: value.extension,
- id: value.id,
- type: value.type,
- size: value.size,
- tags: [{ value: value.type, title: value.type }],
- });
- } else {
- let thumb;
- switch (fileType) {
- case "raw":
- thumb = `${window.location.origin}/file.png`;
- break;
- default:
- thumb = GenerateThumbUrl(value);
- break;
- }
+ useEffect(() => {
+ let documents = data.reduce(
+ (acc, value) => {
+ const fileType = DetermineFileType(value.type);
+ if (value.type.startsWith("image")) {
+ acc.images.push({
+ // src: GenerateSrcUrl(value),
+ src: GenerateThumbUrl(value),
+ // src: GenerateSrcUrl(value),
+ // thumbnail: GenerateThumbUrl(value),
+ fullsize: GenerateSrcUrl(value),
+ height: 225,
+ width: 225,
+ isSelected: false,
+ key: value.key,
+ extension: value.extension,
+ id: value.id,
+ type: value.type,
+ size: value.size,
+ tags: [{value: value.type, title: value.type}],
+ });
+ } else {
+ let thumb;
+ switch (fileType) {
+ case "raw":
+ thumb = `${window.location.origin}/file.png`;
+ break;
+ default:
+ thumb = GenerateThumbUrl(value);
+ break;
+ }
- const fileName = value.key.split("/").pop();
- acc.other.push({
- source: GenerateSrcUrl(value),
- src: thumb,
- thumbnail: thumb,
- tags: [
- {
- value: fileName,
- title: fileName,
- },
+ const fileName = value.key.split("/").pop();
+ acc.other.push({
+ source: GenerateSrcUrl(value),
+ src: thumb,
+ thumbnail: thumb,
+ tags: [
+ {
+ value: fileName,
+ title: fileName,
+ },
- { value: value.type, title: value.type },
- ...(value.bill
- ? [
- {
- value: value.bill.vendor.name,
- title: t("vendors.fields.name"),
- },
- { value: value.bill.date, title: t("bills.fields.date") },
- {
- value: value.bill.invoice_number,
- title: t("bills.fields.invoice_number"),
- },
- ]
- : []),
- ],
- height: 225,
- width: 225,
- isSelected: false,
- extension: value.extension,
- key: value.key,
- id: value.id,
- type: value.type,
- size: value.size,
- });
- }
+ {value: value.type, title: value.type},
+ ...(value.bill
+ ? [
+ {
+ value: value.bill.vendor.name,
+ title: t("vendors.fields.name"),
+ },
+ {value: value.bill.date, title: t("bills.fields.date")},
+ {
+ value: value.bill.invoice_number,
+ title: t("bills.fields.invoice_number"),
+ },
+ ]
+ : []),
+ ],
+ height: 225,
+ width: 225,
+ isSelected: false,
+ extension: value.extension,
+ key: value.key,
+ id: value.id,
+ type: value.type,
+ size: value.size,
+ });
+ }
- return acc;
- },
- { images: [], other: [] }
+ return acc;
+ },
+ {images: [], other: []}
+ );
+ setgalleryImages(documents);
+ }, [data, setgalleryImages, t]);
+
+ return (
+
+
+
+
+ refetch && refetch()}>
+
+
+
+
+
+ {!billId && (
+
+ )}
+
+
+
+
+
+
+
+
+
+
+ {
+ setModalState({open: true, index: index});
+ // window.open(
+ // item.fullsize,
+ // "_blank",
+ // "toolbar=0,location=0,menubar=0"
+ // );
+ }}
+ onSelect={(index, image) => {
+ setgalleryImages({
+ ...galleryImages,
+ images: galleryImages.images.map((g, idx) =>
+ index === idx ? {...g, isSelected: !g.isSelected} : g
+ ),
+ });
+ }}
+ />
+
+
+
+
+ {
+ return {
+ backgroundImage: ,
+ height: "100%",
+ width: "100%",
+ cursor: "pointer",
+ };
+ }}
+ onClick={(index) => {
+ window.open(
+ galleryImages.other[index].source,
+ "_blank",
+ "toolbar=0,location=0,menubar=0"
+ );
+ }}
+ onSelect={(index) => {
+ setgalleryImages({
+ ...galleryImages,
+ other: galleryImages.other.map((g, idx) =>
+ index === idx ? {...g, isSelected: !g.isSelected} : g
+ ),
+ });
+ }}
+ />
+
+
+ {modalState.open && (
+ {
+ const newWindow = window.open(
+ `${window.location.protocol}//${
+ window.location.host
+ }/edit?documentId=${
+ galleryImages.images[modalState.index].id
+ }`,
+ "_blank",
+ "noopener,noreferrer"
+ );
+ if (newWindow) newWindow.opener = null;
+ }}
+ />,
+ ]}
+ mainSrc={galleryImages.images[modalState.index].fullsize}
+ nextSrc={
+ galleryImages.images[
+ (modalState.index + 1) % galleryImages.images.length
+ ].fullsize
+ }
+ prevSrc={
+ galleryImages.images[
+ (modalState.index + galleryImages.images.length - 1) %
+ galleryImages.images.length
+ ].fullsize
+ }
+ onCloseRequest={() => setModalState({open: false, index: 0})}
+ onMovePrevRequest={() =>
+ setModalState({
+ ...modalState,
+ index:
+ (modalState.index + galleryImages.images.length - 1) %
+ galleryImages.images.length,
+ })
+ }
+ onMoveNextRequest={() =>
+ setModalState({
+ ...modalState,
+ index: (modalState.index + 1) % galleryImages.images.length,
+ })
+ }
+ />
+ )}
+
+
);
- setgalleryImages(documents);
- }, [data, setgalleryImages, t]);
-
- return (
-
-
-
-
- refetch && refetch()}>
-
-
-
-
-
- {!billId && (
-
- )}
-
-
-
-
-
-
-
-
-
-
- {
- setModalState({ open: true, index: index });
- // window.open(
- // item.fullsize,
- // "_blank",
- // "toolbar=0,location=0,menubar=0"
- // );
- }}
- onSelect={(index, image) => {
- setgalleryImages({
- ...galleryImages,
- images: galleryImages.images.map((g, idx) =>
- index === idx ? { ...g, isSelected: !g.isSelected } : g
- ),
- });
- }}
- />
-
-
-
-
- {
- return {
- backgroundImage: ,
- height: "100%",
- width: "100%",
- cursor: "pointer",
- };
- }}
- onClick={(index) => {
- window.open(
- galleryImages.other[index].source,
- "_blank",
- "toolbar=0,location=0,menubar=0"
- );
- }}
- onSelect={(index) => {
- setgalleryImages({
- ...galleryImages,
- other: galleryImages.other.map((g, idx) =>
- index === idx ? { ...g, isSelected: !g.isSelected } : g
- ),
- });
- }}
- />
-
-
- {modalState.open && (
- {
- const newWindow = window.open(
- `${window.location.protocol}//${
- window.location.host
- }/edit?documentId=${
- galleryImages.images[modalState.index].id
- }`,
- "_blank",
- "noopener,noreferrer"
- );
- if (newWindow) newWindow.opener = null;
- }}
- />,
- ]}
- mainSrc={galleryImages.images[modalState.index].fullsize}
- nextSrc={
- galleryImages.images[
- (modalState.index + 1) % galleryImages.images.length
- ].fullsize
- }
- prevSrc={
- galleryImages.images[
- (modalState.index + galleryImages.images.length - 1) %
- galleryImages.images.length
- ].fullsize
- }
- onCloseRequest={() => setModalState({ open: false, index: 0 })}
- onMovePrevRequest={() =>
- setModalState({
- ...modalState,
- index:
- (modalState.index + galleryImages.images.length - 1) %
- galleryImages.images.length,
- })
- }
- onMoveNextRequest={() =>
- setModalState({
- ...modalState,
- index: (modalState.index + 1) % galleryImages.images.length,
- })
- }
- />
- )}
-
-
- );
}
+
export default JobsDocumentsComponent;
diff --git a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.container.jsx b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.container.jsx
index 0efe8b798..c2b765570 100644
--- a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.container.jsx
+++ b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.container.jsx
@@ -1,35 +1,35 @@
-import { useQuery } from "@apollo/client";
+import {useQuery} from "@apollo/client";
import React from "react";
-import { GET_DOCUMENTS_BY_JOB } from "../../graphql/documents.queries";
+import {GET_DOCUMENTS_BY_JOB} from "../../graphql/documents.queries";
import AlertComponent from "../alert/alert.component";
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
import JobDocuments from "./jobs-documents-gallery.component";
export default function JobsDocumentsContainer({
- jobId,
- billId,
- documentsList,
- billsCallback,
-}) {
- const { loading, error, data, refetch } = useQuery(GET_DOCUMENTS_BY_JOB, {
- variables: { jobId: jobId },
- fetchPolicy: "network-only",
- nextFetchPolicy: "network-only",
- skip: !!billId,
- });
+ jobId,
+ billId,
+ documentsList,
+ billsCallback,
+ }) {
+ const {loading, error, data, refetch} = useQuery(GET_DOCUMENTS_BY_JOB, {
+ variables: {jobId: jobId},
+ fetchPolicy: "network-only",
+ nextFetchPolicy: "network-only",
+ skip: !!billId,
+ });
- if (loading) return ;
- if (error) return ;
+ if (loading) return ;
+ if (error) return ;
- return (
-
- );
+ return (
+
+ );
}
diff --git a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.delete.component.jsx b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.delete.component.jsx
index ce5669df2..dee737273 100644
--- a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.delete.component.jsx
+++ b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.delete.component.jsx
@@ -1,62 +1,62 @@
-import { QuestionCircleOutlined } from "@ant-design/icons";
-import { Button, notification, Popconfirm } from "antd";
+import {QuestionCircleOutlined} from "@ant-design/icons";
+import {Button, notification, Popconfirm} from "antd";
import axios from "axios";
-import React, { useState } from "react";
-import { useTranslation } from "react-i18next";
-import { logImEXEvent } from "../../firebase/firebase.utils";
+import React, {useState} from "react";
+import {useTranslation} from "react-i18next";
+import {logImEXEvent} from "../../firebase/firebase.utils";
//Context: currentUserEmail, bodyshop, jobid, invoiceid
export default function JobsDocumentsDeleteButton({
- galleryImages,
- deletionCallback,
-}) {
- const { t } = useTranslation();
+ galleryImages,
+ deletionCallback,
+ }) {
+ const {t} = useTranslation();
- const imagesToDelete = [
- ...galleryImages.images.filter((image) => image.isSelected),
- ...galleryImages.other.filter((image) => image.isSelected),
- ];
- const [loading, setLoading] = useState(false);
+ const imagesToDelete = [
+ ...galleryImages.images.filter((image) => image.isSelected),
+ ...galleryImages.other.filter((image) => image.isSelected),
+ ];
+ const [loading, setLoading] = useState(false);
- const handleDelete = async () => {
- logImEXEvent("job_documents_delete", { count: imagesToDelete.length });
- setLoading(true);
- const res = await axios.post("/media/delete", {
- ids: imagesToDelete,
- });
+ const handleDelete = async () => {
+ logImEXEvent("job_documents_delete", {count: imagesToDelete.length});
+ setLoading(true);
+ const res = await axios.post("/media/delete", {
+ ids: imagesToDelete,
+ });
- if (res.data.error) {
- notification["error"]({
- message: t("documents.errors.deleting", {
- error: JSON.stringify(res.data.error.response.errors),
- }),
- });
- } else {
- notification.open({
- key: "docdeletedsuccesfully",
- type: "success",
- message: t("documents.successes.delete"),
- });
+ if (res.data.error) {
+ notification["error"]({
+ message: t("documents.errors.deleting", {
+ error: JSON.stringify(res.data.error.response.errors),
+ }),
+ });
+ } else {
+ notification.open({
+ key: "docdeletedsuccesfully",
+ type: "success",
+ message: t("documents.successes.delete"),
+ });
- if (deletionCallback) deletionCallback();
- }
+ if (deletionCallback) deletionCallback();
+ }
- setLoading(false);
- };
+ setLoading(false);
+ };
- return (
- }
- onConfirm={handleDelete}
- title={t("documents.labels.confirmdelete")}
- okText={t("general.actions.delete")}
- okButtonProps={{ type: "danger" }}
- cancelText={t("general.actions.cancel")}
- >
-
- {t("documents.actions.delete")}
-
-
- );
+ return (
+ }
+ onConfirm={handleDelete}
+ title={t("documents.labels.confirmdelete")}
+ okText={t("general.actions.delete")}
+ okButtonProps={{type: "danger"}}
+ cancelText={t("general.actions.cancel")}
+ >
+
+ {t("documents.actions.delete")}
+
+
+ );
}
diff --git a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.external.component.jsx b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.external.component.jsx
index 27774f5a8..6fa2344c4 100644
--- a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.external.component.jsx
+++ b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.external.component.jsx
@@ -1,53 +1,54 @@
-import React, { useEffect } from "react";
-import { Gallery } from "react-grid-gallery";
-import { useTranslation } from "react-i18next";
-import { GenerateSrcUrl, GenerateThumbUrl } from "./job-documents.utility";
+import React, {useEffect} from "react";
+import {Gallery} from "react-grid-gallery";
+import {useTranslation} from "react-i18next";
+import {GenerateSrcUrl, GenerateThumbUrl} from "./job-documents.utility";
function JobsDocumentGalleryExternal({
- data,
+ data,
- externalMediaState,
-}) {
- const [galleryImages, setgalleryImages] = externalMediaState;
- const { t } = useTranslation();
+ externalMediaState,
+ }) {
+ const [galleryImages, setgalleryImages] = externalMediaState;
+ const {t} = useTranslation();
- useEffect(() => {
- let documents = data.reduce((acc, value) => {
- if (value.type.startsWith("image")) {
- acc.push({
- fullsize: GenerateSrcUrl(value),
- src: GenerateThumbUrl(value),
- thumbnailHeight: 225,
- thumbnailWidth: 225,
- isSelected: false,
- key: value.key,
- extension: value.extension,
- id: value.id,
- type: value.type,
- tags: [{ value: value.type, title: value.type }],
- size: value.size,
- });
- }
+ useEffect(() => {
+ let documents = data.reduce((acc, value) => {
+ if (value.type.startsWith("image")) {
+ acc.push({
+ fullsize: GenerateSrcUrl(value),
+ src: GenerateThumbUrl(value),
+ thumbnailHeight: 225,
+ thumbnailWidth: 225,
+ isSelected: false,
+ key: value.key,
+ extension: value.extension,
+ id: value.id,
+ type: value.type,
+ tags: [{value: value.type, title: value.type}],
+ size: value.size,
+ });
+ }
- return acc;
- }, []);
- setgalleryImages(documents);
- }, [data, setgalleryImages, t]);
+ return acc;
+ }, []);
+ setgalleryImages(documents);
+ }, [data, setgalleryImages, t]);
- return (
-
- {
- setgalleryImages(
- galleryImages.map((g, idx) =>
- index === idx ? { ...g, isSelected: !g.isSelected } : g
- )
- );
- }}
- />
-
- );
+ return (
+
+ {
+ setgalleryImages(
+ galleryImages.map((g, idx) =>
+ index === idx ? {...g, isSelected: !g.isSelected} : g
+ )
+ );
+ }}
+ />
+
+ );
}
+
export default JobsDocumentGalleryExternal;
diff --git a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.selectall.component.jsx b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.selectall.component.jsx
index b140e2043..593c15f21 100644
--- a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.selectall.component.jsx
+++ b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.selectall.component.jsx
@@ -1,67 +1,67 @@
-import { Button, Space } from "antd";
+import {Button, Space} from "antd";
import React from "react";
-import { useTranslation } from "react-i18next";
+import {useTranslation} from "react-i18next";
export default function JobsDocumentsGallerySelectAllComponent({
- galleryImages,
- setGalleryImages,
-}) {
- const { t } = useTranslation();
+ galleryImages,
+ setGalleryImages,
+ }) {
+ const {t} = useTranslation();
- const handleSelectAll = () => {
- setGalleryImages({
- ...galleryImages,
- other: galleryImages.other.map((i) => {
- return { ...i, isSelected: true };
- }),
- images: galleryImages.images.map((i) => {
- return { ...i, isSelected: true };
- }),
- });
- };
- const handleSelectAllImages = () => {
- setGalleryImages({
- ...galleryImages,
+ const handleSelectAll = () => {
+ setGalleryImages({
+ ...galleryImages,
+ other: galleryImages.other.map((i) => {
+ return {...i, isSelected: true};
+ }),
+ images: galleryImages.images.map((i) => {
+ return {...i, isSelected: true};
+ }),
+ });
+ };
+ const handleSelectAllImages = () => {
+ setGalleryImages({
+ ...galleryImages,
- images: galleryImages.images.map((i) => {
- return { ...i, isSelected: true };
- }),
- });
- };
- const handleSelectAllDocuments = () => {
- setGalleryImages({
- ...galleryImages,
- other: galleryImages.other.map((i) => {
- return { ...i, isSelected: true };
- }),
- });
- };
- const handleDeselectAll = () => {
- setGalleryImages({
- ...galleryImages,
- other: galleryImages.other.map((i) => {
- return { ...i, isSelected: false };
- }),
- images: galleryImages.images.map((i) => {
- return { ...i, isSelected: false };
- }),
- });
- };
+ images: galleryImages.images.map((i) => {
+ return {...i, isSelected: true};
+ }),
+ });
+ };
+ const handleSelectAllDocuments = () => {
+ setGalleryImages({
+ ...galleryImages,
+ other: galleryImages.other.map((i) => {
+ return {...i, isSelected: true};
+ }),
+ });
+ };
+ const handleDeselectAll = () => {
+ setGalleryImages({
+ ...galleryImages,
+ other: galleryImages.other.map((i) => {
+ return {...i, isSelected: false};
+ }),
+ images: galleryImages.images.map((i) => {
+ return {...i, isSelected: false};
+ }),
+ });
+ };
- return (
-
-
- {t("general.actions.selectall")}
-
-
- {t("documents.actions.selectallimages")}
-
-
- {t("documents.actions.selectallotherdocuments")}
-
-
- {t("general.actions.deselectall")}
-
-
- );
+ return (
+
+
+ {t("general.actions.selectall")}
+
+
+ {t("documents.actions.selectallimages")}
+
+
+ {t("documents.actions.selectallotherdocuments")}
+
+
+ {t("general.actions.deselectall")}
+
+
+ );
}
diff --git a/client/src/components/jobs-documents-local-gallery/jobs-documents-local-gallery.container.jsx b/client/src/components/jobs-documents-local-gallery/jobs-documents-local-gallery.container.jsx
index f9889f3a6..f91daae96 100644
--- a/client/src/components/jobs-documents-local-gallery/jobs-documents-local-gallery.container.jsx
+++ b/client/src/components/jobs-documents-local-gallery/jobs-documents-local-gallery.container.jsx
@@ -1,18 +1,14 @@
-import { SyncOutlined, FileExcelFilled } from "@ant-design/icons";
-import { Alert, Button, Card, Space } from "antd";
-import React, { useEffect, useState } from "react";
-import { Gallery } from "react-grid-gallery";
-import { useTranslation } from "react-i18next";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import {
- getBillMedia,
- getJobMedia,
- toggleMediaSelected,
-} from "../../redux/media/media.actions";
-import { selectAllMedia } from "../../redux/media/media.selectors";
-import { selectBodyshop } from "../../redux/user/user.selectors";
-import { CreateExplorerLinkForJob } from "../../utils/localmedia";
+import {FileExcelFilled, SyncOutlined} from "@ant-design/icons";
+import {Alert, Button, Card, Space} from "antd";
+import React, {useEffect, useState} from "react";
+import {Gallery} from "react-grid-gallery";
+import {useTranslation} from "react-i18next";
+import {connect} from "react-redux";
+import {createStructuredSelector} from "reselect";
+import {getBillMedia, getJobMedia, toggleMediaSelected,} from "../../redux/media/media.actions";
+import {selectAllMedia} from "../../redux/media/media.selectors";
+import {selectBodyshop} from "../../redux/user/user.selectors";
+import {CreateExplorerLinkForJob} from "../../utils/localmedia";
import DocumentsLocalUploadComponent from "../documents-local-upload/documents-local-upload.component";
import JobsDocumentsLocalDeleteButton from "./jobs-documents-local-gallery.delete.component";
import JobsLocalGalleryDownloadButton from "./jobs-documents-local-gallery.download";
@@ -23,194 +19,194 @@ import Lightbox from "react-image-lightbox";
import "react-image-lightbox/style.css";
const mapStateToProps = createStructuredSelector({
- bodyshop: selectBodyshop,
- allMedia: selectAllMedia,
+ bodyshop: selectBodyshop,
+ allMedia: selectAllMedia,
});
const mapDispatchToProps = (dispatch) => ({
- getJobMedia: (id) => dispatch(getJobMedia(id)),
- getBillMedia: ({ jobid, invoice_number }) => {
- dispatch(getBillMedia({ jobid, invoice_number }));
- },
- toggleMediaSelected: ({ jobid, filename }) =>
- dispatch(toggleMediaSelected({ jobid, filename })),
+ getJobMedia: (id) => dispatch(getJobMedia(id)),
+ getBillMedia: ({jobid, invoice_number}) => {
+ dispatch(getBillMedia({jobid, invoice_number}));
+ },
+ toggleMediaSelected: ({jobid, filename}) =>
+ dispatch(toggleMediaSelected({jobid, filename})),
});
export default connect(
- mapStateToProps,
- mapDispatchToProps
+ mapStateToProps,
+ mapDispatchToProps
)(JobsDocumentsLocalGallery);
export function JobsDocumentsLocalGallery({
- bodyshop,
- toggleMediaSelected,
- getJobMedia,
- getBillMedia,
- allMedia,
- job,
- invoice_number,
- vendorid,
-}) {
- const { t } = useTranslation();
- const [modalState, setModalState] = useState({ open: false, index: 0 });
- useEffect(() => {
- if (job) {
- if (invoice_number) {
- getBillMedia({ jobid: job.id, invoice_number });
- } else {
- getJobMedia(job.id);
- }
- }
- }, [job, invoice_number, getJobMedia, getBillMedia]);
- let optimized;
- const jobMedia =
- allMedia && allMedia[job.id]
- ? allMedia[job.id].reduce(
- (acc, val) => {
- if (
- val.type &&
- val.type.mime &&
- val.type.mime.startsWith("image")
- ) {
- acc.images.push({
- ...val,
- fullsize: val.src,
- src: val.thumbnail,
- height: val.thumbnailHeight,
- width: val.thumbnailWidth,
- ...(val.optimized && { src: val.optimized, fullsize: val.src }),
- });
- if (val.optimized) optimized = true;
+ bodyshop,
+ toggleMediaSelected,
+ getJobMedia,
+ getBillMedia,
+ allMedia,
+ job,
+ invoice_number,
+ vendorid,
+ }) {
+ const {t} = useTranslation();
+ const [modalState, setModalState] = useState({open: false, index: 0});
+ useEffect(() => {
+ if (job) {
+ if (invoice_number) {
+ getBillMedia({jobid: job.id, invoice_number});
} else {
- acc.other.push({
- ...val,
- fullsize: val.src,
- src: val.thumbnail,
- height: val.thumbnailHeight,
- width: val.thumbnailWidth,
- tags: [{ value: val.filename, title: val.filename }],
- });
- }
- return acc;
- },
- { images: [], other: [] }
- )
- : { images: [], other: [] };
-
- return (
-
-
- {
- if (job) {
- if (invoice_number) {
- getBillMedia({ jobid: job.id, invoice_number });
- } else {
getJobMedia(job.id);
- }
}
- }}
- >
-
-
-
- {t("documents.labels.openinexplorer")}
-
-
-
-
-
-
-
-
-
-
- {
- toggleMediaSelected({ jobid: job.id, filename: image.filename });
- }}
- {...(optimized && {
- customControls: [
- ,
- ],
- })}
- onClick={(index) => {
- setModalState({ open: true, index: index });
- // const media = allMedia[job.id].find(
- // (m) => m.optimized === item.src
- // );
+ }
+ }, [job, invoice_number, getJobMedia, getBillMedia]);
+ let optimized;
+ const jobMedia =
+ allMedia && allMedia[job.id]
+ ? allMedia[job.id].reduce(
+ (acc, val) => {
+ if (
+ val.type &&
+ val.type.mime &&
+ val.type.mime.startsWith("image")
+ ) {
+ acc.images.push({
+ ...val,
+ fullsize: val.src,
+ src: val.thumbnail,
+ height: val.thumbnailHeight,
+ width: val.thumbnailWidth,
+ ...(val.optimized && {src: val.optimized, fullsize: val.src}),
+ });
+ if (val.optimized) optimized = true;
+ } else {
+ acc.other.push({
+ ...val,
+ fullsize: val.src,
+ src: val.thumbnail,
+ height: val.thumbnailHeight,
+ width: val.thumbnailWidth,
+ tags: [{value: val.filename, title: val.filename}],
+ });
+ }
+ return acc;
+ },
+ {images: [], other: []}
+ )
+ : {images: [], other: []};
- // window.open(
- // media ? media.fullsize : item.fullsize,
- // "_blank",
- // "toolbar=0,location=0,menubar=0"
- // );
- }}
- />
-
-
- {
- return {
- backgroundImage: ,
- height: "100%",
- width: "100%",
- cursor: "pointer",
- };
- }}
- onClick={(index) => {
- window.open(
- jobMedia.other[index].fullsize,
- "_blank",
- "toolbar=0,location=0,menubar=0"
- );
- }}
- onSelect={(index, image) => {
- toggleMediaSelected({ jobid: job.id, filename: image.filename });
- }}
- />
-
- {modalState.open && (
-
setModalState({ open: false, index: 0 })}
- onMovePrevRequest={() =>
- setModalState({
- ...modalState,
- index:
- (modalState.index + jobMedia.images.length - 1) %
- jobMedia.images.length,
- })
- }
- onMoveNextRequest={() =>
- setModalState({
- ...modalState,
- index: (modalState.index + 1) % jobMedia.images.length,
- })
- }
- />
- )}
-
- );
+ return (
+
+
+ {
+ if (job) {
+ if (invoice_number) {
+ getBillMedia({jobid: job.id, invoice_number});
+ } else {
+ getJobMedia(job.id);
+ }
+ }
+ }}
+ >
+
+
+
+ {t("documents.labels.openinexplorer")}
+
+
+
+
+
+
+
+
+
+
+ {
+ toggleMediaSelected({jobid: job.id, filename: image.filename});
+ }}
+ {...(optimized && {
+ customControls: [
+ ,
+ ],
+ })}
+ onClick={(index) => {
+ setModalState({open: true, index: index});
+ // const media = allMedia[job.id].find(
+ // (m) => m.optimized === item.src
+ // );
+
+ // window.open(
+ // media ? media.fullsize : item.fullsize,
+ // "_blank",
+ // "toolbar=0,location=0,menubar=0"
+ // );
+ }}
+ />
+
+
+ {
+ return {
+ backgroundImage: ,
+ height: "100%",
+ width: "100%",
+ cursor: "pointer",
+ };
+ }}
+ onClick={(index) => {
+ window.open(
+ jobMedia.other[index].fullsize,
+ "_blank",
+ "toolbar=0,location=0,menubar=0"
+ );
+ }}
+ onSelect={(index, image) => {
+ toggleMediaSelected({jobid: job.id, filename: image.filename});
+ }}
+ />
+
+ {modalState.open && (
+
setModalState({open: false, index: 0})}
+ onMovePrevRequest={() =>
+ setModalState({
+ ...modalState,
+ index:
+ (modalState.index + jobMedia.images.length - 1) %
+ jobMedia.images.length,
+ })
+ }
+ onMoveNextRequest={() =>
+ setModalState({
+ ...modalState,
+ index: (modalState.index + 1) % jobMedia.images.length,
+ })
+ }
+ />
+ )}
+
+ );
}
diff --git a/client/src/components/jobs-documents-local-gallery/jobs-documents-local-gallery.delete.component.jsx b/client/src/components/jobs-documents-local-gallery/jobs-documents-local-gallery.delete.component.jsx
index 0fe38256c..29af34e74 100644
--- a/client/src/components/jobs-documents-local-gallery/jobs-documents-local-gallery.delete.component.jsx
+++ b/client/src/components/jobs-documents-local-gallery/jobs-documents-local-gallery.delete.component.jsx
@@ -1,81 +1,81 @@
-import { QuestionCircleOutlined } from "@ant-design/icons";
-import { Button, notification, Popconfirm } from "antd";
-import React, { useState } from "react";
-import { useTranslation } from "react-i18next";
-import { logImEXEvent } from "../../firebase/firebase.utils";
+import {QuestionCircleOutlined} from "@ant-design/icons";
+import {Button, notification, Popconfirm} from "antd";
+import React, {useState} from "react";
+import {useTranslation} from "react-i18next";
+import {logImEXEvent} from "../../firebase/firebase.utils";
import cleanAxios from "../../utils/CleanAxios";
//Context: currentUserEmail, bodyshop, jobid, invoiceid
+import {connect} from "react-redux";
+import {createStructuredSelector} from "reselect";
+import {getJobMedia} from "../../redux/media/media.actions";
+import {selectAllMedia} from "../../redux/media/media.selectors";
+import {selectBodyshop} from "../../redux/user/user.selectors";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { getJobMedia } from "../../redux/media/media.actions";
-import { selectAllMedia } from "../../redux/media/media.selectors";
-import { selectBodyshop } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
- allMedia: selectAllMedia,
+ allMedia: selectAllMedia,
- bodyshop: selectBodyshop,
+ bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
- getJobMedia: (id) => dispatch(getJobMedia(id)),
+ getJobMedia: (id) => dispatch(getJobMedia(id)),
});
export default connect(
- mapStateToProps,
- mapDispatchToProps
+ mapStateToProps,
+ mapDispatchToProps
)(JobsDocumentsLocalDeleteButton);
export function JobsDocumentsLocalDeleteButton({
- bodyshop,
- getJobMedia,
- allMedia,
- jobid,
-}) {
- const { t } = useTranslation();
+ bodyshop,
+ getJobMedia,
+ allMedia,
+ jobid,
+ }) {
+ const {t} = useTranslation();
- const [loading, setLoading] = useState(false);
+ const [loading, setLoading] = useState(false);
- const handleDelete = async () => {
- logImEXEvent("job_documents_delete");
- setLoading(true);
+ const handleDelete = async () => {
+ logImEXEvent("job_documents_delete");
+ setLoading(true);
- const delres = await cleanAxios.post(
- `${bodyshop.localmediaserverhttp}/jobs/delete`,
- {
- jobid: jobid,
- files: ((allMedia && allMedia[jobid]) || [])
- .filter((i) => i.isSelected)
- .map((i) => i.filename),
- },
- { headers: { ims_token: bodyshop.localmediatoken } }
+ const delres = await cleanAxios.post(
+ `${bodyshop.localmediaserverhttp}/jobs/delete`,
+ {
+ jobid: jobid,
+ files: ((allMedia && allMedia[jobid]) || [])
+ .filter((i) => i.isSelected)
+ .map((i) => i.filename),
+ },
+ {headers: {ims_token: bodyshop.localmediatoken}}
+ );
+
+ if (delres.errors) {
+ notification["error"]({
+ message: t("documents.errors.deleting", {
+ message: JSON.stringify(delres.errors),
+ }),
+ });
+ } else {
+ notification.open({
+ key: "docdeletedsuccesfully",
+ type: "success",
+ message: t("documents.successes.delete"),
+ });
+ }
+ getJobMedia(jobid);
+ setLoading(false);
+ };
+
+ return (
+ }
+ onConfirm={handleDelete}
+ title={t("documents.labels.confirmdelete")}
+ okText={t("general.actions.delete")}
+ okButtonProps={{type: "danger"}}
+ cancelText={t("general.actions.cancel")}
+ >
+ {t("documents.actions.delete")}
+
);
-
- if (delres.errors) {
- notification["error"]({
- message: t("documents.errors.deleting", {
- message: JSON.stringify(delres.errors),
- }),
- });
- } else {
- notification.open({
- key: "docdeletedsuccesfully",
- type: "success",
- message: t("documents.successes.delete"),
- });
- }
- getJobMedia(jobid);
- setLoading(false);
- };
-
- return (
- }
- onConfirm={handleDelete}
- title={t("documents.labels.confirmdelete")}
- okText={t("general.actions.delete")}
- okButtonProps={{ type: "danger" }}
- cancelText={t("general.actions.cancel")}
- >
- {t("documents.actions.delete")}
-
- );
}
diff --git a/client/src/components/jobs-documents-local-gallery/jobs-documents-local-gallery.download.jsx b/client/src/components/jobs-documents-local-gallery/jobs-documents-local-gallery.download.jsx
index 57d186d69..02dff33a5 100644
--- a/client/src/components/jobs-documents-local-gallery/jobs-documents-local-gallery.download.jsx
+++ b/client/src/components/jobs-documents-local-gallery/jobs-documents-local-gallery.download.jsx
@@ -1,74 +1,75 @@
-import { Button } from "antd";
-import React, { useState } from "react";
-import { useTranslation } from "react-i18next";
+import {Button} from "antd";
+import React, {useState} from "react";
+import {useTranslation} from "react-i18next";
import cleanAxios from "../../utils/CleanAxios";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { selectAllMedia } from "../../redux/media/media.selectors";
-import { selectBodyshop } from "../../redux/user/user.selectors";
+import {connect} from "react-redux";
+import {createStructuredSelector} from "reselect";
+import {selectAllMedia} from "../../redux/media/media.selectors";
+import {selectBodyshop} from "../../redux/user/user.selectors";
+
const mapStateToProps = createStructuredSelector({
- bodyshop: selectBodyshop,
- allMedia: selectAllMedia,
+ bodyshop: selectBodyshop,
+ allMedia: selectAllMedia,
});
const mapDispatchToProps = (dispatch) => ({
- //setUserLanguage: language => dispatch(setUserLanguage(language))
+ //setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(
- mapStateToProps,
- mapDispatchToProps
+ mapStateToProps,
+ mapDispatchToProps
)(JobsLocalGalleryDownloadButton);
export function JobsLocalGalleryDownloadButton({
- bodyshop,
- galleryImages,
- allMedia,
- job,
-}) {
- const { t } = useTranslation();
- const [download, setDownload] = useState(null);
+ bodyshop,
+ galleryImages,
+ allMedia,
+ job,
+ }) {
+ const {t} = useTranslation();
+ const [download, setDownload] = useState(null);
- function downloadProgress(progressEvent) {
- setDownload((currentDownloadState) => {
- return {
- downloaded: progressEvent.loaded || 0,
- speed:
- (progressEvent.loaded || 0) -
- ((currentDownloadState && currentDownloadState.downloaded) || 0),
- };
- });
- }
+ function downloadProgress(progressEvent) {
+ setDownload((currentDownloadState) => {
+ return {
+ downloaded: progressEvent.loaded || 0,
+ speed:
+ (progressEvent.loaded || 0) -
+ ((currentDownloadState && currentDownloadState.downloaded) || 0),
+ };
+ });
+ }
- const handleDownload = async () => {
- const theDownloadedZip = await cleanAxios.post(
- `${bodyshop.localmediaserverhttp}/jobs/download`,
- {
- jobid: job.id,
- files: ((allMedia && allMedia[job.id]) || [])
- .filter((i) => i.isSelected)
- .map((i) => i.filename),
- },
- {
- headers: { ims_token: bodyshop.localmediatoken },
- responseType: "arraybuffer",
- onDownloadProgress: downloadProgress,
- }
+ const handleDownload = async () => {
+ const theDownloadedZip = await cleanAxios.post(
+ `${bodyshop.localmediaserverhttp}/jobs/download`,
+ {
+ jobid: job.id,
+ files: ((allMedia && allMedia[job.id]) || [])
+ .filter((i) => i.isSelected)
+ .map((i) => i.filename),
+ },
+ {
+ headers: {ims_token: bodyshop.localmediatoken},
+ responseType: "arraybuffer",
+ onDownloadProgress: downloadProgress,
+ }
+ );
+ setDownload(null);
+ standardMediaDownload(theDownloadedZip.data, job.ro_number);
+ };
+
+ return (
+
+ {t("documents.actions.download")}
+
);
- setDownload(null);
- standardMediaDownload(theDownloadedZip.data, job.ro_number);
- };
-
- return (
-
- {t("documents.actions.download")}
-
- );
}
function standardMediaDownload(bufferData, filename) {
- const a = document.createElement("a");
- const url = window.URL.createObjectURL(new Blob([bufferData]));
- a.href = url;
- a.download = `${filename}.zip`;
- a.click();
+ const a = document.createElement("a");
+ const url = window.URL.createObjectURL(new Blob([bufferData]));
+ a.href = url;
+ a.download = `${filename}.zip`;
+ a.click();
}
diff --git a/client/src/components/jobs-documents-local-gallery/jobs-documents-local-gallery.external.component.jsx b/client/src/components/jobs-documents-local-gallery/jobs-documents-local-gallery.external.component.jsx
index 19e18be1e..a1eef302d 100644
--- a/client/src/components/jobs-documents-local-gallery/jobs-documents-local-gallery.external.component.jsx
+++ b/client/src/components/jobs-documents-local-gallery/jobs-documents-local-gallery.external.component.jsx
@@ -1,82 +1,79 @@
-import React, { useEffect } from "react";
-import { Gallery } from "react-grid-gallery";
-import { useTranslation } from "react-i18next";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import {
- getJobMedia,
- toggleMediaSelected,
-} from "../../redux/media/media.actions";
-import { selectAllMedia } from "../../redux/media/media.selectors";
-import { selectBodyshop } from "../../redux/user/user.selectors";
+import React, {useEffect} from "react";
+import {Gallery} from "react-grid-gallery";
+import {useTranslation} from "react-i18next";
+import {connect} from "react-redux";
+import {createStructuredSelector} from "reselect";
+import {getJobMedia, toggleMediaSelected,} from "../../redux/media/media.actions";
+import {selectAllMedia} from "../../redux/media/media.selectors";
+import {selectBodyshop} from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
- bodyshop: selectBodyshop,
- allMedia: selectAllMedia,
+ bodyshop: selectBodyshop,
+ allMedia: selectAllMedia,
});
const mapDispatchToProps = (dispatch) => ({
- getJobMedia: (id) => dispatch(getJobMedia(id)),
+ getJobMedia: (id) => dispatch(getJobMedia(id)),
- toggleMediaSelected: ({ jobid, filename }) =>
- dispatch(toggleMediaSelected({ jobid, filename })),
+ toggleMediaSelected: ({jobid, filename}) =>
+ dispatch(toggleMediaSelected({jobid, filename})),
});
export default connect(
- mapStateToProps,
- mapDispatchToProps
+ mapStateToProps,
+ mapDispatchToProps
)(JobDocumentsLocalGalleryExternal);
function JobDocumentsLocalGalleryExternal({
- jobId,
- externalMediaState,
- getJobMedia,
- toggleMediaSelected,
- allMedia,
-}) {
- const [galleryImages, setgalleryImages] = externalMediaState;
- const { t } = useTranslation();
+ jobId,
+ externalMediaState,
+ getJobMedia,
+ toggleMediaSelected,
+ allMedia,
+ }) {
+ const [galleryImages, setgalleryImages] = externalMediaState;
+ const {t} = useTranslation();
- useEffect(() => {
- if (jobId) {
- getJobMedia(jobId);
- }
- }, [jobId, getJobMedia]);
+ useEffect(() => {
+ if (jobId) {
+ getJobMedia(jobId);
+ }
+ }, [jobId, getJobMedia]);
- useEffect(() => {
- let documents =
- allMedia && allMedia[jobId]
- ? allMedia[jobId].reduce((acc, val) => {
- if (
- val.type &&
- val.type.mime &&
- val.type.mime.startsWith("image")
- ) {
- acc.push({ ...val, src: val.thumbnail, fullsize: val.src });
- }
- return acc;
- }, [])
- : [];
- console.log(
- "🚀 ~ file: jobs-documents-local-gallery.external.component.jsx:48 ~ useEffect ~ documents:",
- documents
+ useEffect(() => {
+ let documents =
+ allMedia && allMedia[jobId]
+ ? allMedia[jobId].reduce((acc, val) => {
+ if (
+ val.type &&
+ val.type.mime &&
+ val.type.mime.startsWith("image")
+ ) {
+ acc.push({...val, src: val.thumbnail, fullsize: val.src});
+ }
+ return acc;
+ }, [])
+ : [];
+ console.log(
+ "🚀 ~ file: jobs-documents-local-gallery.external.component.jsx:48 ~ useEffect ~ documents:",
+ documents
+ );
+
+ setgalleryImages(documents);
+ }, [allMedia, jobId, setgalleryImages, t]);
+
+ return (
+
+ {
+ setgalleryImages(
+ galleryImages.map((g, idx) =>
+ index === idx ? {...g, isSelected: !g.isSelected} : g
+ )
+ );
+ }}
+ />
+
);
-
- setgalleryImages(documents);
- }, [allMedia, jobId, setgalleryImages, t]);
-
- return (
-
- {
- setgalleryImages(
- galleryImages.map((g, idx) =>
- index === idx ? { ...g, isSelected: !g.isSelected } : g
- )
- );
- }}
- />
-
- );
}
diff --git a/client/src/components/jobs-documents-local-gallery/jobs-documents-local-gallery.reassign.component.jsx b/client/src/components/jobs-documents-local-gallery/jobs-documents-local-gallery.reassign.component.jsx
index 74c5a52b9..b27474a14 100644
--- a/client/src/components/jobs-documents-local-gallery/jobs-documents-local-gallery.reassign.component.jsx
+++ b/client/src/components/jobs-documents-local-gallery/jobs-documents-local-gallery.reassign.component.jsx
@@ -1,96 +1,96 @@
-import { Button, Form, Popover, Space } from "antd";
-import React, { useState } from "react";
-import { useTranslation } from "react-i18next";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { getJobMedia } from "../../redux/media/media.actions";
-import { selectAllMedia } from "../../redux/media/media.selectors";
-import { selectBodyshop } from "../../redux/user/user.selectors";
+import {Button, Form, Popover, Space} from "antd";
+import React, {useState} from "react";
+import {useTranslation} from "react-i18next";
+import {connect} from "react-redux";
+import {createStructuredSelector} from "reselect";
+import {getJobMedia} from "../../redux/media/media.actions";
+import {selectAllMedia} from "../../redux/media/media.selectors";
+import {selectBodyshop} from "../../redux/user/user.selectors";
import cleanAxios from "../../utils/CleanAxios";
import JobSearchSelect from "../job-search-select/job-search-select.component";
const mapStateToProps = createStructuredSelector({
- allMedia: selectAllMedia,
- bodyshop: selectBodyshop,
+ allMedia: selectAllMedia,
+ bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
- getJobMedia: (id) => dispatch(getJobMedia(id)),
+ getJobMedia: (id) => dispatch(getJobMedia(id)),
- //setUserLanguage: language => dispatch(setUserLanguage(language))
+ //setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(
- mapStateToProps,
- mapDispatchToProps
+ mapStateToProps,
+ mapDispatchToProps
)(JobsDocumentsLocalGalleryReassign);
export function JobsDocumentsLocalGalleryReassign({
- bodyshop,
- jobid,
- allMedia,
- getJobMedia,
-}) {
- const { t } = useTranslation();
- const [form] = Form.useForm();
+ bodyshop,
+ jobid,
+ allMedia,
+ getJobMedia,
+ }) {
+ const {t} = useTranslation();
+ const [form] = Form.useForm();
- const [visible, setVisible] = useState(false);
- const [loading, setLoading] = useState(false);
+ const [open, setOpen] = useState(false);
+ const [loading, setLoading] = useState(false);
- const handleFinish = async ({ jobid: newJobid }) => {
- setLoading(true);
- const selectedDocuments = allMedia[jobid].filter((m) => m.isSelected);
+ const handleFinish = async ({jobid: newJobid}) => {
+ setLoading(true);
+ const selectedDocuments = allMedia[jobid].filter((m) => m.isSelected);
- await cleanAxios.post(
- `${bodyshop.localmediaserverhttp}/jobs/move`,
- {
- from_jobid: jobid,
- jobid: newJobid,
- files: selectedDocuments.map((f) => f.filename),
- },
- { headers: { ims_token: bodyshop.localmediatoken } }
+ await cleanAxios.post(
+ `${bodyshop.localmediaserverhttp}/jobs/move`,
+ {
+ from_jobid: jobid,
+ jobid: newJobid,
+ files: selectedDocuments.map((f) => f.filename),
+ },
+ {headers: {ims_token: bodyshop.localmediatoken}}
+ );
+
+ getJobMedia(jobid);
+ setOpen(false);
+ setLoading(false);
+ };
+
+ const popContent = (
+
+
+
+
+
+
+ form.submit()}>
+ {t("general.actions.submit")}
+
+ setOpen(false)}>
+ {t("general.actions.cancel")}
+
+
+
);
- getJobMedia(jobid);
- setVisible(false);
- setLoading(false);
- };
-
- const popContent = (
-
-
-
-
-
-
- form.submit()}>
- {t("general.actions.submit")}
-
- setVisible(false)}>
- {t("general.actions.cancel")}
-
-
-
- );
-
- return (
-
- setVisible(true)}
- loading={loading}
- >
- {t("documents.actions.reassign")}
-
-
- );
+ return (
+
+ setOpen(true)}
+ loading={loading}
+ >
+ {t("documents.actions.reassign")}
+
+
+ );
}
diff --git a/client/src/components/jobs-documents-local-gallery/jobs-documents-local-gallery.selectall.component.jsx b/client/src/components/jobs-documents-local-gallery/jobs-documents-local-gallery.selectall.component.jsx
index 459a1fdac..a8c41d2ac 100644
--- a/client/src/components/jobs-documents-local-gallery/jobs-documents-local-gallery.selectall.component.jsx
+++ b/client/src/components/jobs-documents-local-gallery/jobs-documents-local-gallery.selectall.component.jsx
@@ -1,53 +1,51 @@
-import { Button, Space } from "antd";
+import {Button, Space} from "antd";
import React from "react";
-import { useTranslation } from "react-i18next";
+import {useTranslation} from "react-i18next";
+
+import {connect} from "react-redux";
+import {createStructuredSelector} from "reselect";
+import {deselectAllMediaForJob, selectAllmediaForJob,} from "../../redux/media/media.actions";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import {
- selectAllmediaForJob,
- deselectAllMediaForJob,
-} from "../../redux/media/media.actions";
const mapStateToProps = createStructuredSelector({
- //currentUser: selectCurrentUser
+ //currentUser: selectCurrentUser
});
const mapDispatchToProps = (dispatch) => ({
- selectAllmediaForJob: (jobid) => dispatch(selectAllmediaForJob(jobid)),
- deselectAllmediaForJob: (jobid) => dispatch(deselectAllMediaForJob(jobid)),
+ selectAllmediaForJob: (jobid) => dispatch(selectAllmediaForJob(jobid)),
+ deselectAllmediaForJob: (jobid) => dispatch(deselectAllMediaForJob(jobid)),
});
export default connect(
- mapStateToProps,
- mapDispatchToProps
+ mapStateToProps,
+ mapDispatchToProps
)(JobsDocumentsLocalGallerySelectAllComponent);
export function JobsDocumentsLocalGallerySelectAllComponent({
- jobid,
- selectAllmediaForJob,
- deselectAllmediaForJob,
-}) {
- const { t } = useTranslation();
+ jobid,
+ selectAllmediaForJob,
+ deselectAllmediaForJob,
+ }) {
+ const {t} = useTranslation();
- // onSelectImage={(index, image) => {
- // toggleMediaSelected({ jobid: job.id, filename: image.filename });
- // }}
+ // onSelectImage={(index, image) => {
+ // toggleMediaSelected({ jobid: job.id, filename: image.filename });
+ // }}
- const handleSelectAll = () => {
- selectAllmediaForJob({ jobid });
- };
+ const handleSelectAll = () => {
+ selectAllmediaForJob({jobid});
+ };
- const handleDeselectAll = () => {
- deselectAllmediaForJob({ jobid });
- };
+ const handleDeselectAll = () => {
+ deselectAllmediaForJob({jobid});
+ };
- return (
-
-
- {t("general.actions.selectall")}
-
+ return (
+
+
+ {t("general.actions.selectall")}
+
-
- {t("general.actions.deselectall")}
-
-
- );
+
+ {t("general.actions.deselectall")}
+
+
+ );
}
diff --git a/client/src/components/jobs-export-all-button/jobs-export-all-button.component.jsx b/client/src/components/jobs-export-all-button/jobs-export-all-button.component.jsx
index 3204d7311..919e71421 100644
--- a/client/src/components/jobs-export-all-button/jobs-export-all-button.component.jsx
+++ b/client/src/components/jobs-export-all-button/jobs-export-all-button.component.jsx
@@ -1,228 +1,225 @@
-import { useMutation } from "@apollo/client";
-import { Button, notification } from "antd";
+import {useMutation} from "@apollo/client";
+import {Button, notification} from "antd";
import axios from "axios";
import _ from "lodash";
-import React, { useState } from "react";
-import { useTranslation } from "react-i18next";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { auth, logImEXEvent } from "../../firebase/firebase.utils";
-import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
-import { UPDATE_JOBS } from "../../graphql/jobs.queries";
-import {
- selectBodyshop,
- selectCurrentUser,
-} from "../../redux/user/user.selectors";
+import React, {useState} from "react";
+import {useTranslation} from "react-i18next";
+import {connect} from "react-redux";
+import {createStructuredSelector} from "reselect";
+import {auth, logImEXEvent} from "../../firebase/firebase.utils";
+import {INSERT_EXPORT_LOG} from "../../graphql/accounting.queries";
+import {UPDATE_JOBS} from "../../graphql/jobs.queries";
+import {selectBodyshop, selectCurrentUser,} from "../../redux/user/user.selectors";
import client from "../../utils/GraphQLClient";
const mapStateToProps = createStructuredSelector({
- bodyshop: selectBodyshop,
- currentUser: selectCurrentUser,
+ bodyshop: selectBodyshop,
+ currentUser: selectCurrentUser,
});
function updateJobCache(items) {
- client.cache.modify({
- id: "ROOT_QUERY",
- fields: {
- jobs(existingJobs = []) {
- return existingJobs.filter(
- (jobRef) => jobRef.__ref.includes(items) === false
- );
- },
- },
- });
+ client.cache.modify({
+ id: "ROOT_QUERY",
+ fields: {
+ jobs(existingJobs = []) {
+ return existingJobs.filter(
+ (jobRef) => jobRef.__ref.includes(items) === false
+ );
+ },
+ },
+ });
}
export function JobsExportAllButton({
- bodyshop,
- currentUser,
- jobIds,
- disabled,
- loadingCallback,
- completedCallback,
- refetch,
-}) {
- const { t } = useTranslation();
- const [updateJob] = useMutation(UPDATE_JOBS);
- const [insertExportLog] = useMutation(INSERT_EXPORT_LOG);
+ bodyshop,
+ currentUser,
+ jobIds,
+ disabled,
+ loadingCallback,
+ completedCallback,
+ refetch,
+ }) {
+ const {t} = useTranslation();
+ const [updateJob] = useMutation(UPDATE_JOBS);
+ const [insertExportLog] = useMutation(INSERT_EXPORT_LOG);
- const [loading, setLoading] = useState(false);
- const handleQbxml = async () => {
- logImEXEvent("jobs_export_all");
- let PartnerResponse;
- setLoading(true);
- if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) {
- PartnerResponse = await axios.post(`/qbo/receivables`, {
- jobIds: jobIds,
- elgen: true,
- });
- } else {
- let QbXmlResponse;
- try {
- QbXmlResponse = await axios.post(
- "/accounting/qbxml/receivables",
- { jobIds: jobIds },
- {
- headers: {
- Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
- },
- }
- );
- } catch (error) {
- console.log("Error getting QBXML from Server.", error);
- notification["error"]({
- message: t("jobs.errors.exporting", {
- error: "Unable to retrieve QBXML. " + JSON.stringify(error.message),
- }),
- });
- setLoading(false);
- return;
- }
-
- try {
- PartnerResponse = await axios.post(
- "http://localhost:1337/qb/",
- // "http://609feaeae986.ngrok.io/qb/",
- QbXmlResponse.data,
- {
- headers: {
- Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
- },
- }
- );
- } catch (error) {
- console.log("Error connecting to quickbooks or partner.", error);
- notification["error"]({
- message: t("jobs.errors.exporting-partner"),
- });
- setLoading(false);
- return;
- }
- }
-
- console.log("PartnerResponse", PartnerResponse);
- const groupedData = _.groupBy(
- PartnerResponse.data,
- bodyshop.accountingconfig.qbo ? "jobid" : "id"
- );
-
- await Promise.all(
- Object.keys(groupedData).map(async (key) => {
- //Check to see if any of them failed. If they didn't don't execute the update.
- const failedTransactions = groupedData[key].filter((r) => !r.success);
- const successfulTransactions = groupedData[key].filter(
- (r) => r.success
- );
- if (failedTransactions.length > 0) {
- //Uh oh. At least one was no good.
- failedTransactions.forEach((ft) => {
- notification.open({
- // key: "failedexports",
- type: "error",
- message: t("jobs.errors.exporting", {
- error: ft.errorMessage || "",
- }),
+ const [loading, setLoading] = useState(false);
+ const handleQbxml = async () => {
+ logImEXEvent("jobs_export_all");
+ let PartnerResponse;
+ setLoading(true);
+ if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) {
+ PartnerResponse = await axios.post(`/qbo/receivables`, {
+ jobIds: jobIds,
+ elgen: true,
});
- //Call is not awaited as it is not critical to finish before proceeding.
- });
-
- if (!(bodyshop.accountingconfig && bodyshop.accountingconfig.qbo)) {
- //QBO Logs are handled server side.
- await insertExportLog({
- variables: {
- logs: [
- {
- bodyshopid: bodyshop.id,
- jobid: key,
- successful: false,
- message: JSON.stringify(
- failedTransactions.map((ft) => ft.errorMessage)
- ),
- useremail: currentUser.email,
- },
- ],
- },
- });
- }
} else {
- if (!(bodyshop.accountingconfig && bodyshop.accountingconfig.qbo)) {
- //QBO Logs are handled server side.
- await insertExportLog({
- variables: {
- logs: [
- {
- bodyshopid: bodyshop.id,
- jobid: key,
- successful: true,
- useremail: currentUser.email,
- },
- ],
- },
- });
-
- const jobUpdateResponse = await updateJob({
- variables: {
- jobIds: [key],
- fields: {
- status:
- bodyshop.md_ro_statuses.default_exported || "Exported*",
- date_exported: new Date(),
- },
- },
- });
-
- if (!!!jobUpdateResponse.errors) {
- notification.open({
- type: "success",
- key: "jobsuccessexport",
- message: t("jobs.successes.exported"),
- });
- updateJobCache(
- jobUpdateResponse.data.update_jobs.returning.map(
- (job) => job.id
- )
- );
- } else {
- notification["error"]({
- message: t("jobs.errors.exporting", {
- error: JSON.stringify(jobUpdateResponse.error),
- }),
- });
+ let QbXmlResponse;
+ try {
+ QbXmlResponse = await axios.post(
+ "/accounting/qbxml/receivables",
+ {jobIds: jobIds},
+ {
+ headers: {
+ Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
+ },
+ }
+ );
+ } catch (error) {
+ console.log("Error getting QBXML from Server.", error);
+ notification["error"]({
+ message: t("jobs.errors.exporting", {
+ error: "Unable to retrieve QBXML. " + JSON.stringify(error.message),
+ }),
+ });
+ setLoading(false);
+ return;
+ }
+
+ try {
+ PartnerResponse = await axios.post(
+ "http://localhost:1337/qb/",
+ // "http://609feaeae986.ngrok.io/qb/",
+ QbXmlResponse.data,
+ {
+ headers: {
+ Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
+ },
+ }
+ );
+ } catch (error) {
+ console.log("Error connecting to quickbooks or partner.", error);
+ notification["error"]({
+ message: t("jobs.errors.exporting-partner"),
+ });
+ setLoading(false);
+ return;
}
- }
- if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && successfulTransactions.length > 0) {
- notification.open({
- type: "success",
- key: "jobsuccessexport",
- message: t("jobs.successes.exported"),
- });
- updateJobCache([
- ...new Set(
- successfulTransactions.map(
- (st) =>
- st[
- bodyshop.accountingconfig && bodyshop.accountingconfig.qbo
- ? "jobid"
- : "id"
- ]
- )
- ),
- ]);
- }
}
- })
+
+ console.log("PartnerResponse", PartnerResponse);
+ const groupedData = _.groupBy(
+ PartnerResponse.data,
+ bodyshop.accountingconfig.qbo ? "jobid" : "id"
+ );
+
+ await Promise.all(
+ Object.keys(groupedData).map(async (key) => {
+ //Check to see if any of them failed. If they didn't don't execute the update.
+ const failedTransactions = groupedData[key].filter((r) => !r.success);
+ const successfulTransactions = groupedData[key].filter(
+ (r) => r.success
+ );
+ if (failedTransactions.length > 0) {
+ //Uh oh. At least one was no good.
+ failedTransactions.forEach((ft) => {
+ notification.open({
+ // key: "failedexports",
+ type: "error",
+ message: t("jobs.errors.exporting", {
+ error: ft.errorMessage || "",
+ }),
+ });
+ //Call is not awaited as it is not critical to finish before proceeding.
+ });
+
+ if (!(bodyshop.accountingconfig && bodyshop.accountingconfig.qbo)) {
+ //QBO Logs are handled server side.
+ await insertExportLog({
+ variables: {
+ logs: [
+ {
+ bodyshopid: bodyshop.id,
+ jobid: key,
+ successful: false,
+ message: JSON.stringify(
+ failedTransactions.map((ft) => ft.errorMessage)
+ ),
+ useremail: currentUser.email,
+ },
+ ],
+ },
+ });
+ }
+ } else {
+ if (!(bodyshop.accountingconfig && bodyshop.accountingconfig.qbo)) {
+ //QBO Logs are handled server side.
+ await insertExportLog({
+ variables: {
+ logs: [
+ {
+ bodyshopid: bodyshop.id,
+ jobid: key,
+ successful: true,
+ useremail: currentUser.email,
+ },
+ ],
+ },
+ });
+
+ const jobUpdateResponse = await updateJob({
+ variables: {
+ jobIds: [key],
+ fields: {
+ status:
+ bodyshop.md_ro_statuses.default_exported || "Exported*",
+ date_exported: new Date(),
+ },
+ },
+ });
+
+ if (!!!jobUpdateResponse.errors) {
+ notification.open({
+ type: "success",
+ key: "jobsuccessexport",
+ message: t("jobs.successes.exported"),
+ });
+ updateJobCache(
+ jobUpdateResponse.data.update_jobs.returning.map(
+ (job) => job.id
+ )
+ );
+ } else {
+ notification["error"]({
+ message: t("jobs.errors.exporting", {
+ error: JSON.stringify(jobUpdateResponse.error),
+ }),
+ });
+ }
+ }
+ if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && successfulTransactions.length > 0) {
+ notification.open({
+ type: "success",
+ key: "jobsuccessexport",
+ message: t("jobs.successes.exported"),
+ });
+ updateJobCache([
+ ...new Set(
+ successfulTransactions.map(
+ (st) =>
+ st[
+ bodyshop.accountingconfig && bodyshop.accountingconfig.qbo
+ ? "jobid"
+ : "id"
+ ]
+ )
+ ),
+ ]);
+ }
+ }
+ })
+ );
+
+ if (!!completedCallback) completedCallback([]);
+ if (!!loadingCallback) loadingCallback(false);
+ setLoading(false);
+ };
+
+ return (
+
+ {t("jobs.actions.exportselected")}
+
);
-
- if (!!completedCallback) completedCallback([]);
- if (!!loadingCallback) loadingCallback(false);
- setLoading(false);
- };
-
- return (
-
- {t("jobs.actions.exportselected")}
-
- );
}
export default connect(mapStateToProps, null)(JobsExportAllButton);
diff --git a/client/src/components/jobs-find-modal/jobs-find-modal.component.jsx b/client/src/components/jobs-find-modal/jobs-find-modal.component.jsx
index 37a88e1ef..a52988e1c 100644
--- a/client/src/components/jobs-find-modal/jobs-find-modal.component.jsx
+++ b/client/src/components/jobs-find-modal/jobs-find-modal.component.jsx
@@ -1,212 +1,212 @@
-import { SyncOutlined } from "@ant-design/icons";
-import { Checkbox, Divider, Input, Table, Button } from "antd";
+import {SyncOutlined} from "@ant-design/icons";
+import {Button, Checkbox, Divider, Input, Table} from "antd";
import React from "react";
-import { useTranslation } from "react-i18next";
-import { Link } from "react-router-dom";
+import {useTranslation} from "react-i18next";
+import {Link} from "react-router-dom";
import PhoneFormatter from "../../utils/PhoneFormatter";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
export default function JobsFindModalComponent({
- selectedJob,
- setSelectedJob,
- jobsList,
- jobsListLoading,
- importOptionsState,
- modalSearchState,
- jobsListRefetch,
- partsQueueToggle,
- setPartsQueueToggle,
-}) {
- const { t } = useTranslation();
- const [modalSearch, setModalSearch] = modalSearchState;
- const [importOptions, setImportOptions] = importOptionsState;
+ selectedJob,
+ setSelectedJob,
+ jobsList,
+ jobsListLoading,
+ importOptionsState,
+ modalSearchState,
+ jobsListRefetch,
+ partsQueueToggle,
+ setPartsQueueToggle,
+ }) {
+ const {t} = useTranslation();
+ const [modalSearch, setModalSearch] = modalSearchState;
+ const [importOptions, setImportOptions] = importOptionsState;
- const columns = [
- {
- title: t("jobs.fields.ro_number"),
- dataIndex: "ro_number",
- key: "ro_number",
- width: "8%",
- render: (text, record) => (
-
+ const columns = [
+ {
+ title: t("jobs.fields.ro_number"),
+ dataIndex: "ro_number",
+ key: "ro_number",
+ width: "8%",
+ render: (text, record) => (
+
{record.ro_number || t("general.labels.na")}
- ),
- },
- {
- title: t("jobs.fields.owner"),
- dataIndex: "owner",
- key: "owner",
- ellipsis: true,
+ ),
+ },
+ {
+ title: t("jobs.fields.owner"),
+ dataIndex: "owner",
+ key: "owner",
+ ellipsis: true,
- width: "25%",
+ width: "25%",
- render: (text, record) => {
- return record.owner ? (
-
-
-
- ) : (
-
-
+ render: (text, record) => {
+ return record.owner ? (
+
+
+
+ ) : (
+
+
- );
- },
- },
- {
- title: t("jobs.fields.ownr_ph1"),
- dataIndex: "ownr_ph1",
- key: "ownr_ph1",
- width: "12%",
- ellipsis: true,
- render: (text, record) => {
- return record.ownr_ph1 ? (
- {record.ownr_ph1}
- ) : (
- t("general.labels.unknown")
- );
- },
- },
- {
- title: t("jobs.fields.ownr_ph2"),
- dataIndex: "ownr_ph2",
- key: "ownr_ph2",
- width: "12%",
- ellipsis: true,
- render: (text, record) => {
- return record.ownr_ph2 ? (
- {record.ownr_ph2}
- ) : (
- t("general.labels.unknown")
- );
- },
- },
- {
- title: t("jobs.fields.status"),
- dataIndex: "status",
- key: "status",
- width: "10%",
- ellipsis: true,
- render: (text, record) => {
- return record.status || t("general.labels.na");
- },
- },
-
- {
- title: t("jobs.fields.vehicle"),
- dataIndex: "vehicle",
- key: "vehicle",
- width: "15%",
- ellipsis: true,
- render: (text, record) => (
-
- {`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
- record.v_model_desc || ""
- }`}
-
- ),
- },
- {
- title: t("vehicles.fields.plate_no"),
- dataIndex: "plate_no",
- key: "plate_no",
- width: "8%",
- ellipsis: true,
- render: (text, record) => {
- return record.plate_no ? (
- {record.plate_no}
- ) : (
- t("general.labels.unknown")
- );
- },
- },
- {
- title: t("jobs.fields.clm_no"),
- dataIndex: "clm_no",
- key: "clm_no",
- width: "12%",
- ellipsis: true,
- render: (text, record) => {
- return record.clm_no ? (
- {record.clm_no}
- ) : (
- t("general.labels.unknown")
- );
- },
- },
- ];
-
- const handleOnRowClick = (record) => {
- if (record) {
- if (record.id) {
- setSelectedJob(record.id);
- return;
- }
- }
- setSelectedJob(null);
- };
-
- return (
-
-
(
-
- {t("jobs.labels.existing_jobs")}
- {
- jobsListRefetch();
- }}
- >
-
-
- {
- setModalSearch(e.target.value);
- }}
- />
-
- )}
- pagination={{ position: "bottom" }}
- columns={columns}
- rowKey="id"
- loading={jobsListLoading}
- dataSource={jobsList}
- rowSelection={{
- onSelect: (props) => {
- setSelectedJob(props.id);
- },
- type: "radio",
- selectedRowKeys: [selectedJob],
- }}
- onRow={(record, rowIndex) => {
- return {
- onClick: (event) => {
- handleOnRowClick(record);
+ );
},
- };
- }}
- />
-
-
- setImportOptions({
- ...importOptions,
- overrideHeaders: e.target.checked,
- })
+ },
+ {
+ title: t("jobs.fields.ownr_ph1"),
+ dataIndex: "ownr_ph1",
+ key: "ownr_ph1",
+ width: "12%",
+ ellipsis: true,
+ render: (text, record) => {
+ return record.ownr_ph1 ? (
+ {record.ownr_ph1}
+ ) : (
+ t("general.labels.unknown")
+ );
+ },
+ },
+ {
+ title: t("jobs.fields.ownr_ph2"),
+ dataIndex: "ownr_ph2",
+ key: "ownr_ph2",
+ width: "12%",
+ ellipsis: true,
+ render: (text, record) => {
+ return record.ownr_ph2 ? (
+ {record.ownr_ph2}
+ ) : (
+ t("general.labels.unknown")
+ );
+ },
+ },
+ {
+ title: t("jobs.fields.status"),
+ dataIndex: "status",
+ key: "status",
+ width: "10%",
+ ellipsis: true,
+ render: (text, record) => {
+ return record.status || t("general.labels.na");
+ },
+ },
+
+ {
+ title: t("jobs.fields.vehicle"),
+ dataIndex: "vehicle",
+ key: "vehicle",
+ width: "15%",
+ ellipsis: true,
+ render: (text, record) => (
+
+ {`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
+ record.v_model_desc || ""
+ }`}
+
+ ),
+ },
+ {
+ title: t("vehicles.fields.plate_no"),
+ dataIndex: "plate_no",
+ key: "plate_no",
+ width: "8%",
+ ellipsis: true,
+ render: (text, record) => {
+ return record.plate_no ? (
+ {record.plate_no}
+ ) : (
+ t("general.labels.unknown")
+ );
+ },
+ },
+ {
+ title: t("jobs.fields.clm_no"),
+ dataIndex: "clm_no",
+ key: "clm_no",
+ width: "12%",
+ ellipsis: true,
+ render: (text, record) => {
+ return record.clm_no ? (
+ {record.clm_no}
+ ) : (
+ t("general.labels.unknown")
+ );
+ },
+ },
+ ];
+
+ const handleOnRowClick = (record) => {
+ if (record) {
+ if (record.id) {
+ setSelectedJob(record.id);
+ return;
+ }
}
- >
- {t("jobs.labels.override_header")}
-
- setPartsQueueToggle(e.target.checked)}
- >
- {t("bodyshop.fields.md_functionality_toggles.parts_queue_toggle")}
-
-
- );
+ setSelectedJob(null);
+ };
+
+ return (
+
+
(
+
+ {t("jobs.labels.existing_jobs")}
+ {
+ jobsListRefetch();
+ }}
+ >
+
+
+ {
+ setModalSearch(e.target.value);
+ }}
+ />
+
+ )}
+ pagination={{position: "bottom"}}
+ columns={columns}
+ rowKey="id"
+ loading={jobsListLoading}
+ dataSource={jobsList}
+ rowSelection={{
+ onSelect: (props) => {
+ setSelectedJob(props.id);
+ },
+ type: "radio",
+ selectedRowKeys: [selectedJob],
+ }}
+ onRow={(record, rowIndex) => {
+ return {
+ onClick: (event) => {
+ handleOnRowClick(record);
+ },
+ };
+ }}
+ />
+
+
+ setImportOptions({
+ ...importOptions,
+ overrideHeaders: e.target.checked,
+ })
+ }
+ >
+ {t("jobs.labels.override_header")}
+
+ setPartsQueueToggle(e.target.checked)}
+ >
+ {t("bodyshop.fields.md_functionality_toggles.parts_queue_toggle")}
+
+
+ );
}
diff --git a/client/src/components/jobs-find-modal/jobs-find-modal.container.jsx b/client/src/components/jobs-find-modal/jobs-find-modal.container.jsx
index 64dc8be9a..d5857f1d4 100644
--- a/client/src/components/jobs-find-modal/jobs-find-modal.container.jsx
+++ b/client/src/components/jobs-find-modal/jobs-find-modal.container.jsx
@@ -1,102 +1,101 @@
-import { useQuery } from "@apollo/client";
-import { Modal } from "antd";
+import {useQuery} from "@apollo/client";
+import {Modal} from "antd";
import React from "react";
-import { useTranslation } from "react-i18next";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { QUERY_ALL_ACTIVE_JOBS } from "../../graphql/jobs.queries";
-import { selectBodyshop } from "../../redux/user/user.selectors";
+import {useTranslation} from "react-i18next";
+import {connect} from "react-redux";
+import {createStructuredSelector} from "reselect";
+import {QUERY_ALL_ACTIVE_JOBS} from "../../graphql/jobs.queries";
+import {selectBodyshop} from "../../redux/user/user.selectors";
import AlertComponent from "../alert/alert.component";
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
import JobsFindModalComponent from "./jobs-find-modal.component";
+
const mapStateToProps = createStructuredSelector({
- bodyshop: selectBodyshop,
+ bodyshop: selectBodyshop,
});
export default connect(
- mapStateToProps,
- null
+ mapStateToProps,
+ null
)(function JobsFindModalContainer({
- bodyshop,
- loading,
- error,
- selectedJob,
- setSelectedJob,
- importOptionsState,
- modalSearchState,
- partsQueueToggle,
- setPartsQueueToggle,
- ...modalProps
-}) {
- const { t } = useTranslation();
+ bodyshop,
+ loading,
+ error,
+ selectedJob,
+ setSelectedJob,
+ importOptionsState,
+ modalSearchState,
+ partsQueueToggle,
+ setPartsQueueToggle,
+ ...modalProps
+ }) {
+ const {t} = useTranslation();
- const jobsList = useQuery(QUERY_ALL_ACTIVE_JOBS, {
- variables: {
- statuses: bodyshop.md_ro_statuses.active_statuses || ["Open"],
- },
- skip: !modalProps.visible,
- fetchPolicy: "network-only",
- nextFetchPolicy: "network-only",
- });
+ const jobsList = useQuery(QUERY_ALL_ACTIVE_JOBS, {
+ variables: {
+ statuses: bodyshop.md_ro_statuses.active_statuses || ["Open"],
+ },
+ skip: !modalProps.open,
+ fetchPolicy: "network-only",
+ nextFetchPolicy: "network-only",
+ });
- const modalSearch = modalSearchState[0];
+ const modalSearch = modalSearchState[0];
- const jobsData =
- jobsList.data && jobsList.data.jobs
- ? modalSearch
- ? jobsList.data.jobs.filter(
- (j) =>
- (j.ro_number || "")
- .toLowerCase()
- .includes(modalSearch.toLowerCase()) ||
- (j.ownr_fn || "")
- .toLowerCase()
- .includes(modalSearch.toLowerCase()) ||
- (j.ownr_ln || "")
- .toLowerCase()
- .includes(modalSearch.toLowerCase()) ||
- (j.status || "")
- .toLowerCase()
- .includes(modalSearch.toLowerCase()) ||
- (j.v_make_desc || "")
- .toLowerCase()
- .includes(modalSearch.toLowerCase()) ||
- (j.v_model_desc || "")
- .toLowerCase()
- .includes(modalSearch.toLowerCase()) ||
- (j.clm_no || "")
- .toLowerCase()
- .includes(modalSearch.toLowerCase()) ||
- (j.plate_no || "")
- .toLowerCase()
- .includes(modalSearch.toLowerCase())
- )
- : jobsList.data.jobs
- : null;
+ const jobsData =
+ jobsList.data && jobsList.data.jobs
+ ? modalSearch
+ ? jobsList.data.jobs.filter(
+ (j) =>
+ (j.ro_number || "")
+ .toLowerCase()
+ .includes(modalSearch.toLowerCase()) ||
+ (j.ownr_fn || "")
+ .toLowerCase()
+ .includes(modalSearch.toLowerCase()) ||
+ (j.ownr_ln || "")
+ .toLowerCase()
+ .includes(modalSearch.toLowerCase()) ||
+ (j.status || "")
+ .toLowerCase()
+ .includes(modalSearch.toLowerCase()) ||
+ (j.v_make_desc || "")
+ .toLowerCase()
+ .includes(modalSearch.toLowerCase()) ||
+ (j.v_model_desc || "")
+ .toLowerCase()
+ .includes(modalSearch.toLowerCase()) ||
+ (j.clm_no || "")
+ .toLowerCase()
+ .includes(modalSearch.toLowerCase()) ||
+ (j.plate_no || "")
+ .toLowerCase()
+ .includes(modalSearch.toLowerCase())
+ )
+ : jobsList.data.jobs
+ : null;
- return (
-
- {loading ? : null}
- {error ? : null}
- {true ? (
-
- ) : null}
-
- );
+ return (
+
+ {loading ? : null}
+ {error ? : null}
+
+
+ );
});
diff --git a/client/src/components/jobs-list-paginated/jobs-list-paginated.component.jsx b/client/src/components/jobs-list-paginated/jobs-list-paginated.component.jsx
index b5048d0ef..3b164466d 100644
--- a/client/src/components/jobs-list-paginated/jobs-list-paginated.component.jsx
+++ b/client/src/components/jobs-list-paginated/jobs-list-paginated.component.jsx
@@ -1,276 +1,282 @@
-import { SyncOutlined } from "@ant-design/icons";
-import { Button, Card, Input, Space, Table, Typography } from "antd";
+import {SyncOutlined} from "@ant-design/icons";
+import {Button, Card, Input, Space, Table, Typography} from "antd";
import axios from "axios";
import _ from "lodash";
import queryString from "query-string";
-import React, { useEffect, useState } from "react";
-import { useTranslation } from "react-i18next";
-import { connect } from "react-redux";
-import { Link, useHistory, useLocation } from "react-router-dom";
-import { createStructuredSelector } from "reselect";
-import { selectBodyshop } from "../../redux/user/user.selectors";
+import React, {useEffect, useState} from "react";
+import {useTranslation} from "react-i18next";
+import {connect} from "react-redux";
+import {Link, useLocation, useNavigate} from "react-router-dom";
+import {createStructuredSelector} from "reselect";
+import {selectBodyshop} from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
+import {pageLimit} from "../../utils/config";
+import useLocalStorage from "../../utils/useLocalStorage";
import StartChatButton from "../chat-open-button/chat-open-button.component";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
-import {pageLimit} from "../../utils/config";
+
const mapStateToProps = createStructuredSelector({
- //currentUser: selectCurrentUser
- bodyshop: selectBodyshop,
+ //currentUser: selectCurrentUser
+ bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
- //setUserLanguage: language => dispatch(setUserLanguage(language))
+ //setUserLanguage: language => dispatch(setUserLanguage(language))
});
-export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
- const search = queryString.parse(useLocation().search);
- const [openSearchResults, setOpenSearchResults] = useState([]);
- const [searchLoading, setSearchLoading] = useState(false);
- const { page, sortcolumn, sortorder } = search;
- const history = useHistory();
+export function JobsList({bodyshop, refetch, loading, jobs, total}) {
+ const search = queryString.parse(useLocation().search);
+ const [openSearchResults, setOpenSearchResults] = useState([]);
+ const [searchLoading, setSearchLoading] = useState(false);
+ const [filter, setFilter] = useLocalStorage("filter_jobs_all", null);
+ const {page, sortcolumn, sortorder} = search;
+ const history = useNavigate();
- const { t } = useTranslation();
- const columns = [
- {
- title: t("jobs.fields.ro_number"),
- dataIndex: "ro_number",
- key: "ro_number",
- sorter: true, //(a, b) => alphaSort(a.ro_number, b.ro_number),
- sortOrder: sortcolumn === "ro_number" && sortorder,
- render: (text, record) => (
-
- {record.ro_number || t("general.labels.na")}
-
- ),
- },
- {
- title: t("jobs.fields.owner"),
- dataIndex: "ownr_ln",
- key: "ownr_ln",
- ellipsis: true,
- //sorter: true, // (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
+ const {t} = useTranslation();
+ const columns = [
+ {
+ title: t("jobs.fields.ro_number"),
+ dataIndex: "ro_number",
+ key: "ro_number",
+ sorter: true, //(a, b) => alphaSort(a.ro_number, b.ro_number),
+ sortOrder: sortcolumn === "ro_number" && sortorder,
+ render: (text, record) => (
+
+ {record.ro_number || t("general.labels.na")}
+
+ ),
+ },
+ {
+ title: t("jobs.fields.owner"),
+ dataIndex: "ownr_ln",
+ key: "ownr_ln",
+ ellipsis: true,
+ //sorter: true, // (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
- //sortOrder: sortcolumn === "ownr_ln" && sortorder,
- render: (text, record) => {
- return record.ownerid ? (
-
-
-
- ) : (
-
-
+ //sortOrder: sortcolumn === "ownr_ln" && sortorder,
+ render: (text, record) => {
+ return record.ownerid ? (
+
+
+
+ ) : (
+
+
- );
- },
- },
- {
- title: t("jobs.fields.ownr_ph1"),
- dataIndex: "ownr_ph1",
- key: "ownr_ph1",
+ );
+ },
+ },
+ {
+ title: t("jobs.fields.ownr_ph1"),
+ dataIndex: "ownr_ph1",
+ key: "ownr_ph1",
- ellipsis: true,
- render: (text, record) => (
-
- ),
- },
- {
- title: t("jobs.fields.ownr_ph2"),
- dataIndex: "ownr_ph2",
- key: "ownr_ph2",
+ ellipsis: true,
+ render: (text, record) => (
+
+ ),
+ },
+ {
+ title: t("jobs.fields.ownr_ph2"),
+ dataIndex: "ownr_ph2",
+ key: "ownr_ph2",
- ellipsis: true,
- render: (text, record) => (
-
- ),
- },
- {
- title: t("jobs.fields.status"),
- dataIndex: "status",
- key: "status",
+ ellipsis: true,
+ render: (text, record) => (
+
+ ),
+ },
+ {
+ title: t("jobs.fields.status"),
+ dataIndex: "status",
+ key: "status",
- ellipsis: true,
- sorter: true, // (a, b) => alphaSort(a.status, b.status),
- sortOrder: sortcolumn === "status" && sortorder,
- render: (text, record) => {
- return record.status || t("general.labels.na");
- },
- filters: bodyshop.md_ro_statuses.statuses.map((s) => {
- return { text: s, value: [s] };
- }),
- onFilter: (value, record) => value.includes(record.status),
- },
+ ellipsis: true,
+ sorter: true, // (a, b) => alphaSort(a.status, b.status),
+ sortOrder: sortcolumn === "status" && sortorder,
+ render: (text, record) => {
+ return record.status || t("general.labels.na");
+ },
+ filteredValue: filter?.status || null,
+ filters: bodyshop.md_ro_statuses.statuses.map((s) => {
+ return {text: s, value: [s]};
+ }),
+ onFilter: (value, record) => value.includes(record.status),
+ },
- {
- title: t("jobs.fields.vehicle"),
- dataIndex: "vehicle",
- key: "vehicle",
+ {
+ title: t("jobs.fields.vehicle"),
+ dataIndex: "vehicle",
+ key: "vehicle",
- ellipsis: true,
- render: (text, record) => {
- return record.vehicleid ? (
-
- {`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
- record.v_model_desc || ""
- }`}
-
- ) : (
- {`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
- record.v_model_desc || ""
- }`}
- );
- },
- },
- {
- title: t("vehicles.fields.plate_no"),
- dataIndex: "plate_no",
- key: "plate_no",
- ellipsis: true,
- sorter: true, //(a, b) => alphaSort(a.plate_no, b.plate_no),
- sortOrder: sortcolumn === "plate_no" && sortorder,
- render: (text, record) => {
- return record.plate_no ? record.plate_no : "";
- },
- },
- {
- title: t("jobs.fields.clm_no"),
- dataIndex: "clm_no",
- key: "clm_no",
- ellipsis: true,
- sorter: true, //(a, b) => alphaSort(a.clm_no, b.clm_no),
- sortOrder: sortcolumn === "clm_no" && sortorder,
- render: (text, record) =>
- `${record.clm_no || ""}${
- record.po_number ? ` (PO: ${record.po_number})` : ""
- }`,
- },
- {
- title: t("jobs.fields.ins_co_nm"),
- dataIndex: "ins_co_nm",
- key: "ins_co_nm",
- ellipsis: true,
- },
- {
- title: t("jobs.fields.clm_total"),
- dataIndex: "clm_total",
- key: "clm_total",
+ ellipsis: true,
+ render: (text, record) => {
+ return record.vehicleid ? (
+
+ {`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
+ record.v_model_desc || ""
+ }`}
+
+ ) : (
+ {`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
+ record.v_model_desc || ""
+ }`}
+ );
+ },
+ },
+ {
+ title: t("vehicles.fields.plate_no"),
+ dataIndex: "plate_no",
+ key: "plate_no",
+ ellipsis: true,
+ sorter: true, //(a, b) => alphaSort(a.plate_no, b.plate_no),
+ sortOrder: sortcolumn === "plate_no" && sortorder,
+ render: (text, record) => {
+ return record.plate_no ? record.plate_no : "";
+ },
+ },
+ {
+ title: t("jobs.fields.clm_no"),
+ dataIndex: "clm_no",
+ key: "clm_no",
+ ellipsis: true,
+ sorter: true, //(a, b) => alphaSort(a.clm_no, b.clm_no),
+ sortOrder: sortcolumn === "clm_no" && sortorder,
+ render: (text, record) =>
+ `${record.clm_no || ""}${
+ record.po_number ? ` (PO: ${record.po_number})` : ""
+ }`,
+ },
+ {
+ title: t("jobs.fields.ins_co_nm"),
+ dataIndex: "ins_co_nm",
+ key: "ins_co_nm",
+ ellipsis: true,
+ },
+ {
+ title: t("jobs.fields.clm_total"),
+ dataIndex: "clm_total",
+ key: "clm_total",
- sorter: true, //(a, b) => a.clm_total - b.clm_total,
- sortOrder: sortcolumn === "clm_total" && sortorder,
- render: (text, record) => {
- return record.clm_total ? (
- {record.clm_total}
- ) : (
- t("general.labels.unknown")
- );
- },
- },
- {
- title: t("jobs.fields.owner_owing"),
- dataIndex: "owner_owing",
- key: "owner_owing",
+ sorter: true, //(a, b) => a.clm_total - b.clm_total,
+ sortOrder: sortcolumn === "clm_total" && sortorder,
+ render: (text, record) => {
+ return record.clm_total ? (
+ {record.clm_total}
+ ) : (
+ t("general.labels.unknown")
+ );
+ },
+ },
+ {
+ title: t("jobs.fields.owner_owing"),
+ dataIndex: "owner_owing",
+ key: "owner_owing",
- render: (text, record) => (
- {record.owner_owing}
- ),
- },
- {
- title: t("jobs.fields.comment"),
- dataIndex: "comment",
- key: "comment",
- ellipsis: true,
- },
- ];
+ render: (text, record) => (
+ {record.owner_owing}
+ ),
+ },
+ {
+ title: t("jobs.fields.comment"),
+ dataIndex: "comment",
+ key: "comment",
+ ellipsis: true,
+ },
+ ];
- const handleTableChange = (pagination, filters, sorter) => {
- search.page = pagination.current;
- search.sortcolumn = sorter.column && sorter.column.key;
- search.sortorder = sorter.order;
- if (filters.status) {
- search.statusFilters = JSON.stringify(_.flattenDeep(filters.status));
- } else {
- delete search.statusFilters;
- }
- history.push({ search: queryString.stringify(search) });
- };
-
- useEffect(() => {
- if (search.search && search.search.trim() !== "") {
- searchJobs();
- }
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, []);
-
- async function searchJobs(value) {
- try {
- setSearchLoading(true);
- const searchData = await axios.post("/search", {
- search: value || search.search,
- index: "jobs",
- });
- setOpenSearchResults(searchData.data.hits.hits.map((s) => s._source));
- } catch (error) {
- console.log("Error while fetching search results", error);
- } finally {
- setSearchLoading(false);
- }
- }
-
- return (
-
- {search.search && (
- <>
-
- {t("general.labels.searchresults", { search: search.search })}
-
- {
- delete search.search;
- delete search.page;
- history.push({ search: queryString.stringify(search) });
- }}
- >
- {t("general.actions.clear")}
-
- >
- )}
- refetch()}>
-
-
- {
- search.search = value;
- history.push({ search: queryString.stringify(search) });
- searchJobs(value);
- }}
- loading={loading || searchLoading}
- enterButton
- />
-
- }
- >
- {
+ search.page = pagination.current;
+ search.sortcolumn = sorter.column && sorter.column.key;
+ search.sortorder = sorter.order;
+ if (filters.status) {
+ search.statusFilters = JSON.stringify(_.flattenDeep(filters.status));
+ } else {
+ delete search.statusFilters;
}
- columns={columns}
- rowKey="id"
- dataSource={search?.search ? openSearchResults : jobs}
- onChange={handleTableChange}
- />
-
- );
+ setFilter(filters);
+ history({search: queryString.stringify(search)});
+ };
+
+ useEffect(() => {
+ if (search.search && search.search.trim() !== "") {
+ searchJobs();
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
+ async function searchJobs(value) {
+ try {
+ setSearchLoading(true);
+ const searchData = await axios.post("/search", {
+ search: value || search.search,
+ index: "jobs",
+ });
+ setOpenSearchResults(searchData.data.hits.hits.map((s) => s._source));
+ } catch (error) {
+ console.log("Error while fetching search results", error);
+ } finally {
+ setSearchLoading(false);
+ }
+ }
+
+ return (
+
+ {search.search && (
+ <>
+
+ {t("general.labels.searchresults", {search: search.search})}
+
+ {
+ delete search.search;
+ delete search.page;
+ history({search: queryString.stringify(search)});
+ }}
+ >
+ {t("general.actions.clear")}
+
+ >
+ )}
+ refetch()}>
+
+
+ {
+ search.search = value;
+ history({search: queryString.stringify(search)});
+ searchJobs(value);
+ }}
+ loading={loading || searchLoading}
+ enterButton
+ />
+
+ }
+ >
+
+
+ );
}
+
export default connect(mapStateToProps, mapDispatchToProps)(JobsList);
diff --git a/client/src/components/jobs-list/jobs-list.component.jsx b/client/src/components/jobs-list/jobs-list.component.jsx
index fb2e1daa6..e5b708fed 100644
--- a/client/src/components/jobs-list/jobs-list.component.jsx
+++ b/client/src/components/jobs-list/jobs-list.component.jsx
@@ -1,22 +1,18 @@
-import {
- SyncOutlined,
- ExclamationCircleFilled,
- PauseCircleOutlined,
- BranchesOutlined,
-} from "@ant-design/icons";
-import { useQuery } from "@apollo/client";
-import { Button, Card, Grid, Input, Space, Table, Tooltip } from "antd";
+import {BranchesOutlined, ExclamationCircleFilled, PauseCircleOutlined, SyncOutlined,} from "@ant-design/icons";
+import {useQuery} from "@apollo/client";
+import {Button, Card, Grid, Input, Space, Table, Tooltip} from "antd";
import queryString from "query-string";
-import React, { useState } from "react";
-import { useTranslation } from "react-i18next";
-import { connect } from "react-redux";
-import { Link, useHistory, useLocation } from "react-router-dom";
-import { createStructuredSelector } from "reselect";
-import { QUERY_ALL_ACTIVE_JOBS } from "../../graphql/jobs.queries";
-import { selectBodyshop } from "../../redux/user/user.selectors";
-import { onlyUnique } from "../../utils/arrayHelper";
+import React, {useState} from "react";
+import {useTranslation} from "react-i18next";
+import {connect} from "react-redux";
+import {Link, useLocation, useNavigate} from "react-router-dom";
+import {createStructuredSelector} from "reselect";
+import {QUERY_ALL_ACTIVE_JOBS} from "../../graphql/jobs.queries";
+import {selectBodyshop} from "../../redux/user/user.selectors";
+import {onlyUnique} from "../../utils/arrayHelper";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
-import { alphaSort } from "../../utils/sorters";
+import {alphaSort, statusSort} from "../../utils/sorters";
+import useLocalStorage from "../../utils/useLocalStorage";
import AlertComponent from "../alert/alert.component";
import ChatOpenButton from "../chat-open-button/chat-open-button.component";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
@@ -25,13 +21,13 @@ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
-export function JobsList({ bodyshop }) {
+export function JobsList({bodyshop}) {
const searchParams = queryString.parse(useLocation().search);
- const { selected } = searchParams;
+ const {selected} = searchParams;
const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
.filter((screen) => !!screen[1])
.slice(-1)[0];
- const { loading, error, data, refetch } = useQuery(QUERY_ALL_ACTIVE_JOBS, {
+ const {loading, error, data, refetch} = useQuery(QUERY_ALL_ACTIVE_JOBS, {
variables: {
statuses: bodyshop.md_ro_statuses.active_statuses || ["Open", "Open*"],
},
@@ -39,16 +35,14 @@ export function JobsList({ bodyshop }) {
nextFetchPolicy: "network-only",
});
- const [state, setState] = useState({
- sortedInfo: {},
- filteredInfo: { text: "" },
- });
+ const [state, setState] = useState({sortedInfo: {}});
+ const [filter, setFilter] = useLocalStorage("filter_jobs_list", null);
- const { t } = useTranslation();
- const history = useHistory();
+ const {t} = useTranslation();
+ const history = useNavigate();
const [searchText, setSearchText] = useState("");
- if (error) return ;
+ if (error) return ;
const jobs = data
? searchText === ""
@@ -91,13 +85,14 @@ export function JobsList({ bodyshop }) {
: [];
const handleTableChange = (pagination, filters, sorter) => {
- setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
+ setState({...state, sortedInfo: sorter});
+ setFilter(filters);
};
const handleOnRowClick = (record) => {
if (record) {
if (record.id) {
- history.push({
+ history({
search: queryString.stringify({
...searchParams,
selected: record.id,
@@ -126,14 +121,14 @@ export function JobsList({ bodyshop }) {
{record.ro_number || t("general.labels.na")}
{record.production_vars && record.production_vars.alert ? (
-
+
) : null}
{record.suspended && (
-
+
)}
{record.iouparent && (
-
+
)}
@@ -156,11 +151,11 @@ export function JobsList({ bodyshop }) {
to={"/manage/owners/" + record.ownerid}
onClick={(e) => e.stopPropagation()}
>
-
+
) : (
-
+
);
},
@@ -172,7 +167,7 @@ export function JobsList({ bodyshop }) {
ellipsis: true,
responsive: ["md"],
render: (text, record) => (
-
+
),
},
{
@@ -182,7 +177,7 @@ export function JobsList({ bodyshop }) {
ellipsis: true,
responsive: ["md"],
render: (text, record) => (
-
+
),
},
@@ -195,6 +190,7 @@ export function JobsList({ bodyshop }) {
sorter: (a, b) => alphaSort(a.status, b.status),
sortOrder:
state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
+ filteredValue: filter?.status || null,
filters:
(jobs &&
jobs
@@ -205,7 +201,14 @@ export function JobsList({ bodyshop }) {
text: s || "No Status*",
value: [s],
};
- })) ||
+ })
+ .sort((a, b) =>
+ statusSort(
+ a.text,
+ b.text,
+ bodyshop.md_ro_statuses.active_statuses
+ )
+ )) ||
[],
onFilter: (value, record) => value.includes(record.status),
},
@@ -262,6 +265,7 @@ export function JobsList({ bodyshop }) {
dataIndex: "ins_co_nm",
key: "ins_co_nm",
ellipsis: true,
+ filteredValue: filter?.ins_co_nm || null,
filters:
(jobs &&
jobs
@@ -269,10 +273,11 @@ export function JobsList({ bodyshop }) {
.filter(onlyUnique)
.map((s) => {
return {
- text: s,
+ text: s || "No Ins. Co.*",
value: [s],
};
- })) ||
+ })
+ .sort((a, b) => alphaSort(a.text, b.text))) ||
[],
onFilter: (value, record) => value.includes(record.ins_co_nm),
responsive: ["md"],
@@ -298,6 +303,7 @@ export function JobsList({ bodyshop }) {
ellipsis: true,
responsive: ["xl"],
filterSearch: true,
+ filteredValue: filter?.estimator || null,
filters:
(jobs &&
jobs
@@ -305,10 +311,11 @@ export function JobsList({ bodyshop }) {
.filter(onlyUnique)
.map((s) => {
return {
- text: s || "N/A",
+ text: s || "No Estimator*",
value: [s],
};
- })) ||
+ })
+ .sort((a, b) => alphaSort(a.text, b.text))) ||
[],
onFilter: (value, record) =>
value.includes(
@@ -350,7 +357,7 @@ export function JobsList({ bodyshop }) {
extra={
refetch()}>
-
+
{
- const newPartRates = _.cloneDeep(form.getFieldValue("parts_tax_rates"));
+ const handleConfirm = () => {
+ const newPartRates = _.cloneDeep(form.getFieldValue("parts_tax_rates"));
- Object.keys(newPartRates).forEach((key) => {
- newPartRates[key] = {
- ...newPartRates[key],
- prt_tax_in: false,
- prt_tax_rt: 0,
- };
- });
+ Object.keys(newPartRates).forEach((key) => {
+ newPartRates[key] = {
+ ...newPartRates[key],
+ prt_tax_in: false,
+ prt_tax_rt: 0,
+ };
+ });
- form.setFieldsValue({
- state_tax_rate: 0,
- tax_lbr_rt: 0,
- tax_levies_rt: 0,
- tax_sub_rt: 0,
- tax_shop_mat_rt: 0,
- tax_paint_mat_rt: 0,
- tax_str_rt: 0,
- tax_tow_rt: 0,
- parts_tax_rates: newPartRates,
- });
- };
+ form.setFieldsValue({
+ state_tax_rate: 0,
+ tax_lbr_rt: 0,
+ tax_levies_rt: 0,
+ tax_sub_rt: 0,
+ tax_shop_mat_rt: 0,
+ tax_paint_mat_rt: 0,
+ tax_str_rt: 0,
+ tax_tow_rt: 0,
+ parts_tax_rates: newPartRates,
+ });
+ };
- return (
-
-
- {t("jobs.actions.markpstexempt")}
-
-
- );
+ return (
+
+
+ {t("jobs.actions.markpstexempt")}
+
+
+ );
}
+
export default connect(mapStateToProps, null)(JobsMarkPstExempt);
diff --git a/client/src/components/jobs-notes/jobs-notes.container.jsx b/client/src/components/jobs-notes/jobs-notes.container.jsx
index f62a219cb..763f869ff 100644
--- a/client/src/components/jobs-notes/jobs-notes.container.jsx
+++ b/client/src/components/jobs-notes/jobs-notes.container.jsx
@@ -1,73 +1,70 @@
-import { useMutation, useQuery } from "@apollo/client";
-import { notification } from "antd";
-import React, { useState } from "react";
+import {useMutation, useQuery} from "@apollo/client";
+import {notification} from "antd";
+import React, {useState} from "react";
//import SpinComponent from "../../components/loading-spinner/loading-spinner.component";
-import { useTranslation } from "react-i18next";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
+import {useTranslation} from "react-i18next";
+import {connect} from "react-redux";
+import {createStructuredSelector} from "reselect";
import AlertComponent from "../../components/alert/alert.component";
-import { logImEXEvent } from "../../firebase/firebase.utils";
-import {
- DELETE_NOTE,
- QUERY_NOTES_BY_JOB_PK,
-} from "../../graphql/notes.queries";
-import { insertAuditTrail } from "../../redux/application/application.actions";
+import {logImEXEvent} from "../../firebase/firebase.utils";
+import {DELETE_NOTE, QUERY_NOTES_BY_JOB_PK,} from "../../graphql/notes.queries";
+import {insertAuditTrail} from "../../redux/application/application.actions";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
import JobNotesComponent from "./jobs.notes.component";
const mapStateToProps = createStructuredSelector({
- //currentUser: selectCurrentUser
+ //currentUser: selectCurrentUser
});
const mapDispatchToProps = (dispatch) => ({
- insertAuditTrail: ({ jobid, operation }) =>
- dispatch(insertAuditTrail({ jobid, operation })),
+ insertAuditTrail: ({jobid, operation}) =>
+ dispatch(insertAuditTrail({jobid, operation})),
});
export default connect(mapStateToProps, mapDispatchToProps)(JobNotesContainer);
-export function JobNotesContainer({ jobId, insertAuditTrail }) {
- const { loading, error, data, refetch } = useQuery(QUERY_NOTES_BY_JOB_PK, {
- variables: { id: jobId },
- fetchPolicy: "network-only",
- nextFetchPolicy: "network-only",
- });
-
- const [deleteNote] = useMutation(DELETE_NOTE);
- const { t } = useTranslation();
- const [deleteLoading, setDeleteLoading] = useState(false);
- const handleNoteDelete = (id) => {
- logImEXEvent("job_note_delete");
- setDeleteLoading(true);
- deleteNote({
- variables: {
- noteId: id,
- },
- }).then((r) => {
- refetch();
- notification["success"]({
- message: t("notes.successes.deleted"),
- });
- insertAuditTrail({
- jobid: jobId,
- operation: AuditTrailMapping.jobnotedeleted(),
- });
+export function JobNotesContainer({jobId, insertAuditTrail}) {
+ const {loading, error, data, refetch} = useQuery(QUERY_NOTES_BY_JOB_PK, {
+ variables: {id: jobId},
+ fetchPolicy: "network-only",
+ nextFetchPolicy: "network-only",
});
- setDeleteLoading(false);
- };
- //if (loading) return ;
- if (error) return ;
- return (
-
- );
+ const [deleteNote] = useMutation(DELETE_NOTE);
+ const {t} = useTranslation();
+ const [deleteLoading, setDeleteLoading] = useState(false);
+ const handleNoteDelete = (id) => {
+ logImEXEvent("job_note_delete");
+ setDeleteLoading(true);
+ deleteNote({
+ variables: {
+ noteId: id,
+ },
+ }).then((r) => {
+ refetch();
+ notification["success"]({
+ message: t("notes.successes.deleted"),
+ });
+ insertAuditTrail({
+ jobid: jobId,
+ operation: AuditTrailMapping.jobnotedeleted(),
+ });
+ });
+ setDeleteLoading(false);
+ };
+
+ //if (loading) return ;
+ if (error) return ;
+ return (
+
+ );
}
diff --git a/client/src/components/jobs-notes/jobs.notes.component.jsx b/client/src/components/jobs-notes/jobs.notes.component.jsx
index c47dec740..51196f4f2 100644
--- a/client/src/components/jobs-notes/jobs.notes.component.jsx
+++ b/client/src/components/jobs-notes/jobs.notes.component.jsx
@@ -1,215 +1,210 @@
-import {
- AuditOutlined,
- DeleteFilled,
- EditFilled,
- EyeInvisibleFilled,
- WarningFilled,
-} from "@ant-design/icons";
-import { Button, Card, Form, Input, Space, Table } from "antd";
+import {AuditOutlined, DeleteFilled, EditFilled, EyeInvisibleFilled, WarningFilled,} from "@ant-design/icons";
+import {Button, Card, Form, Input, Space, Table} 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 { setModalContext } from "../../redux/modals/modals.actions";
-import { DateTimeFormatter } from "../../utils/DateFormatter";
-import { TemplateList } from "../../utils/TemplateConstants";
+import {useTranslation} from "react-i18next";
+import {connect} from "react-redux";
+import {createStructuredSelector} from "reselect";
+import {selectJobReadOnly} from "../../redux/application/application.selectors";
+import {setModalContext} from "../../redux/modals/modals.actions";
+import {DateTimeFormatter} from "../../utils/DateFormatter";
+import {TemplateList} from "../../utils/TemplateConstants";
import useLocalStorage from "../../utils/useLocalStorage";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
import NoteUpsertModal from "../note-upsert-modal/note-upsert-modal.container";
import PrintWrapperComponent from "../print-wrapper/print-wrapper.component";
const mapStateToProps = createStructuredSelector({
- jobRO: selectJobReadOnly,
+ jobRO: selectJobReadOnly,
});
const mapDispatchToProps = (dispatch) => ({
- setNoteUpsertContext: (context) =>
- dispatch(setModalContext({ context: context, modal: "noteUpsert" })),
+ setNoteUpsertContext: (context) =>
+ dispatch(setModalContext({context: context, modal: "noteUpsert"})),
});
export function JobNotesComponent({
- jobRO,
- loading,
- data,
- refetch,
- handleNoteDelete,
- jobId,
- setNoteUpsertContext,
- deleteLoading,
- ro_number,
- relatedRos,
-}) {
- const { t } = useTranslation();
- const [filter, setFilter] = useLocalStorage("filter_job_notes_icons", null);
+ jobRO,
+ loading,
+ data,
+ refetch,
+ handleNoteDelete,
+ jobId,
+ setNoteUpsertContext,
+ deleteLoading,
+ ro_number,
+ relatedRos,
+ }) {
+ const {t} = useTranslation();
+ const [filter, setFilter] = useLocalStorage("filter_job_notes_icons", null);
- const Templates = TemplateList("job_special", {
- ro_number,
- });
+ const Templates = TemplateList("job_special", {
+ ro_number,
+ });
- const columns = [
- {
- title: "",
- dataIndex: "icons",
- key: "icons",
- width: 80,
- filteredValue: filter?.icons || null,
- filters: [
+ const columns = [
{
- text: t("notes.labels.usernotes"),
- value: false,
- },
- {
- text: t("notes.labels.systemnotes"),
- value: true,
- },
- ],
- onFilter: (value, record) => record.audit === value,
- render: (text, record) => (
-
+ title: "",
+ dataIndex: "icons",
+ key: "icons",
+ width: 80,
+ filteredValue: filter?.icons || null,
+ filters: [
+ {
+ text: t("notes.labels.usernotes"),
+ value: false,
+ },
+ {
+ text: t("notes.labels.systemnotes"),
+ value: true,
+ },
+ ],
+ onFilter: (value, record) => record.audit === value,
+ render: (text, record) => (
+
{record.critical ? (
-
+
) : null}
- {record.private ? : null}
- {record.audit ? : null}
+ {record.private ? : null}
+ {record.audit ? : null}
- ),
- },
- {
- title: t("notes.fields.type"),
- dataIndex: "type",
- key: "type",
- width: 120,
- filteredValue: filter?.type || null,
- filters: [
- { value: "general", text: t("notes.fields.types.general") },
- { value: "customer", text: t("notes.fields.types.customer") },
- { value: "shop", text: t("notes.fields.types.shop") },
- { value: "office", text: t("notes.fields.types.office") },
- { value: "parts", text: t("notes.fields.types.parts") },
- { value: "paint", text: t("notes.fields.types.paint") },
- {
- value: "supplement",
- text: t("notes.fields.types.supplement"),
+ ),
},
- ],
- onFilter: (value, record) => value.includes(record.type),
- render: (text, record) => t(`notes.fields.types.${record.type}`),
- },
- {
- title: t("notes.fields.text"),
- dataIndex: "text",
- key: "text",
- ellipsis: true,
- render: (text, record) => (
- {text}
- ),
- },
-
- {
- title: t("notes.fields.updatedat"),
- dataIndex: "updated_at",
- key: "updated_at",
- defaultSortOrder: "descend",
- width: 200,
- sorter: (a, b) => new Date(a.updated_at) - new Date(b.updated_at),
- render: (text, record) => (
- {record.updated_at}
- ),
- },
- {
- title: t("notes.fields.createdby"),
- dataIndex: "created_by",
- key: "created_by",
- width: 200,
- },
- {
- title: t("notes.actions.actions"),
- dataIndex: "actions",
- key: "actions",
- width: 200,
- render: (text, record) => (
-
- handleNoteDelete(record.id)}
- >
-
-
- {
- setNoteUpsertContext({
- actions: { refetch: refetch },
- context: {
- jobId: jobId,
- existingNote: record,
+ {
+ title: t("notes.fields.type"),
+ dataIndex: "type",
+ key: "type",
+ width: 120,
+ filteredValue: filter?.type || null,
+ filters: [
+ {value: "general", text: t("notes.fields.types.general")},
+ {value: "customer", text: t("notes.fields.types.customer")},
+ {value: "shop", text: t("notes.fields.types.shop")},
+ {value: "office", text: t("notes.fields.types.office")},
+ {value: "parts", text: t("notes.fields.types.parts")},
+ {value: "paint", text: t("notes.fields.types.paint")},
+ {
+ value: "supplement",
+ text: t("notes.fields.types.supplement"),
},
- });
- }}
- >
-
-
- value.includes(record.type),
+ render: (text, record) => t(`notes.fields.types.${record.type}`),
+ },
+ {
+ title: t("notes.fields.text"),
+ dataIndex: "text",
+ key: "text",
+ ellipsis: true,
+ render: (text, record) => (
+ {text}
+ ),
+ },
- variables: { id: record.id },
- }}
- messageObject={{
- subject: Templates.individual_job_note.subject,
- }}
- id={jobId}
- />
-
- ),
- },
- ];
+ {
+ title: t("notes.fields.updatedat"),
+ dataIndex: "updated_at",
+ key: "updated_at",
+ defaultSortOrder: "descend",
+ width: 200,
+ sorter: (a, b) => new Date(a.updated_at) - new Date(b.updated_at),
+ render: (text, record) => (
+ {record.updated_at}
+ ),
+ },
+ {
+ title: t("notes.fields.createdby"),
+ dataIndex: "created_by",
+ key: "created_by",
+ width: 200,
+ },
+ {
+ title: t("notes.actions.actions"),
+ dataIndex: "actions",
+ key: "actions",
+ width: 200,
+ render: (text, record) => (
+
+ handleNoteDelete(record.id)}
+ >
+
+
+ {
+ setNoteUpsertContext({
+ actions: {refetch: refetch},
+ context: {
+ jobId: jobId,
+ existingNote: record,
+ },
+ });
+ }}
+ >
+
+
+ {
- setFilter(filters);
- };
+ variables: {id: record.id},
+ }}
+ messageObject={{
+ subject: Templates.individual_job_note.subject,
+ }}
+ id={jobId}
+ />
+
+ ),
+ },
+ ];
- return (
-
-
-
-
-
-
-
{
- setNoteUpsertContext({
- actions: { refetch: refetch },
- context: {
- jobId: jobId,
- relatedRos: relatedRos,
- },
- });
- }}
- >
- {t("notes.actions.new")}
-
- }
- >
-
+ const handleTableChange = (pagination, filters, sorter) => {
+ setFilter(filters);
+ };
-
-
-
- );
+ return (
+
+
+
+
+
+
+
{
+ setNoteUpsertContext({
+ actions: {refetch: refetch},
+ context: {
+ jobId: jobId,
+ relatedRos: relatedRos,
+ },
+ });
+ }}
+ >
+ {t("notes.actions.new")}
+
+ }
+ >
+
+
+
+
+
+ );
}
+
export default connect(mapStateToProps, mapDispatchToProps)(JobNotesComponent);
diff --git a/client/src/components/jobs-ready-list/jobs-ready-list.component.jsx b/client/src/components/jobs-ready-list/jobs-ready-list.component.jsx
index fee461df2..1862cf300 100644
--- a/client/src/components/jobs-ready-list/jobs-ready-list.component.jsx
+++ b/client/src/components/jobs-ready-list/jobs-ready-list.component.jsx
@@ -1,408 +1,409 @@
-import {
- BranchesOutlined,
- ExclamationCircleFilled,
- PauseCircleOutlined,
- SyncOutlined,
-} from "@ant-design/icons";
-import { useQuery } from "@apollo/client";
-import { Button, Card, Grid, Input, Space, Table, Tooltip } from "antd";
+import {BranchesOutlined, ExclamationCircleFilled, PauseCircleOutlined, SyncOutlined,} from "@ant-design/icons";
+import {useQuery} from "@apollo/client";
+import {Button, Card, Grid, Input, Space, Table, Tooltip} from "antd";
import queryString from "query-string";
-import React, { useMemo, useState } from "react";
-import { useTranslation } from "react-i18next";
-import { connect } from "react-redux";
-import { Link, useHistory, useLocation } from "react-router-dom";
-import { createStructuredSelector } from "reselect";
-import { QUERY_ALL_ACTIVE_JOBS } from "../../graphql/jobs.queries";
-import { selectBodyshop } from "../../redux/user/user.selectors";
+import React, {useMemo, useState} from "react";
+import {useTranslation} from "react-i18next";
+import {connect} from "react-redux";
+import {Link, useLocation, useNavigate} from "react-router-dom";
+import {createStructuredSelector} from "reselect";
+import {QUERY_ALL_ACTIVE_JOBS} from "../../graphql/jobs.queries";
+import {selectBodyshop} from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
-import { onlyUnique } from "../../utils/arrayHelper";
-import { alphaSort } from "../../utils/sorters";
+import {onlyUnique} from "../../utils/arrayHelper";
+import {pageLimit} from "../../utils/config";
+import {alphaSort, statusSort} from "../../utils/sorters";
+import useLocalStorage from "../../utils/useLocalStorage";
import AlertComponent from "../alert/alert.component";
import ChatOpenButton from "../chat-open-button/chat-open-button.component";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
-import {pageLimit} from "../../utils/config";
const mapStateToProps = createStructuredSelector({
- bodyshop: selectBodyshop,
+ bodyshop: selectBodyshop,
});
-export function JobsReadyList({ bodyshop }) {
- const searchParams = queryString.parse(useLocation().search);
- const { selected } = searchParams;
- const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
- .filter((screen) => !!screen[1])
- .slice(-1)[0];
+export function JobsReadyList({bodyshop}) {
+ const searchParams = queryString.parse(useLocation().search);
+ const {selected} = searchParams;
+ const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
+ .filter((screen) => !!screen[1])
+ .slice(-1)[0];
- const readyStatuses = useMemo(() => {
- if (bodyshop.md_ro_statuses.ready_statuses)
- return bodyshop.md_ro_statuses.ready_statuses;
+ const readyStatuses = useMemo(() => {
+ if (bodyshop.md_ro_statuses.ready_statuses)
+ return bodyshop.md_ro_statuses.ready_statuses;
- return bodyshop.md_ro_statuses.post_production_statuses.filter(
- (s) =>
- s !== bodyshop.md_ro_statuses.default_invoiced &&
- s !== bodyshop.md_ro_statuses.default_exported
- );
- }, [bodyshop.md_ro_statuses]);
+ return bodyshop.md_ro_statuses.post_production_statuses.filter(
+ (s) =>
+ s !== bodyshop.md_ro_statuses.default_invoiced &&
+ s !== bodyshop.md_ro_statuses.default_exported
+ );
+ }, [bodyshop.md_ro_statuses]);
- const { loading, error, data, refetch } = useQuery(QUERY_ALL_ACTIVE_JOBS, {
- variables: {
- statuses: readyStatuses,
- isConverted: true,
- },
- fetchPolicy: "network-only",
- nextFetchPolicy: "network-only",
- });
+ const {loading, error, data, refetch} = useQuery(QUERY_ALL_ACTIVE_JOBS, {
+ variables: {
+ statuses: readyStatuses,
+ isConverted: true,
+ },
+ fetchPolicy: "network-only",
+ nextFetchPolicy: "network-only",
+ });
- const [state, setState] = useState({
- sortedInfo: {},
- filteredInfo: { text: "" },
- });
+ const [state, setState] = useState({sortedInfo: {}});
+ const [filter, setFilter] = useLocalStorage("filter_jobs_ready", null);
- const { t } = useTranslation();
- const history = useHistory();
- const [searchText, setSearchText] = useState("");
+ const {t} = useTranslation();
+ const history = useNavigate();
+ const [searchText, setSearchText] = useState("");
- if (error) return ;
+ if (error) return ;
- const jobs = data
- ? searchText === ""
- ? data.jobs
- : data.jobs.filter(
- (j) =>
- (j.ro_number || "")
- .toString()
- .toLowerCase()
- .includes(searchText.toLowerCase()) ||
- (j.ownr_co_nm || "")
- .toLowerCase()
- .includes(searchText.toLowerCase()) ||
- (j.comments || "")
- .toLowerCase()
- .includes(searchText.toLowerCase()) ||
- (j.ownr_fn || "")
- .toLowerCase()
- .includes(searchText.toLowerCase()) ||
- (j.ownr_ln || "")
- .toLowerCase()
- .includes(searchText.toLowerCase()) ||
- (j.clm_no || "").toLowerCase().includes(searchText.toLowerCase()) ||
- (j.plate_no || "")
- .toLowerCase()
- .includes(searchText.toLowerCase()) ||
- (j.v_model_desc || "")
- .toLowerCase()
- .includes(searchText.toLowerCase()) ||
- (j.est_ct_fn || "")
- .toLowerCase()
- .includes(searchText.toLowerCase()) ||
- (j.est_ct_ln || "")
- .toLowerCase()
- .includes(searchText.toLowerCase()) ||
- (j.v_make_desc || "")
- .toLowerCase()
- .includes(searchText.toLowerCase())
- )
- : [];
+ const jobs = data
+ ? searchText === ""
+ ? data.jobs
+ : data.jobs.filter(
+ (j) =>
+ (j.ro_number || "")
+ .toString()
+ .toLowerCase()
+ .includes(searchText.toLowerCase()) ||
+ (j.ownr_co_nm || "")
+ .toLowerCase()
+ .includes(searchText.toLowerCase()) ||
+ (j.comments || "")
+ .toLowerCase()
+ .includes(searchText.toLowerCase()) ||
+ (j.ownr_fn || "")
+ .toLowerCase()
+ .includes(searchText.toLowerCase()) ||
+ (j.ownr_ln || "")
+ .toLowerCase()
+ .includes(searchText.toLowerCase()) ||
+ (j.clm_no || "").toLowerCase().includes(searchText.toLowerCase()) ||
+ (j.plate_no || "")
+ .toLowerCase()
+ .includes(searchText.toLowerCase()) ||
+ (j.v_model_desc || "")
+ .toLowerCase()
+ .includes(searchText.toLowerCase()) ||
+ (j.est_ct_fn || "")
+ .toLowerCase()
+ .includes(searchText.toLowerCase()) ||
+ (j.est_ct_ln || "")
+ .toLowerCase()
+ .includes(searchText.toLowerCase()) ||
+ (j.v_make_desc || "")
+ .toLowerCase()
+ .includes(searchText.toLowerCase())
+ )
+ : [];
- const handleTableChange = (pagination, filters, sorter) => {
- setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
- };
+ const handleTableChange = (pagination, filters, sorter) => {
+ setState({...state, sortedInfo: sorter});
+ setFilter(filters);
+ };
- const handleOnRowClick = (record) => {
- if (record) {
- if (record.id) {
- history.push({
- search: queryString.stringify({
- ...searchParams,
- selected: record.id,
- }),
- });
- }
- }
- };
+ const handleOnRowClick = (record) => {
+ if (record) {
+ if (record.id) {
+ history({
+ search: queryString.stringify({
+ ...searchParams,
+ selected: record.id,
+ }),
+ });
+ }
+ }
+ };
- const columns = [
- {
- title: t("jobs.fields.ro_number"),
- dataIndex: "ro_number",
- key: "ro_number",
- sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
- sortOrder:
- state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
-
- render: (text, record) => (
- e.stopPropagation()}
- >
-
- {record.ro_number || t("general.labels.na")}
- {record.production_vars && record.production_vars.alert ? (
-
- ) : null}
- {record.suspended && (
-
- )}
- {record.iouparent && (
-
-
-
- )}
-
-
- ),
- },
- {
- title: t("jobs.fields.owner"),
- dataIndex: "owner",
- key: "owner",
- ellipsis: true,
-
- responsive: ["md"],
- sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
- sortOrder:
- state.sortedInfo.columnKey === "owner" && state.sortedInfo.order,
- render: (text, record) => {
- return record.owner ? (
- e.stopPropagation()}
- >
-
-
- ) : (
-
-
+ const columns = [
+ {
+ title: t("jobs.fields.ro_number"),
+ dataIndex: "ro_number",
+ key: "ro_number",
+ sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
+ sortOrder:
+ state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
+ render: (text, record) => (
+ e.stopPropagation()}
+ >
+
+ {record.ro_number || t("general.labels.na")}
+ {record.production_vars && record.production_vars.alert ? (
+
+ ) : null}
+ {record.suspended && (
+
+ )}
+ {record.iouparent && (
+
+
+
+ )}
+
+
+ ),
+ },
+ {
+ title: t("jobs.fields.owner"),
+ dataIndex: "owner",
+ key: "owner",
+ ellipsis: true,
+ responsive: ["md"],
+ sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
+ sortOrder:
+ state.sortedInfo.columnKey === "owner" && state.sortedInfo.order,
+ render: (text, record) => {
+ return record.owner ? (
+ e.stopPropagation()}
+ >
+
+
+ ) : (
+
+
- );
- },
- },
- {
- title: t("jobs.fields.ownr_ph1"),
- dataIndex: "ownr_ph1",
- key: "ownr_ph1",
- ellipsis: true,
- responsive: ["md"],
- render: (text, record) => (
-
- ),
- },
- {
- title: t("jobs.fields.ownr_ph2"),
- dataIndex: "ownr_ph2",
- key: "ownr_ph2",
- ellipsis: true,
- responsive: ["md"],
- render: (text, record) => (
-
- ),
- },
-
- {
- title: t("jobs.fields.status"),
- dataIndex: "status",
- key: "status",
- ellipsis: true,
-
- sorter: (a, b) => alphaSort(a.status, b.status),
- sortOrder:
- state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
- filters:
- (jobs &&
- jobs
- .map((j) => j.status)
- .filter(onlyUnique)
- .map((s) => {
- return {
- text: s || "No Status*",
- value: [s],
- };
- })) ||
- [],
- onFilter: (value, record) => value.includes(record.status),
- },
-
- {
- title: t("jobs.fields.vehicle"),
- dataIndex: "vehicle",
- key: "vehicle",
- ellipsis: true,
- render: (text, record) => {
- return record.vehicleid ? (
- e.stopPropagation()}
- >
- {`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
- record.v_model_desc || ""
- }`}
-
- ) : (
- {`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
- record.v_model_desc || ""
- }`}
- );
- },
- },
- {
- title: t("vehicles.fields.plate_no"),
- dataIndex: "plate_no",
- key: "plate_no",
- ellipsis: true,
-
- responsive: ["md"],
- sorter: (a, b) => alphaSort(a.plate_no, b.plate_no),
- sortOrder:
- state.sortedInfo.columnKey === "plate_no" && state.sortedInfo.order,
- },
- {
- title: t("jobs.fields.clm_no"),
- dataIndex: "clm_no",
- key: "clm_no",
- ellipsis: true,
- responsive: ["md"],
- sorter: (a, b) => alphaSort(a.clm_no, b.clm_no),
- sortOrder:
- state.sortedInfo.columnKey === "clm_no" && state.sortedInfo.order,
- render: (text, record) =>
- `${record.clm_no || ""}${
- record.po_number ? ` (PO: ${record.po_number})` : ""
- }`,
- },
- {
- title: t("jobs.fields.ins_co_nm"),
- dataIndex: "ins_co_nm",
- key: "ins_co_nm",
- ellipsis: true,
- filters:
- (jobs &&
- jobs
- .map((j) => j.ins_co_nm)
- .filter(onlyUnique)
- .map((s) => {
- return {
- text: s,
- value: [s],
- };
- })) ||
- [],
- onFilter: (value, record) => value.includes(record.ins_co_nm),
- responsive: ["md"],
- },
- {
- title: t("jobs.fields.clm_total"),
- dataIndex: "clm_total",
- key: "clm_total",
- responsive: ["md"],
- ellipsis: true,
-
- sorter: (a, b) => a.clm_total - b.clm_total,
- sortOrder:
- state.sortedInfo.columnKey === "clm_total" && state.sortedInfo.order,
- render: (text, record) => (
- {record.clm_total}
- ),
- },
- {
- title: t("jobs.labels.estimator"),
- dataIndex: "jobs.labels.estimator",
- key: "jobs.labels.estimator",
- ellipsis: true,
- responsive: ["xl"],
- filterSearch: true,
- filters:
- (jobs &&
- jobs
- .map((j) => `${j.est_ct_fn || ""} ${j.est_ct_ln || ""}`.trim())
- .filter(onlyUnique)
- .map((s) => {
- return {
- text: s || "N/A",
- value: [s],
- };
- })) ||
- [],
- onFilter: (value, record) =>
- value.includes(
- `${record.est_ct_fn || ""} ${record.est_ct_ln || ""}`.trim()
- ),
- render: (text, record) =>
- `${record.est_ct_fn || ""} ${record.est_ct_ln || ""}`.trim(),
- },
- {
- title: t("jobs.fields.comment"),
- dataIndex: "comment",
- key: "comment",
- ellipsis: true,
- responsive: ["md"],
- },
- // {
- // title: t("jobs.fields.owner_owing"),
- // dataIndex: "owner_owing",
- // key: "owner_owing",
- // responsive: ["md"],
- // render: (text, record) => (
- // {record.owner_owing}
- // ),
- // },
- ];
-
- const scrollMapper = {
- xs: true,
- sm: true,
- md: true,
- lg: "100%",
- xl: "100%",
- xxl: "100%",
- };
-
- return (
-
- ({readyStatuses && readyStatuses.join(", ")})
- refetch()}>
-
-
- {
- setSearchText(e.target.value);
- }}
- value={searchText}
- enterButton
- />
-
- }
- >
- {
- handleOnRowClick(record);
- },
- selectedRowKeys: [selected],
- type: "radio",
- }}
- onChange={handleTableChange}
- onRow={(record, rowIndex) => {
- return {
- onClick: (event) => {
- handleOnRowClick(record);
+ );
},
- };
- }}
- />
-
- );
+ },
+ {
+ title: t("jobs.fields.ownr_ph1"),
+ dataIndex: "ownr_ph1",
+ key: "ownr_ph1",
+ ellipsis: true,
+ responsive: ["md"],
+ render: (text, record) => (
+
+ ),
+ },
+ {
+ title: t("jobs.fields.ownr_ph2"),
+ dataIndex: "ownr_ph2",
+ key: "ownr_ph2",
+ ellipsis: true,
+ responsive: ["md"],
+ render: (text, record) => (
+
+ ),
+ },
+ {
+ title: t("jobs.fields.status"),
+ dataIndex: "status",
+ key: "status",
+ ellipsis: true,
+ sorter: (a, b) => alphaSort(a.status, b.status),
+ sortOrder:
+ state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
+ filteredValue: filter?.status || null,
+ filters:
+ (jobs &&
+ jobs
+ .map((j) => j.status)
+ .filter(onlyUnique)
+ .map((s) => {
+ return {
+ text: s || "No Status*",
+ value: [s],
+ };
+ })
+ .sort((a, b) =>
+ statusSort(
+ a.text,
+ b.text,
+ bodyshop.md_ro_statuses.active_statuses
+ )
+ )) ||
+ [],
+ onFilter: (value, record) => value.includes(record.status),
+ },
+ {
+ title: t("jobs.fields.vehicle"),
+ dataIndex: "vehicle",
+ key: "vehicle",
+ ellipsis: true,
+ render: (text, record) => {
+ return record.vehicleid ? (
+ e.stopPropagation()}
+ >
+ {`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
+ record.v_model_desc || ""
+ }`}
+
+ ) : (
+ {`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
+ record.v_model_desc || ""
+ }`}
+ );
+ },
+ },
+ {
+ title: t("vehicles.fields.plate_no"),
+ dataIndex: "plate_no",
+ key: "plate_no",
+ ellipsis: true,
+
+ responsive: ["md"],
+ sorter: (a, b) => alphaSort(a.plate_no, b.plate_no),
+ sortOrder:
+ state.sortedInfo.columnKey === "plate_no" && state.sortedInfo.order,
+ },
+ {
+ title: t("jobs.fields.clm_no"),
+ dataIndex: "clm_no",
+ key: "clm_no",
+ ellipsis: true,
+ responsive: ["md"],
+ sorter: (a, b) => alphaSort(a.clm_no, b.clm_no),
+ sortOrder:
+ state.sortedInfo.columnKey === "clm_no" && state.sortedInfo.order,
+ render: (text, record) =>
+ `${record.clm_no || ""}${
+ record.po_number ? ` (PO: ${record.po_number})` : ""
+ }`,
+ },
+ {
+ title: t("jobs.fields.ins_co_nm"),
+ dataIndex: "ins_co_nm",
+ key: "ins_co_nm",
+ ellipsis: true,
+ filteredValue: filter?.ins_co_nm || null,
+ filters:
+ (jobs &&
+ jobs
+ .map((j) => j.ins_co_nm)
+ .filter(onlyUnique)
+ .map((s) => {
+ return {
+ text: s || "No Ins Co.*",
+ value: [s],
+ };
+ })
+ .sort((a, b) => alphaSort(a.text, b.text))) ||
+ [],
+ onFilter: (value, record) => value.includes(record.ins_co_nm),
+ responsive: ["md"],
+ },
+ {
+ title: t("jobs.fields.clm_total"),
+ dataIndex: "clm_total",
+ key: "clm_total",
+ responsive: ["md"],
+ ellipsis: true,
+ sorter: (a, b) => a.clm_total - b.clm_total,
+ sortOrder:
+ state.sortedInfo.columnKey === "clm_total" && state.sortedInfo.order,
+ render: (text, record) => (
+ {record.clm_total}
+ ),
+ },
+ {
+ title: t("jobs.labels.estimator"),
+ dataIndex: "jobs.labels.estimator",
+ key: "estimator",
+ ellipsis: true,
+ responsive: ["xl"],
+ filteredValue: filter?.estimator || null,
+ filterSearch: true,
+ filters:
+ (jobs &&
+ jobs
+ .map((j) => `${j.est_ct_fn || ""} ${j.est_ct_ln || ""}`.trim())
+ .filter(onlyUnique)
+ .map((s) => {
+ return {
+ text: s || "No Estimator*",
+ value: [s],
+ };
+ })
+ .sort((a, b) => alphaSort(a.text, b.text))) ||
+ [],
+ onFilter: (value, record) =>
+ value.includes(
+ `${record.est_ct_fn || ""} ${record.est_ct_ln || ""}`.trim()
+ ),
+ render: (text, record) =>
+ `${record.est_ct_fn || ""} ${record.est_ct_ln || ""}`.trim(),
+ },
+ {
+ title: t("jobs.fields.comment"),
+ dataIndex: "comment",
+ key: "comment",
+ ellipsis: true,
+ responsive: ["md"],
+ },
+ // {
+ // title: t("jobs.fields.owner_owing"),
+ // dataIndex: "owner_owing",
+ // key: "owner_owing",
+ // responsive: ["md"],
+ // render: (text, record) => (
+ // {record.owner_owing}
+ // ),
+ // },
+ ];
+
+ const scrollMapper = {
+ xs: true,
+ sm: true,
+ md: true,
+ lg: "100%",
+ xl: "100%",
+ xxl: "100%",
+ };
+
+ return (
+
+ ({readyStatuses && readyStatuses.join(", ")})
+ refetch()}>
+
+
+ {
+ setSearchText(e.target.value);
+ }}
+ value={searchText}
+ enterButton
+ />
+
+ }
+ >
+ {
+ handleOnRowClick(record);
+ },
+ selectedRowKeys: [selected],
+ type: "radio",
+ }}
+ onChange={handleTableChange}
+ onRow={(record, rowIndex) => {
+ return {
+ onClick: (event) => {
+ handleOnRowClick(record);
+ },
+ };
+ }}
+ />
+
+ );
}
export default connect(mapStateToProps, null)(JobsReadyList);
diff --git a/client/src/components/jobs-related-ros/jobs-related-ros.component.jsx b/client/src/components/jobs-related-ros/jobs-related-ros.component.jsx
index 9f1a3b5b9..1d77bebc8 100644
--- a/client/src/components/jobs-related-ros/jobs-related-ros.component.jsx
+++ b/client/src/components/jobs-related-ros/jobs-related-ros.component.jsx
@@ -1,20 +1,26 @@
-import { Space, Tag } from "antd";
+import {Space, Tag} from "antd";
import React from "react";
-import { Link } from "react-router-dom";
+import {Link} from "react-router-dom";
-export default function JobsRelatedRos({ jobid, job }) {
- if (!(job && job.vehicle && job.vehicle.jobs)) return null;
- return (
-
- {job.vehicle.jobs
- .filter((j) => j.id !== job.id)
- .map((j) => (
-
- {`${j.ro_number || "N/A"}${
- j.clm_no ? ` | ${j.clm_no}` : ""
- }${j.status ? ` | ${j.status}` : ""}`}
-
- ))}
-
- );
+export default function JobsRelatedRos({jobid, job, disabled}) {
+ if (!(job && job.vehicle && job.vehicle.jobs)) return null;
+ return (
+
+ {job.vehicle.jobs
+ .filter((j) => j.id !== job.id)
+ .map((j) => (
+
+ {disabled ? (
+ <>{`${j.ro_number || "N/A"}${j.clm_no ? ` | ${j.clm_no}` : ""}${
+ j.status ? ` | ${j.status}` : ""
+ }`}>
+ ) : (
+ {`${j.ro_number || "N/A"}${
+ j.clm_no ? ` | ${j.clm_no}` : ""
+ }${j.status ? ` | ${j.status}` : ""}`}
+ )}
+
+ ))}
+
+ );
}
diff --git a/client/src/components/labor-allocations-adjustment-edit/labor-allocations-adjustment-edit.component.jsx b/client/src/components/labor-allocations-adjustment-edit/labor-allocations-adjustment-edit.component.jsx
index 5d5a56d2c..b75f284a4 100644
--- a/client/src/components/labor-allocations-adjustment-edit/labor-allocations-adjustment-edit.component.jsx
+++ b/client/src/components/labor-allocations-adjustment-edit/labor-allocations-adjustment-edit.component.jsx
@@ -1,182 +1,175 @@
-import { useMutation } from "@apollo/client";
-import {
- Button,
- Card,
- Form,
- InputNumber,
- notification,
- Popover,
- Select,
-} from "antd";
-import React, { useState } from "react";
-import { useTranslation } from "react-i18next";
-import { UPDATE_JOB } from "../../graphql/jobs.queries";
+import {useMutation} from "@apollo/client";
+import {Button, Card, Form, InputNumber, notification, Popover, Select,} from "antd";
+import React, {useState} from "react";
+import {useTranslation} from "react-i18next";
+import {UPDATE_JOB} from "../../graphql/jobs.queries";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { insertAuditTrail } from "../../redux/application/application.actions";
+import {connect} from "react-redux";
+import {createStructuredSelector} from "reselect";
+import {insertAuditTrail} from "../../redux/application/application.actions";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
+
const mapStateToProps = createStructuredSelector({
- //currentUser: selectCurrentUser
+ //currentUser: selectCurrentUser
});
const mapDispatchToProps = (dispatch) => ({
- insertAuditTrail: ({ jobid, operation }) =>
- dispatch(insertAuditTrail({ jobid, operation })),
+ insertAuditTrail: ({jobid, operation}) =>
+ dispatch(insertAuditTrail({jobid, operation})),
});
export default connect(
- mapStateToProps,
- mapDispatchToProps
+ mapStateToProps,
+ mapDispatchToProps
)(LaborAllocationsAdjustmentEdit);
export function LaborAllocationsAdjustmentEdit({
- insertAuditTrail,
- jobId,
- mod_lbr_ty,
- adjustments,
- children,
- refetchQueryNames,
-}) {
- const [loading, setLoading] = useState(false);
- const [visible, setVisible] = useState(false);
- const [updateAdjustments] = useMutation(UPDATE_JOB);
- const [form] = Form.useForm();
+ insertAuditTrail,
+ jobId,
+ mod_lbr_ty,
+ adjustments,
+ children,
+ refetchQueryNames,
+ }) {
+ const [loading, setLoading] = useState(false);
+ const [open, setOpen] = useState(false);
+ const [updateAdjustments] = useMutation(UPDATE_JOB);
+ const [form] = Form.useForm();
- const { t } = useTranslation();
+ const {t} = useTranslation();
- const handleFinish = async (values) => {
- setLoading(true);
- const result = await updateAdjustments({
- variables: {
- jobId: jobId,
- job: {
- lbr_adjustments: {
- ...adjustments,
- [values.mod_lbr_ty]: values.hours,
- },
- },
- },
- ...(refetchQueryNames ? { refetchQueries: refetchQueryNames } : {}),
- });
+ const handleFinish = async (values) => {
+ setLoading(true);
+ const result = await updateAdjustments({
+ variables: {
+ jobId: jobId,
+ job: {
+ lbr_adjustments: {
+ ...adjustments,
+ [values.mod_lbr_ty]: values.hours,
+ },
+ },
+ },
+ ...(refetchQueryNames ? {refetchQueries: refetchQueryNames} : {}),
+ });
- if (!!result.errors) {
- notification["error"]({
- message: t("jobs.errors.saving", {
- message: JSON.stringify(result.errors),
- }),
- });
- } else {
- notification["success"]({
- message: t("jobs.successes.save"),
- });
- insertAuditTrail({
- jobid: jobId,
- operation: AuditTrailMapping.jobmodifylbradj({
- mod_lbr_ty: values.mod_lbr_ty,
- hours:
- values.hours -
- ((adjustments && adjustments[mod_lbr_ty]) || 0).toFixed(1),
- }),
- });
- }
- setLoading(false);
- setVisible(false);
- };
+ if (!!result.errors) {
+ notification["error"]({
+ message: t("jobs.errors.saving", {
+ message: JSON.stringify(result.errors),
+ }),
+ });
+ } else {
+ notification["success"]({
+ message: t("jobs.successes.save"),
+ });
+ insertAuditTrail({
+ jobid: jobId,
+ operation: AuditTrailMapping.jobmodifylbradj({
+ mod_lbr_ty: values.mod_lbr_ty,
+ hours:
+ values.hours -
+ ((adjustments && adjustments[mod_lbr_ty]) || 0).toFixed(1),
+ }),
+ });
+ }
+ setLoading(false);
+ setOpen(false);
+ };
- const overlay = (
-
-
-
- );
-
- return (
- setVisible(vis)}
- content={overlay}
- trigger="click"
- >
- {children}
-
- );
+ {children}
+
+ );
}
diff --git a/client/src/components/labor-allocations-table/labor-allocations-table.component.jsx b/client/src/components/labor-allocations-table/labor-allocations-table.component.jsx
index 83f99d867..4a4828d23 100644
--- a/client/src/components/labor-allocations-table/labor-allocations-table.component.jsx
+++ b/client/src/components/labor-allocations-table/labor-allocations-table.component.jsx
@@ -1,266 +1,268 @@
-import { EditFilled } from "@ant-design/icons";
-import { Card, Col, Row, Space, Table, Typography } from "antd";
+import {EditFilled} from "@ant-design/icons";
+import {Card, Col, Row, Space, Table, Typography} from "antd";
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 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 { alphaSort } from "../../utils/sorters";
-import LaborAllocationsAdjustmentEdit from "../labor-allocations-adjustment-edit/labor-allocations-adjustment-edit.component";
+import {alphaSort} from "../../utils/sorters";
+import LaborAllocationsAdjustmentEdit
+ from "../labor-allocations-adjustment-edit/labor-allocations-adjustment-edit.component";
import "./labor-allocations-table.styles.scss";
-import { CalculateAllocationsTotals } from "./labor-allocations-table.utility";
+import {CalculateAllocationsTotals} from "./labor-allocations-table.utility";
const mapStateToProps = createStructuredSelector({
- bodyshop: selectBodyshop,
- technician: selectTechnician,
+ bodyshop: selectBodyshop,
+ technician: selectTechnician,
});
export function LaborAllocationsTable({
- jobId,
- joblines,
- timetickets,
- bodyshop,
- adjustments,
- technician,
-}) {
- const { t } = useTranslation();
- const [totals, setTotals] = useState([]);
- const [state, setState] = useState({
- sortedInfo: {
- columnKey: "cost_center",
- field: "cost_center",
- order: "ascend",
- },
- filteredInfo: {},
- });
+ jobId,
+ joblines,
+ timetickets,
+ bodyshop,
+ adjustments,
+ technician,
+ }) {
+ const {t} = useTranslation();
+ const [totals, setTotals] = useState([]);
+ const [state, setState] = useState({
+ sortedInfo: {
+ columnKey: "cost_center",
+ field: "cost_center",
+ order: "ascend",
+ },
+ filteredInfo: {},
+ });
- useEffect(() => {
- if (!!joblines && !!timetickets && !!bodyshop);
- setTotals(
- CalculateAllocationsTotals(bodyshop, joblines, timetickets, adjustments)
- );
- if (!jobId) setTotals([]);
- }, [joblines, timetickets, bodyshop, adjustments, jobId]);
+ useEffect(() => {
+ if (!!joblines && !!timetickets && !!bodyshop) ;
+ setTotals(
+ CalculateAllocationsTotals(bodyshop, joblines, timetickets, adjustments)
+ );
+ if (!jobId) setTotals([]);
+ }, [joblines, timetickets, bodyshop, adjustments, jobId]);
- const convertedLines = useMemo(
- () => joblines && joblines.filter((j) => j.convertedtolbr),
- [joblines]
- );
-
- const columns = [
- {
- title: t("timetickets.fields.cost_center"),
- dataIndex: "cost_center",
- key: "cost_center",
- defaultSortOrder: "cost_center",
- sorter: (a, b) => alphaSort(a.cost_center, b.cost_center),
- sortOrder:
- state.sortedInfo.columnKey === "cost_center" && state.sortedInfo.order,
- render: (text, record) => `${record.cost_center} (${record.mod_lbr_ty})`,
- },
- {
- title: t("jobs.labels.hrs_total"),
- dataIndex: "total",
- key: "total",
- sorter: (a, b) => a.total - b.total,
- sortOrder:
- state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
- render: (text, record) => record.total.toFixed(1),
- },
- {
- title: t("jobs.labels.hrs_claimed"),
- dataIndex: "hrs_claimed",
- key: "hrs_claimed",
- sorter: (a, b) => a.claimed - b.claimed,
- sortOrder:
- state.sortedInfo.columnKey === "claimed" && state.sortedInfo.order,
- render: (text, record) => record.claimed && record.claimed.toFixed(1),
- },
- {
- title: t("jobs.labels.adjustments"),
- dataIndex: "adjustments",
- key: "adjustments",
- sorter: (a, b) => a.adjustments - b.adjustments,
- sortOrder:
- state.sortedInfo.columnKey === "adjustments" && state.sortedInfo.order,
- render: (text, record) => (
-
- {record.adjustments.toFixed(1)}
- {!technician && (
-
-
-
- )}
-
- ),
- },
- {
- 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) => (
- = 0 ? "green" : "red",
- }}
- >
- {_.round(record.difference, 1)}
-
- ),
- },
- ];
- 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) => (
- <>
-
- {record.db_ref === "900510" || record.db_ref === "900511"
- ? record.prt_dsmk_m
- : record.act_price}
-
- {record.prt_dsmk_p && record.prt_dsmk_p !== 0 ? (
- {`(${record.prt_dsmk_p}%)`}
- ) : (
- <>>
- )}
- >
- ),
- },
- {
- 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(1),
- },
- ];
-
- const handleTableChange = (pagination, filters, sorter) => {
- setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
- };
-
- const summary =
- totals &&
- totals.reduce(
- (acc, val) => {
- acc.hrs_total += val.total;
- acc.hrs_claimed += val.claimed;
- acc.adjustments += val.adjustments;
- acc.difference += val.difference;
- return acc;
- },
- { hrs_total: 0, hrs_claimed: 0, adjustments: 0, difference: 0 }
+ const convertedLines = useMemo(
+ () => joblines && joblines.filter((j) => j.convertedtolbr),
+ [joblines]
);
- return (
-
-
-
- `${record.cost_center} ${record.mod_lbr_ty}`}
- pagination={false}
- onChange={handleTableChange}
- dataSource={totals}
- scroll={{
- x: true,
- }}
- summary={() => (
-
-
-
- {t("general.labels.totals")}
-
-
-
- {summary.hrs_total.toFixed(1)}
-
-
- {summary.hrs_claimed.toFixed(1)}
-
-
- {summary.adjustments.toFixed(1)}
-
-
- alphaSort(a.cost_center, b.cost_center),
+ sortOrder:
+ state.sortedInfo.columnKey === "cost_center" && state.sortedInfo.order,
+ render: (text, record) => `${record.cost_center} (${record.mod_lbr_ty})`,
+ },
+ {
+ title: t("jobs.labels.hrs_total"),
+ dataIndex: "total",
+ key: "total",
+ sorter: (a, b) => a.total - b.total,
+ sortOrder:
+ state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
+ render: (text, record) => record.total.toFixed(1),
+ },
+ {
+ title: t("jobs.labels.hrs_claimed"),
+ dataIndex: "hrs_claimed",
+ key: "hrs_claimed",
+ sorter: (a, b) => a.claimed - b.claimed,
+ sortOrder:
+ state.sortedInfo.columnKey === "claimed" && state.sortedInfo.order,
+ render: (text, record) => record.claimed && record.claimed.toFixed(1),
+ },
+ {
+ title: t("jobs.labels.adjustments"),
+ dataIndex: "adjustments",
+ key: "adjustments",
+ sorter: (a, b) => a.adjustments - b.adjustments,
+ sortOrder:
+ state.sortedInfo.columnKey === "adjustments" && state.sortedInfo.order,
+ render: (text, record) => (
+
+ {record.adjustments.toFixed(1)}
+ {!technician && (
+
+
+
+ )}
+
+ ),
+ },
+ {
+ 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) => (
+ = 0 ? "green" : "red",
+ color: record.difference >= 0 ? "green" : "red",
}}
- >
- {summary.difference.toFixed(1)}
-
-
-
+ >
+ {_.round(record.difference, 1)}
+
+ ),
+ },
+ ];
+ 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) => (
+ <>
+
+ {record.db_ref === "900510" || record.db_ref === "900511"
+ ? record.prt_dsmk_m
+ : record.act_price}
+
+ {record.prt_dsmk_p && record.prt_dsmk_p !== 0 ? (
+ {`(${record.prt_dsmk_p}%)`}
+ ) : (
+ <>>
+ )}
+ >
+ ),
+ },
+ {
+ 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(1),
+ },
+ ];
+
+ const handleTableChange = (pagination, filters, sorter) => {
+ setState({...state, filteredInfo: filters, sortedInfo: sorter});
+ };
+
+ const summary =
+ totals &&
+ totals.reduce(
+ (acc, val) => {
+ acc.hrs_total += val.total;
+ acc.hrs_claimed += val.claimed;
+ acc.adjustments += val.adjustments;
+ acc.difference += val.difference;
+ return acc;
+ },
+ {hrs_total: 0, hrs_claimed: 0, adjustments: 0, difference: 0}
+ );
+
+ return (
+
+
+
+ `${record.cost_center} ${record.mod_lbr_ty}`}
+ pagination={false}
+ onChange={handleTableChange}
+ dataSource={totals}
+ scroll={{
+ x: true,
+ }}
+ summary={() => (
+
+
+
+ {t("general.labels.totals")}
+
+
+
+ {summary.hrs_total.toFixed(1)}
+
+
+ {summary.hrs_claimed.toFixed(1)}
+
+
+ {summary.adjustments.toFixed(1)}
+
+
+ = 0 ? "green" : "red",
+ }}
+ >
+ {summary.difference.toFixed(1)}
+
+
+
+ )}
+ />
+
+
+ {convertedLines && convertedLines.length > 0 && (
+
+
+
+
+
)}
- />
-
-
- {convertedLines && convertedLines.length > 0 && (
-
-
-
-
-
- )}
-
- );
+
+ );
}
+
export default connect(mapStateToProps, null)(LaborAllocationsTable);
diff --git a/client/src/components/labor-allocations-table/labor-allocations-table.payroll.component.jsx b/client/src/components/labor-allocations-table/labor-allocations-table.payroll.component.jsx
index 6bb247992..66bc490c3 100644
--- a/client/src/components/labor-allocations-table/labor-allocations-table.payroll.component.jsx
+++ b/client/src/components/labor-allocations-table/labor-allocations-table.payroll.component.jsx
@@ -1,333 +1,325 @@
-import {
- Button,
- Card,
- Col,
- Row,
- Space,
- Table,
- Typography,
- notification,
-} from "antd";
-import { SyncOutlined } from "@ant-design/icons";
+import {Button, Card, Col, notification, Row, Space, Table, Typography,} 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 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,
+ 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: {},
- });
+ 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 (
-
- {t("timetickets.labels.unassigned")}
-
- );
+ useEffect(() => {
+ async function CalculateTotals() {
+ const {data} = await axios.post("/payroll/calculatelabor", {
+ jobid: jobId,
+ });
+ setTotals(data);
}
- 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 ? (
-
- {t("timetickets.labels.unassigned")}
-
- ) : (
- 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
- );
+ if (!!joblines && !!timetickets && !!bodyshop) {
+ CalculateTotals();
+ }
+ if (!jobId) setTotals([]);
+ }, [joblines, timetickets, bodyshop, adjustments, jobId]);
- return (
- = 0 ? "green" : "red",
- }}
- >
- {difference}
-
- );
- },
- },
- ];
- 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) => (
- <>
-
- {record.db_ref === "900510" || record.db_ref === "900511"
- ? record.prt_dsmk_m
- : record.act_price}
-
- {record.prt_dsmk_p && record.prt_dsmk_p !== 0 ? (
- {`(${record.prt_dsmk_p}%)`}
- ) : (
- <>>
- )}
- >
- ),
- },
- {
- 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 }
+ const convertedLines = useMemo(
+ () => joblines && joblines.filter((j) => j.convertedtolbr),
+ [joblines]
);
- return (
-
-
-
- {
- const response = await axios.post("/payroll/payall", {
- jobid: jobId,
- });
+ const columns = [
+ {
+ title: t("timetickets.fields.employee"),
+ dataIndex: "employeeid",
+ key: "employeeid",
+ render: (text, record) => {
+ if (record.employeeid === undefined) {
+ return (
+
+ {t("timetickets.labels.unassigned")}
+
+ );
+ }
+ 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 ? (
+
+ {t("timetickets.labels.unassigned")}
+
+ ) : (
+ 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",
- 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,
- }),
- });
+ 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 (
+ = 0 ? "green" : "red",
+ }}
+ >
+ {difference}
+
+ );
+ },
+ },
+ ];
+ 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) => (
+ <>
+
+ {record.db_ref === "900510" || record.db_ref === "900511"
+ ? record.prt_dsmk_m
+ : record.act_price}
+
+ {record.prt_dsmk_p && record.prt_dsmk_p !== 0 ? (
+ {`(${record.prt_dsmk_p}%)`}
+ ) : (
+ <>>
+ )}
+ >
+ ),
+ },
+ {
+ 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 (
+
+