Compare commits

..

1 Commits

Author SHA1 Message Date
Allan Carr
98bff6d8f6 IO-2824 Dev Server Instance Switch
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-06-20 10:56:07 -07:00
56 changed files with 13029 additions and 14896 deletions

View File

@@ -1,6 +1,7 @@
VITE_APP_GRAPHQL_ENDPOINT=https://db.dev.bodyshop.app/v1/graphql VITE_APP_GRAPHQL_ENDPOINT=https://db.dev.bodyshop.app/v1/graphql
VITE_APP_GRAPHQL_ENDPOINT_WS=wss://db.dev.bodyshop.app/v1/graphql VITE_APP_GRAPHQL_ENDPOINT_WS=wss://db.dev.bodyshop.app/v1/graphql
VITE_APP_GA_CODE=231099835 VITE_APP_GA_CODE=231099835
# VITE_APP_FIREBASE_CONFIG={ "apiKey": "AIzaSyAuLQR9SV5LsVxjU8wh9hvFLdhcAHU6cxE", "authDomain": "rome-prod-1.firebaseapp.com", "projectId": "rome-prod-1", "storageBucket": "rome-prod-1.appspot.com", "messagingSenderId": "147786367145", "appId": "1:147786367145:web:9d4cba68071c3f29a8a9b8", "measurementId": "G-G8Z9DRHTZS"}
VITE_APP_FIREBASE_CONFIG={"apiKey":"AIzaSyDPLT8GiDHDR1R4nI66Qi0BY1aYviDPioc","authDomain":"imex-dev.firebaseapp.com","databaseURL":"https://imex-dev.firebaseio.com","projectId":"imex-dev","storageBucket":"imex-dev.appspot.com","messagingSenderId":"759548147434","appId":"1:759548147434:web:e8239868a48ceb36700993","measurementId":"G-K5XRBVVB4S"} VITE_APP_FIREBASE_CONFIG={"apiKey":"AIzaSyDPLT8GiDHDR1R4nI66Qi0BY1aYviDPioc","authDomain":"imex-dev.firebaseapp.com","databaseURL":"https://imex-dev.firebaseio.com","projectId":"imex-dev","storageBucket":"imex-dev.appspot.com","messagingSenderId":"759548147434","appId":"1:759548147434:web:e8239868a48ceb36700993","measurementId":"G-K5XRBVVB4S"}
VITE_APP_CLOUDINARY_ENDPOINT_API=https://api.cloudinary.com/v1_1/io-test VITE_APP_CLOUDINARY_ENDPOINT_API=https://api.cloudinary.com/v1_1/io-test
VITE_APP_CLOUDINARY_ENDPOINT=https://res.cloudinary.com/io-test VITE_APP_CLOUDINARY_ENDPOINT=https://res.cloudinary.com/io-test

View File

@@ -1,7 +1,8 @@
VITE_APP_GRAPHQL_ENDPOINT=https://db.dev.bodyshop.app/v1/graphql VITE_APP_GRAPHQL_ENDPOINT=https://db.dev.bodyshop.app/v1/graphql
VITE_APP_GRAPHQL_ENDPOINT_WS=wss://db.dev.bodyshop.app/v1/graphql VITE_APP_GRAPHQL_ENDPOINT_WS=wss://db.dev.bodyshop.app/v1/graphql
VITE_APP_GA_CODE=231099835 VITE_APP_GA_CODE=231099835
VITE_APP_FIREBASE_CONFIG={ "apiKey": "AIzaSyAuLQR9SV5LsVxjU8wh9hvFLdhcAHU6cxE", "authDomain": "rome-prod-1.firebaseapp.com", "projectId": "rome-prod-1", "storageBucket": "rome-prod-1.appspot.com", "messagingSenderId": "147786367145", "appId": "1:147786367145:web:9d4cba68071c3f29a8a9b8", "measurementId": "G-G8Z9DRHTZS"} # VITE_APP_FIREBASE_CONFIG={ "apiKey": "AIzaSyAuLQR9SV5LsVxjU8wh9hvFLdhcAHU6cxE", "authDomain": "rome-prod-1.firebaseapp.com", "projectId": "rome-prod-1", "storageBucket": "rome-prod-1.appspot.com", "messagingSenderId": "147786367145", "appId": "1:147786367145:web:9d4cba68071c3f29a8a9b8", "measurementId": "G-G8Z9DRHTZS"}
VITE_APP_FIREBASE_CONFIG={"apiKey":"AIzaSyDPLT8GiDHDR1R4nI66Qi0BY1aYviDPioc","authDomain":"imex-dev.firebaseapp.com","databaseURL":"https://imex-dev.firebaseio.com","projectId":"imex-dev","storageBucket":"imex-dev.appspot.com","messagingSenderId":"759548147434","appId":"1:759548147434:web:e8239868a48ceb36700993","measurementId":"G-K5XRBVVB4S"}
VITE_APP_CLOUDINARY_ENDPOINT_API=https://api.cloudinary.com/v1_1/io-test VITE_APP_CLOUDINARY_ENDPOINT_API=https://api.cloudinary.com/v1_1/io-test
VITE_APP_CLOUDINARY_ENDPOINT=https://res.cloudinary.com/io-test VITE_APP_CLOUDINARY_ENDPOINT=https://res.cloudinary.com/io-test
VITE_APP_CLOUDINARY_API_KEY=957865933348715 VITE_APP_CLOUDINARY_API_KEY=957865933348715

View File

@@ -7,7 +7,9 @@ import { connect } from "react-redux";
import { Route, Routes } from "react-router-dom"; import { Route, Routes } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import DocumentEditorContainer from "../components/document-editor/document-editor.container"; import DocumentEditorContainer from "../components/document-editor/document-editor.container";
import ErrorBoundary from "../components/error-boundary/error-boundary.component"; // Component Imports import ErrorBoundary from "../components/error-boundary/error-boundary.component";
//Component Imports
import LoadingSpinner from "../components/loading-spinner/loading-spinner.component"; import LoadingSpinner from "../components/loading-spinner/loading-spinner.component";
import DisclaimerPage from "../pages/disclaimer/disclaimer.page"; import DisclaimerPage from "../pages/disclaimer/disclaimer.page";
import LandingPage from "../pages/landing/landing.page"; import LandingPage from "../pages/landing/landing.page";
@@ -21,21 +23,20 @@ import "./App.styles.scss";
import handleBeta from "../utils/betaHandler"; import handleBeta from "../utils/betaHandler";
import Eula from "../components/eula/eula.component"; import Eula from "../components/eula/eula.component";
import InstanceRenderMgr from "../utils/instanceRenderMgr"; import InstanceRenderMgr from "../utils/instanceRenderMgr";
import ProductFruitsWrapper from "./ProductFruitsWrapper.jsx"; import { ProductFruits } from "react-product-fruits";
const ResetPassword = lazy(() => import("../pages/reset-password/reset-password.component")); const ResetPassword = lazy(() => import("../pages/reset-password/reset-password.component"));
const ManagePage = lazy(() => import("../pages/manage/manage.page.container")); const ManagePage = lazy(() => import("../pages/manage/manage.page.container"));
const SignInPage = lazy(() => import("../pages/sign-in/sign-in.page")); const SignInPage = lazy(() => import("../pages/sign-in/sign-in.page"));
const CsiPage = lazy(() => import("../pages/csi/csi.container.page")); const CsiPage = lazy(() => import("../pages/csi/csi.container.page"));
const MobilePaymentContainer = lazy(() => import("../pages/mobile-payment/mobile-payment.container")); const MobilePaymentContainer = lazy(() => import("../pages/mobile-payment/mobile-payment.container"));
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser, currentUser: selectCurrentUser,
online: selectOnline, online: selectOnline,
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
currentEula: selectCurrentEula currentEula: selectCurrentEula
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
checkUserSession: () => dispatch(checkUserSession()), checkUserSession: () => dispatch(checkUserSession()),
setOnline: (isOnline) => dispatch(setOnline(isOnline)) setOnline: (isOnline) => dispatch(setOnline(isOnline))
@@ -59,11 +60,11 @@ export function App({ bodyshop, checkUserSession, currentUser, online, setOnline
// Associate event listeners, memoize to prevent multiple listeners being added // Associate event listeners, memoize to prevent multiple listeners being added
useEffect(() => { useEffect(() => {
const offlineListener = () => { const offlineListener = (e) => {
setOnline(false); setOnline(false);
}; };
const onlineListener = () => { const onlineListener = (e) => {
setOnline(true); setOnline(true);
}; };
@@ -97,7 +98,7 @@ export function App({ bodyshop, checkUserSession, currentUser, online, setOnline
InstanceRenderMgr({ InstanceRenderMgr({
imex: "gvfvfw/bodyshopapp", imex: "gvfvfw/bodyshopapp",
rome: "rome-online/rome-online", rome: "rome-online/rome-online",
promanager: "" // TODO: AIO Add in log rocket for promanager instances. promanager: "" //TODO:AIO Add in log rocket for promanager instances.
}) })
); );
} }
@@ -110,20 +111,24 @@ export function App({ bodyshop, checkUserSession, currentUser, online, setOnline
handleBeta(); handleBeta();
if (!online) { if (!online)
return ( return (
<Result <Result
status="warning" status="warning"
title={t("general.labels.nointernet")} title={t("general.labels.nointernet")}
subTitle={t("general.labels.nointernet_sub")} subTitle={t("general.labels.nointernet_sub")}
extra={ extra={
<Button type="primary" onClick={() => window.location.reload()}> <Button
type="primary"
onClick={() => {
window.location.reload();
}}
>
{t("general.actions.refresh")} {t("general.actions.refresh")}
</Button> </Button>
} }
/> />
); );
}
if (currentEula && !currentUser.eulaIsAccepted) { if (currentEula && !currentUser.eulaIsAccepted) {
return <Eula />; return <Eula />;
@@ -142,13 +147,18 @@ export function App({ bodyshop, checkUserSession, currentUser, online, setOnline
/> />
} }
> >
<ProductFruitsWrapper <ProductFruits
currentUser={currentUser}
workspaceCode={InstanceRenderMgr({ workspaceCode={InstanceRenderMgr({
imex: null, imex: null,
rome: "9BkbEseqNqxw8jUH", rome: "9BkbEseqNqxw8jUH",
promanager: "aoJoEifvezYI0Z0P" promanager: "aoJoEifvezYI0Z0P"
})} })}
debug
language="en"
user={{
email: currentUser.email,
username: currentUser.email
}}
/> />
<Routes> <Routes>

View File

@@ -1,32 +0,0 @@
import React from "react";
import { ProductFruits } from "react-product-fruits";
import PropTypes from "prop-types";
const ProductFruitsWrapper = React.memo(({ currentUser, workspaceCode }) => {
return (
workspaceCode &&
currentUser?.authorized === true &&
currentUser?.email && (
<ProductFruits
lifeCycle="unmount"
workspaceCode={workspaceCode}
debug
language="en"
user={{
email: currentUser.email,
username: currentUser.email
}}
/>
)
);
});
export default ProductFruitsWrapper;
ProductFruitsWrapper.propTypes = {
currentUser: PropTypes.shape({
authorized: PropTypes.bool,
email: PropTypes.string
}).isRequired,
workspaceCode: PropTypes.string.isRequired
};

View File

@@ -4,6 +4,7 @@ import { useTranslation } from "react-i18next";
import InstanceRenderMgr from "../../utils/instanceRenderMgr"; import InstanceRenderMgr from "../../utils/instanceRenderMgr";
//To be used as a form element only. //To be used as a form element only.
const { Option } = Select;
const BillLineSearchSelect = ({ options, disabled, allowRemoved, ...restProps }, ref) => { const BillLineSearchSelect = ({ options, disabled, allowRemoved, ...restProps }, ref) => {
const { t } = useTranslation(); const { t } = useTranslation();

View File

@@ -14,6 +14,7 @@ import {
Typography Typography
} from "antd"; } from "antd";
import Dinero from "dinero.js"; import Dinero from "dinero.js";
import dayjs from "../../utils/day";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
@@ -21,7 +22,6 @@ import { createStructuredSelector } from "reselect";
import { determineDmsType } from "../../pages/dms/dms.container"; import { determineDmsType } from "../../pages/dms/dms.container";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import i18n from "../../translations/i18n"; import i18n from "../../translations/i18n";
import dayjs from "../../utils/day";
import DmsCdkMakes from "../dms-cdk-makes/dms-cdk-makes.component"; import DmsCdkMakes from "../dms-cdk-makes/dms-cdk-makes.component";
import DmsCdkMakesRefetch from "../dms-cdk-makes/dms-cdk-makes.refetch.component"; import DmsCdkMakesRefetch from "../dms-cdk-makes/dms-cdk-makes.refetch.component";
import FormDatePicker from "../form-date-picker/form-date-picker.component"; import FormDatePicker from "../form-date-picker/form-date-picker.component";
@@ -89,7 +89,7 @@ export function DmsPostForm({ bodyshop, socket, job, logsRef }) {
job.area_of_damage && job.area_of_damage.impact1 job.area_of_damage && job.area_of_damage.impact1
? " " + ? " " +
t("jobs.labels.dms.damageto", { t("jobs.labels.dms.damageto", {
area_of_damage: (job.area_of_damage && job.area_of_damage.impact1.padStart(2, "0")) || "UNKNOWN" area_of_damage: (job.area_of_damage && job.area_of_damage.impact1) || "UNKNOWN"
}) })
: "" : ""
}`.slice(0, 239), }`.slice(0, 239),

View File

@@ -1,5 +1,6 @@
import { useMutation } from "@apollo/client"; import { useMutation } from "@apollo/client";
import { Button, Card, Form, Input, notification, Switch } from "antd"; import { Button, Card, Form, Input, notification, Switch } from "antd";
import dayjs from "../../../../utils/day";
import queryString from "query-string"; import queryString from "query-string";
import React, { useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -13,7 +14,6 @@ import { UPDATE_OWNER } from "../../../../graphql/owners.queries";
import { insertAuditTrail } from "../../../../redux/application/application.actions"; import { insertAuditTrail } from "../../../../redux/application/application.actions";
import { selectBodyshop, selectCurrentUser } from "../../../../redux/user/user.selectors"; import { selectBodyshop, selectCurrentUser } from "../../../../redux/user/user.selectors";
import AuditTrailMapping from "../../../../utils/AuditTrailMappings"; import AuditTrailMapping from "../../../../utils/AuditTrailMappings";
import dayjs from "../../../../utils/day";
import ConfigFormComponents from "../../../config-form-components/config-form-components.component"; import ConfigFormComponents from "../../../config-form-components/config-form-components.component";
import DateTimePicker from "../../../form-date-time-picker/form-date-time-picker.component"; import DateTimePicker from "../../../form-date-time-picker/form-date-time-picker.component";
@@ -275,19 +275,7 @@ export function JobChecklistForm({ insertAuditTrail, formItems, bodyshop, curren
> >
<DateTimePicker disabled={readOnly} /> <DateTimePicker disabled={readOnly} />
</Form.Item> </Form.Item>
<Form.Item <Form.Item name="actual_delivery" label={t("jobs.fields.actual_delivery")} disabled={readOnly}>
name="actual_delivery"
label={t("jobs.fields.actual_delivery")}
rules={[
{
required: bodyshop.deliverchecklist.actual_delivery
? bodyshop.deliverchecklist.actual_delivery
: false
//message: t("general.validation.required"),
}
]}
disabled={readOnly}
>
<DateTimePicker disabled={readOnly} /> <DateTimePicker disabled={readOnly} />
</Form.Item> </Form.Item>
<Form.Item <Form.Item

View File

@@ -3,7 +3,7 @@ import React from "react";
import { useQuery } from "@apollo/client"; import { useQuery } from "@apollo/client";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { QUERY_PARTS_BILLS_BY_JOBID } from "../../graphql/bills.queries"; import { QUERY_BILLS_BY_JOBID } from "../../graphql/bills.queries";
import { selectJobReadOnly } from "../../redux/application/application.selectors"; import { selectJobReadOnly } from "../../redux/application/application.selectors";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
@@ -19,7 +19,7 @@ const mapDispatchToProps = (dispatch) => ({
export default connect(mapStateToProps, mapDispatchToProps)(JobCloseRoGuardBills); export default connect(mapStateToProps, mapDispatchToProps)(JobCloseRoGuardBills);
export function JobCloseRoGuardBills({ job, jobRO, bodyshop, form, warningCallback }) { export function JobCloseRoGuardBills({ job, jobRO, bodyshop, form, warningCallback }) {
const { loading, error, data } = useQuery(QUERY_PARTS_BILLS_BY_JOBID, { const { loading, error, data } = useQuery(QUERY_BILLS_BY_JOBID, {
variables: { jobid: job.id }, variables: { jobid: job.id },
fetchPolicy: "network-only", fetchPolicy: "network-only",
nextFetchPolicy: "network-only" nextFetchPolicy: "network-only"

View File

@@ -1,6 +1,6 @@
import React, { useCallback, useState } from "react";
import { LockOutlined } from "@ant-design/icons"; import { LockOutlined } from "@ant-design/icons";
import { Badge, Card, Col, Collapse, Form, Input, Row, Space, Tooltip } from "antd"; import { Badge, Card, Col, Collapse, Form, Input, Row, Space, Tooltip } from "antd";
import React, { useCallback, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
@@ -12,9 +12,9 @@ import JobCloseRoGuardBills from "./job-close-ro-guard.bills";
import JobCloseRoGuardPpd from "./job-close-ro-guard.ppd"; import JobCloseRoGuardPpd from "./job-close-ro-guard.ppd";
import JobCloseRoGuardProfit from "./job-close-ro-guard.profit"; import JobCloseRoGuardProfit from "./job-close-ro-guard.profit";
import "./job-close-ro-guard.styles.scss"; import "./job-close-ro-guard.styles.scss";
// import JobCloseRoGuardSublet from "./job-close-ro-guard.sublet"; import JobCloseRoGuardSublet from "./job-close-ro-guard.sublet";
import InstanceRenderManager from "../../utils/instanceRenderMgr";
import JobCloseRoGuardTtLifecycle from "./job-close-ro-guard.tt-lifecycle"; import JobCloseRoGuardTtLifecycle from "./job-close-ro-guard.tt-lifecycle";
import InstanceRenderManager from "../../utils/instanceRenderMgr";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser //currentUser: selectCurrentUser

View File

@@ -1,21 +1,14 @@
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import Car from "../job-damage-visual/job-damage-visual.component";
import CardTemplate from "./job-detail-cards.template.component"; import CardTemplate from "./job-detail-cards.template.component";
import Car from "../job-damage-visual/job-damage-visual.component";
export default function JobDetailCardsDamageComponent({ loading, data }) { export default function JobDetailCardsDamageComponent({ loading, data }) {
const { t } = useTranslation(); const { t } = useTranslation();
const { area_of_damage } = data; const { area_of_damage } = data;
return ( return (
<CardTemplate loading={loading} title={t("jobs.labels.cards.damage")}> <CardTemplate loading={loading} title={t("jobs.labels.cards.damage")}>
{area_of_damage ? ( {area_of_damage ? <Car dmg1={area_of_damage.impact1} dmg2={area_of_damage.impact2} /> : t("jobs.errors.nodamage")}
<Car
dmg1={area_of_damage.impact1 && area_of_damage.impact1.padStart(2, "0")}
dmg2={area_of_damage.impact2 && area_of_damage.impact2.padStart(2, "0")}
/>
) : (
t("jobs.errors.nodamage")
)}
</CardTemplate> </CardTemplate>
); );
} }

View File

@@ -26,16 +26,6 @@ export function JobDetailCardsPartsComponent({ loading, data, jobRO }) {
const { t } = useTranslation(); const { t } = useTranslation();
const { joblines_status } = data; const { joblines_status } = data;
const filteredJobLines = data.joblines.filter(
(j) =>
j.part_type !== null &&
j.part_type !== "PAE" &&
j.part_type !== "PAS" &&
j.part_type !== "PASL" &&
j.part_qty !== 0 &&
j.act_price !== 0
);
//TODO: Correct jobline_statuses view by including the part_qty !== 0 and act_price !== 0
const columns = [ const columns = [
{ {
title: t("joblines.fields.line_desc"), title: t("joblines.fields.line_desc"),
@@ -105,7 +95,7 @@ export function JobDetailCardsPartsComponent({ loading, data, jobRO }) {
<div> <div>
<CardTemplate loading={loading} title={t("jobs.labels.cards.parts")}> <CardTemplate loading={loading} title={t("jobs.labels.cards.parts")}>
<PartsStatusPie joblines_status={joblines_status} /> <PartsStatusPie joblines_status={joblines_status} />
<Table key="id" columns={columns} dataSource={filteredJobLines ? filteredJobLines : []} /> <Table key="id" columns={columns} dataSource={data ? data.joblines : []} />
</CardTemplate> </CardTemplate>
</div> </div>
); );

View File

@@ -2,18 +2,17 @@ import { useQuery } from "@apollo/client";
import { Col, Row, Skeleton, Space, Timeline, Typography } from "antd"; import { Col, Row, Skeleton, Space, Timeline, Typography } from "antd";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import { GET_JOB_LINE_ORDERS } from "../../graphql/jobs.queries"; import { GET_JOB_LINE_ORDERS } from "../../graphql/jobs.queries";
import { QUERY_JOBLINE_TASKS_PAGINATED } from "../../graphql/tasks.queries.js";
import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter"; import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { DateFormatter } from "../../utils/DateFormatter"; import { DateFormatter } from "../../utils/DateFormatter";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
import BillDetailEditcontainer from "../bill-detail-edit/bill-detail-edit.container.jsx"; import { connect } from "react-redux";
import FeatureWrapper from "../feature-wrapper/feature-wrapper.component.jsx"; import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { QUERY_JOBLINE_TASKS_PAGINATED } from "../../graphql/tasks.queries.js";
import TaskListContainer from "../task-list/task-list.container.jsx"; import TaskListContainer from "../task-list/task-list.container.jsx";
import FeatureWrapper from "../feature-wrapper/feature-wrapper.component.jsx";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop bodyshop: selectBodyshop
@@ -85,17 +84,17 @@ export function JobLinesExpander({ jobline, jobid, bodyshop }) {
key: line.id, key: line.id,
children: ( children: (
<Row> <Row>
<Col span={8}>{line.parts_dispatch.number}</Col> <Col span={8}>
<Link to={`/manage/jobs/${jobid}?partsorderid=${line.id}`}>{line.parts_dispatch.number}</Link>
</Col>
<Col span={8}> <Col span={8}>
{bodyshop.employees.find((e) => e.id === line.parts_dispatch.employeeid)?.first_name} {bodyshop.employees.find((e) => e.id === line.parts_dispatch.employeeid)?.first_name}
</Col> </Col>
<Col span={8}> <Col span={8}>
{line.accepted_at ? ( <Space>
<Space> {t("parts_dispatch_lines.fields.accepted_at")}
{t("parts_dispatch_lines.fields.accepted_at")} <DateFormatter>{line.accepted_at}</DateFormatter>
<DateFormatter>{line.accepted_at}</DateFormatter> </Space>
</Space>
) : null}
</Col> </Col>
</Row> </Row>
) )
@@ -112,7 +111,6 @@ export function JobLinesExpander({ jobline, jobid, bodyshop }) {
<FeatureWrapper featureName="bills" noauth={() => null}> <FeatureWrapper featureName="bills" noauth={() => null}>
<Col md={24} lg={8}> <Col md={24} lg={8}>
<Typography.Title level={4}>{t("bills.labels.bills")}</Typography.Title> <Typography.Title level={4}>{t("bills.labels.bills")}</Typography.Title>
<BillDetailEditcontainer />
<Timeline <Timeline
items={ items={
data.billlines.length > 0 data.billlines.length > 0

View File

@@ -31,20 +31,19 @@ import JobLinesBillRefernece from "../job-lines-bill-reference/job-lines-bill-re
// import AllocationsEmployeeLabelContainer from "../allocations-employee-label/allocations-employee-label.container"; // import AllocationsEmployeeLabelContainer from "../allocations-employee-label/allocations-employee-label.container";
import { useSplitTreatments } from "@splitsoftware/splitio-react"; import { useSplitTreatments } from "@splitsoftware/splitio-react";
import _ from "lodash"; import _ from "lodash";
import { FaTasks } from "react-icons/fa";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import dayjs from "../../utils/day"; import dayjs from "../../utils/day";
import InstanceRenderManager from "../../utils/instanceRenderMgr";
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component"; import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
import JobCreateIOU from "../job-create-iou/job-create-iou.component"; import JobCreateIOU from "../job-create-iou/job-create-iou.component";
import JobLineBulkAssignComponent from "../job-line-bulk-assign/job-line-bulk-assign.component"; import JobLineBulkAssignComponent from "../job-line-bulk-assign/job-line-bulk-assign.component";
import JobLineDispatchButton from "../job-line-dispatch-button/job-line-dispatch-button.component"; import JobLineDispatchButton from "../job-line-dispatch-button/job-line-dispatch-button.component";
import JoblineTeamAssignment from "../job-line-team-assignment/job-line-team-assignmnent.component"; import JoblineTeamAssignment from "../job-line-team-assignment/job-line-team-assignmnent.component";
import JobSendPartPriceChangeComponent from "../job-send-parts-price-change/job-send-parts-price-change.component"; import JobSendPartPriceChangeComponent from "../job-send-parts-price-change/job-send-parts-price-change.component";
import PartsOrderDrawer from "../parts-order-list-table/parts-order-list-table-drawer.component";
import PartsOrderModalContainer from "../parts-order-modal/parts-order-modal.container"; import PartsOrderModalContainer from "../parts-order-modal/parts-order-modal.container";
import JobLinesExpander from "./job-lines-expander.component"; import JobLinesExpander from "./job-lines-expander.component";
import JobLinesPartPriceChange from "./job-lines-part-price-change.component"; import JobLinesPartPriceChange from "./job-lines-part-price-change.component";
import { FaTasks } from "react-icons/fa";
import InstanceRenderManager from "../../utils/instanceRenderMgr";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
@@ -55,7 +54,6 @@ const mapStateToProps = createStructuredSelector({
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
setJobLineEditContext: (context) => dispatch(setModalContext({ context: context, modal: "jobLineEdit" })), setJobLineEditContext: (context) => dispatch(setModalContext({ context: context, modal: "jobLineEdit" })),
setPartsOrderContext: (context) => dispatch(setModalContext({ context: context, modal: "partsOrder" })), setPartsOrderContext: (context) => dispatch(setModalContext({ context: context, modal: "partsOrder" })),
setPartsReceiveContext: (context) => dispatch(setModalContext({ context: context, modal: "partsReceive" })),
setBillEnterContext: (context) => dispatch(setModalContext({ context: context, modal: "billEnter" })), setBillEnterContext: (context) => dispatch(setModalContext({ context: context, modal: "billEnter" })),
setTaskUpsertContext: (context) => dispatch(setModalContext({ context, modal: "taskUpsert" })) setTaskUpsertContext: (context) => dispatch(setModalContext({ context, modal: "taskUpsert" }))
}); });
@@ -65,7 +63,6 @@ export function JobLinesComponent({
jobRO, jobRO,
technician, technician,
setPartsOrderContext, setPartsOrderContext,
setPartsReceiveContext,
loading, loading,
refetch, refetch,
jobLines, jobLines,
@@ -74,11 +71,7 @@ export function JobLinesComponent({
setJobLineEditContext, setJobLineEditContext,
form, form,
setBillEnterContext, setBillEnterContext,
setTaskUpsertContext, setTaskUpsertContext
billsQuery,
handleBillOnRowClick,
handlePartsOrderOnRowClick,
handlePartsDispatchOnRowClick
}) { }) {
const [deleteJobLine] = useMutation(DELETE_JOB_LINE_BY_PK); const [deleteJobLine] = useMutation(DELETE_JOB_LINE_BY_PK);
const { const {
@@ -444,13 +437,6 @@ export function JobLinesComponent({
return ( return (
<div> <div>
<PartsOrderModalContainer /> <PartsOrderModalContainer />
<PartsOrderDrawer
job={job}
billsQuery={billsQuery}
handleOnRowClick={handlePartsOrderOnRowClick}
setPartsReceiveContext={setPartsReceiveContext}
setTaskUpsertContext={setTaskUpsertContext}
/>
<PageHeader <PageHeader
title={t("jobs.labels.estimatelines")} title={t("jobs.labels.estimatelines")}
extra={ extra={

View File

@@ -1,17 +1,7 @@
import React, { useMemo, useState } from "react"; import React, { useMemo, useState } from "react";
import JobLinesComponent from "./job-lines.component"; import JobLinesComponent from "./job-lines.component";
function JobLinesContainer({ function JobLinesContainer({ job, joblines, refetch, form, ...rest }) {
job,
joblines,
billsQuery,
handleBillOnRowClick,
handlePartsOrderOnRowClick,
handlePartsDispatchOnRowClick,
refetch,
form,
...rest
}) {
const [searchText, setSearchText] = useState(""); const [searchText, setSearchText] = useState("");
const jobLines = useMemo(() => { const jobLines = useMemo(() => {
@@ -32,19 +22,7 @@ function JobLinesContainer({
}, [joblines, searchText]); }, [joblines, searchText]);
return ( return (
<div> <JobLinesComponent refetch={refetch} jobLines={jobLines} setSearchText={setSearchText} job={job} form={form} />
<JobLinesComponent
refetch={refetch}
jobLines={jobLines}
billsQuery={billsQuery}
handleBillOnRowClick={handleBillOnRowClick}
handlePartsOrderOnRowClick={handlePartsOrderOnRowClick}
handlePartsDispatchOnRowClick={handlePartsDispatchOnRowClick}
setSearchText={setSearchText}
job={job}
form={form}
/>
</div>
); );
} }

View File

@@ -3,8 +3,8 @@ import Dinero from "dinero.js";
import React, { useMemo, useState } from "react"; import React, { useMemo, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import CurrencyFormatter from "../../utils/CurrencyFormatter"; import CurrencyFormatter from "../../utils/CurrencyFormatter";
import InstanceRenderManager from "../../utils/instanceRenderMgr";
import { alphaSort } from "../../utils/sorters"; import { alphaSort } from "../../utils/sorters";
import InstanceRenderManager from "../../utils/instanceRenderMgr";
export default function JobTotalsTableLabor({ job }) { export default function JobTotalsTableLabor({ job }) {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -56,47 +56,16 @@ export default function JobTotalsTableLabor({ job }) {
sortOrder: state.sortedInfo.columnKey === "mod_lb_hrs" && state.sortedInfo.order, sortOrder: state.sortedInfo.columnKey === "mod_lb_hrs" && state.sortedInfo.order,
render: (text, record) => record.hours.toFixed(1) render: (text, record) => record.hours.toFixed(1)
}, },
...InstanceRenderManager({ {
imex: { title: t("joblines.fields.total"),
title: t("joblines.fields.total"), dataIndex: "total",
dataIndex: "total", key: "total",
key: "total", align: "right",
align: "right", sorter: (a, b) => a.total.amount - b.total.amount,
sorter: (a, b) => a.total.amount - b.total.amount, sortOrder: state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
sortOrder: state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
render: (text, record) => Dinero(record.total).toFormat() render: (text, record) => Dinero(record.total).toFormat()
}, }
rome: [
{
title: t("joblines.fields.amount"),
dataIndex: "base",
key: "base",
align: "right",
sorter: (a, b) => a.base.amount - b.base.amount,
sortOrder: state.sortedInfo.columnKey === "base" && state.sortedInfo.order,
render: (text, record) => Dinero(record.base).toFormat()
},
{
title: t("joblines.fields.adjustment"),
dataIndex: "adjustment",
key: "adjustment",
align: "right",
sorter: (a, b) => a.adjustment.amount - b.adjustment.amount,
sortOrder: state.sortedInfo.columnKey === "adjustment" && state.sortedInfo.order,
render: (text, record) => Dinero(record.adjustment).toFormat()
},
{
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()
}
],
promanager: "USE_ROME"
})
]; ];
const handleTableChange = (pagination, filters, sorter) => { const handleTableChange = (pagination, filters, sorter) => {
@@ -122,16 +91,6 @@ export default function JobTotalsTableLabor({ job }) {
<Table.Summary.Cell> <Table.Summary.Cell>
{(job.job_totals.rates.mapa.hours + job.job_totals.rates.mash.hours).toFixed(1)} {(job.job_totals.rates.mapa.hours + job.job_totals.rates.mash.hours).toFixed(1)}
</Table.Summary.Cell> </Table.Summary.Cell>
{InstanceRenderManager({
imex: null,
rome: (
<>
<Table.Summary.Cell />
<Table.Summary.Cell />
</>
),
promanager: "USE_ROME"
})}
<Table.Summary.Cell align="right"> <Table.Summary.Cell align="right">
<strong>{Dinero(job.job_totals.rates.rates_subtotal).toFormat()}</strong> <strong>{Dinero(job.job_totals.rates.rates_subtotal).toFormat()}</strong>
</Table.Summary.Cell> </Table.Summary.Cell>
@@ -163,29 +122,7 @@ export default function JobTotalsTableLabor({ job }) {
<CurrencyFormatter>{job.job_totals.rates.mapa.rate}</CurrencyFormatter> <CurrencyFormatter>{job.job_totals.rates.mapa.rate}</CurrencyFormatter>
</Table.Summary.Cell> </Table.Summary.Cell>
<Table.Summary.Cell>{job.job_totals.rates.mapa.hours.toFixed(1)}</Table.Summary.Cell> <Table.Summary.Cell>{job.job_totals.rates.mapa.hours.toFixed(1)}</Table.Summary.Cell>
{InstanceRenderManager({ <Table.Summary.Cell align="right">{Dinero(job.job_totals.rates.mapa.total).toFormat()}</Table.Summary.Cell>
imex: (
<>
<Table.Summary.Cell align="right">
{Dinero(job.job_totals.rates.mapa.total).toFormat()}
</Table.Summary.Cell>
</>
),
rome: (
<>
<Table.Summary.Cell align="right">
{Dinero(job.job_totals.rates.mapa.base).toFormat()}
</Table.Summary.Cell>
<Table.Summary.Cell align="right">
{Dinero(job.job_totals.rates.mapa.adjustment).toFormat()}
</Table.Summary.Cell>
<Table.Summary.Cell align="right">
{Dinero(job.job_totals.rates.mapa.total).toFormat()}
</Table.Summary.Cell>
</>
),
promanager: "USE_ROME"
})}
</Table.Summary.Row> </Table.Summary.Row>
<Table.Summary.Row> <Table.Summary.Row>
<Table.Summary.Cell> <Table.Summary.Cell>
@@ -214,29 +151,7 @@ export default function JobTotalsTableLabor({ job }) {
<CurrencyFormatter>{job.job_totals.rates.mash.rate}</CurrencyFormatter> <CurrencyFormatter>{job.job_totals.rates.mash.rate}</CurrencyFormatter>
</Table.Summary.Cell> </Table.Summary.Cell>
<Table.Summary.Cell>{job.job_totals.rates.mash.hours.toFixed(1)}</Table.Summary.Cell> <Table.Summary.Cell>{job.job_totals.rates.mash.hours.toFixed(1)}</Table.Summary.Cell>
{InstanceRenderManager({ <Table.Summary.Cell align="right">{Dinero(job.job_totals.rates.mash.total).toFormat()}</Table.Summary.Cell>
imex: (
<>
<Table.Summary.Cell align="right">
{Dinero(job.job_totals.rates.mash.total).toFormat()}
</Table.Summary.Cell>
</>
),
rome: (
<>
<Table.Summary.Cell align="right">
{Dinero(job.job_totals.rates.mash.base).toFormat()}
</Table.Summary.Cell>
<Table.Summary.Cell align="right">
{Dinero(job.job_totals.rates.mash.adjustment).toFormat()}
</Table.Summary.Cell>
<Table.Summary.Cell align="right">
{Dinero(job.job_totals.rates.mash.total).toFormat()}
</Table.Summary.Cell>
</>
),
promanager: "USE_ROME"
})}
</Table.Summary.Row> </Table.Summary.Row>
<Table.Summary.Row> <Table.Summary.Row>
<Table.Summary.Cell> <Table.Summary.Cell>
@@ -244,16 +159,6 @@ export default function JobTotalsTableLabor({ job }) {
</Table.Summary.Cell> </Table.Summary.Cell>
<Table.Summary.Cell /> <Table.Summary.Cell />
<Table.Summary.Cell /> <Table.Summary.Cell />
{InstanceRenderManager({
imex: null,
rome: (
<>
<Table.Summary.Cell />
<Table.Summary.Cell />
</>
),
promanager: "USE_ROME"
})}
<Table.Summary.Cell align="right"> <Table.Summary.Cell align="right">
<strong>{Dinero(job.job_totals.rates.subtotal).toFormat()}</strong> <strong>{Dinero(job.job_totals.rates.subtotal).toFormat()}</strong>
</Table.Summary.Cell> </Table.Summary.Cell>

View File

@@ -3,7 +3,6 @@ import { Button, Space, notification } from "antd";
import React, { useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { DELETE_DELIVERY_CHECKLIST, DELETE_INTAKE_CHECKLIST } from "../../graphql/jobs.queries"; import { DELETE_DELIVERY_CHECKLIST, DELETE_INTAKE_CHECKLIST } from "../../graphql/jobs.queries";
import InstanceRenderManager from "../../utils/instanceRenderMgr";
export default function JobAdminDeleteIntake({ job }) { export default function JobAdminDeleteIntake({ job }) {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -48,22 +47,16 @@ export default function JobAdminDeleteIntake({ job }) {
setLoading(false); setLoading(false);
}; };
const InstanceRender = InstanceRenderManager({ return (
imex: true,
rome: "USE_IMEX",
promanager: false
});
return InstanceRender ? (
<> <>
<Space wrap> <Space wrap>
<Button loading={loading} onClick={handleDelete} disabled={!job.intakechecklist}> <Button loading={loading} onClick={handleDelete} disabled={!job.intakechecklist}>
{t("jobs.labels.deleteintake")} {t("jobs.labels.deleteintake")}
</Button> </Button>
<Button loading={loading} onClick={handleDeleteDelivery} disabled={!job.deliverchecklist}> <Button loading={loading} onClick={handleDeleteDelivery} disabled={!job.deliverychecklist}>
{t("jobs.labels.deletedelivery")} {t("jobs.labels.deletedelivery")}
</Button> </Button>
</Space> </Space>
</> </>
) : null; );
} }

View File

@@ -189,10 +189,7 @@ export function JobsDetailGeneral({ bodyshop, jobRO, job, form }) {
</Col> </Col>
<Col {...lossColDamage}> <Col {...lossColDamage}>
{job.area_of_damage ? ( {job.area_of_damage ? (
<Car <Car dmg1={job.area_of_damage.impact1} dmg2={job.area_of_damage.impact2} />
dmg1={job.area_of_damage.impact1 && job.area_of_damage.impact1.padStart(2, "0")}
dmg2={job.area_of_damage.impact2 && job.area_of_damage.impact2.padStart(2, "0")}
/>
) : ( ) : (
t("jobs.errors.nodamage") t("jobs.errors.nodamage")
)} )}

View File

@@ -1,13 +1,55 @@
import { useQuery } from "@apollo/client";
import queryString from "query-string";
import React from "react"; import React from "react";
import { useLocation, useNavigate } from "react-router-dom";
import { QUERY_BILLS_BY_JOBID } from "../../graphql/bills.queries";
import JobsDetailPliComponent from "./jobs-detail-pli.component"; import JobsDetailPliComponent from "./jobs-detail-pli.component";
export default function JobsDetailPliContainer({ export default function JobsDetailPliContainer({ job }) {
job, const billsQuery = useQuery(QUERY_BILLS_BY_JOBID, {
billsQuery, variables: { jobid: job.id },
handleBillOnRowClick, fetchPolicy: "network-only",
handlePartsOrderOnRowClick, nextFetchPolicy: "network-only"
handlePartsDispatchOnRowClick });
}) {
const search = queryString.parse(useLocation().search);
const history = useNavigate();
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({ 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 ( return (
<JobsDetailPliComponent <JobsDetailPliComponent
job={job} job={job}

View File

@@ -1,4 +1,4 @@
import { Collapse, Form, InputNumber, Switch } from "antd"; import { Collapse, Form, Switch } from "antd";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
@@ -17,9 +17,6 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
<Collapse defaultActiveKey={expanded && "rates"}> <Collapse defaultActiveKey={expanded && "rates"}>
<Collapse.Panel forceRender header={t("jobs.labels.cieca_pfl")} key="cieca_pfl"> <Collapse.Panel forceRender header={t("jobs.labels.cieca_pfl")} key="cieca_pfl">
<LayoutFormRow header={t("joblines.fields.lbr_types.LAB")}> <LayoutFormRow header={t("joblines.fields.lbr_types.LAB")}>
<Form.Item label={t("jobs.fields.cieca_pfl.lbr_adjp")} name={["cieca_pfl", "LAB", "lbr_adjp"]}>
<InputNumber min={-100} max={100} precision={4} disabled={jobRO} />
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tax_in")} label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
name={["cieca_pfl", "LAB", "lbr_tax_in"]} name={["cieca_pfl", "LAB", "lbr_tax_in"]}
@@ -27,24 +24,6 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
> >
<Switch disabled={jobRO} /> <Switch disabled={jobRO} />
</Form.Item> </Form.Item>
<Form.Item shouldUpdate>
{() => {
return (
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_taxp")}
name={["cieca_pfl", "LAB", "lbr_taxp"]}
rules={[
{
required: form.getFieldValue(["cieca_pfl", "LAB", "lbr_tax_in"])
//message: t("general.validation.required"),
}
]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")} label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
name={["cieca_pfl", "LAB", "lbr_tx_in1"]} name={["cieca_pfl", "LAB", "lbr_tx_in1"]}
@@ -82,9 +61,6 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
</Form.Item> </Form.Item>
</LayoutFormRow> </LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.lbr_types.LAD")}> <LayoutFormRow header={t("joblines.fields.lbr_types.LAD")}>
<Form.Item label={t("jobs.fields.cieca_pfl.lbr_adjp")} name={["cieca_pfl", "LAD", "lbr_adjp"]}>
<InputNumber min={-100} max={100} precision={4} disabled={jobRO} />
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tax_in")} label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
name={["cieca_pfl", "LAD", "lbr_tax_in"]} name={["cieca_pfl", "LAD", "lbr_tax_in"]}
@@ -92,24 +68,6 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
> >
<Switch disabled={jobRO} /> <Switch disabled={jobRO} />
</Form.Item> </Form.Item>
<Form.Item shouldUpdate>
{() => {
return (
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_taxp")}
name={["cieca_pfl", "LAD", "lbr_taxp"]}
rules={[
{
required: form.getFieldValue(["cieca_pfl", "LAD", "lbr_tax_in"])
//message: t("general.validation.required"),
}
]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")} label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
name={["cieca_pfl", "LAD", "lbr_tx_in1"]} name={["cieca_pfl", "LAD", "lbr_tx_in1"]}
@@ -147,9 +105,6 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
</Form.Item> </Form.Item>
</LayoutFormRow> </LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.lbr_types.LAE")}> <LayoutFormRow header={t("joblines.fields.lbr_types.LAE")}>
<Form.Item label={t("jobs.fields.cieca_pfl.lbr_adjp")} name={["cieca_pfl", "LAE", "lbr_adjp"]}>
<InputNumber min={-100} max={100} precision={4} disabled={jobRO} />
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tax_in")} label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
name={["cieca_pfl", "LAE", "lbr_tax_in"]} name={["cieca_pfl", "LAE", "lbr_tax_in"]}
@@ -157,24 +112,6 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
> >
<Switch disabled={jobRO} /> <Switch disabled={jobRO} />
</Form.Item> </Form.Item>
<Form.Item shouldUpdate>
{() => {
return (
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_taxp")}
name={["cieca_pfl", "LAE", "lbr_taxp"]}
rules={[
{
required: form.getFieldValue(["cieca_pfl", "LAE", "lbr_tax_in"])
//message: t("general.validation.required"),
}
]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")} label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
name={["cieca_pfl", "LAE", "lbr_tx_in1"]} name={["cieca_pfl", "LAE", "lbr_tx_in1"]}
@@ -212,9 +149,6 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
</Form.Item> </Form.Item>
</LayoutFormRow> </LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.lbr_types.LAF")}> <LayoutFormRow header={t("joblines.fields.lbr_types.LAF")}>
<Form.Item label={t("jobs.fields.cieca_pfl.lbr_adjp")} name={["cieca_pfl", "LAF", "lbr_adjp"]}>
<InputNumber min={-100} max={100} precision={4} disabled={jobRO} />
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tax_in")} label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
name={["cieca_pfl", "LAF", "lbr_tax_in"]} name={["cieca_pfl", "LAF", "lbr_tax_in"]}
@@ -222,24 +156,6 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
> >
<Switch disabled={jobRO} /> <Switch disabled={jobRO} />
</Form.Item> </Form.Item>
<Form.Item shouldUpdate>
{() => {
return (
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_taxp")}
name={["cieca_pfl", "LAF", "lbr_taxp"]}
rules={[
{
required: form.getFieldValue(["cieca_pfl", "LAF", "lbr_tax_in"])
//message: t("general.validation.required"),
}
]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")} label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
name={["cieca_pfl", "LAF", "lbr_tx_in1"]} name={["cieca_pfl", "LAF", "lbr_tx_in1"]}
@@ -277,9 +193,6 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
</Form.Item> </Form.Item>
</LayoutFormRow> </LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.lbr_types.LAG")}> <LayoutFormRow header={t("joblines.fields.lbr_types.LAG")}>
<Form.Item label={t("jobs.fields.cieca_pfl.lbr_adjp")} name={["cieca_pfl", "LAG", "lbr_adjp"]}>
<InputNumber min={-100} max={100} precision={4} disabled={jobRO} />
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tax_in")} label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
name={["cieca_pfl", "LAG", "lbr_tax_in"]} name={["cieca_pfl", "LAG", "lbr_tax_in"]}
@@ -287,24 +200,6 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
> >
<Switch disabled={jobRO} /> <Switch disabled={jobRO} />
</Form.Item> </Form.Item>
<Form.Item shouldUpdate>
{() => {
return (
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_taxp")}
name={["cieca_pfl", "LAG", "lbr_taxp"]}
rules={[
{
required: form.getFieldValue(["cieca_pfl", "LAG", "lbr_tax_in"])
//message: t("general.validation.required"),
}
]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")} label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
name={["cieca_pfl", "LAG", "lbr_tx_in1"]} name={["cieca_pfl", "LAG", "lbr_tx_in1"]}
@@ -342,9 +237,6 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
</Form.Item> </Form.Item>
</LayoutFormRow> </LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.lbr_types.LAM")}> <LayoutFormRow header={t("joblines.fields.lbr_types.LAM")}>
<Form.Item label={t("jobs.fields.cieca_pfl.lbr_adjp")} name={["cieca_pfl", "LAM", "lbr_adjp"]}>
<InputNumber min={-100} max={100} precision={4} disabled={jobRO} />
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tax_in")} label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
name={["cieca_pfl", "LAM", "lbr_tax_in"]} name={["cieca_pfl", "LAM", "lbr_tax_in"]}
@@ -352,24 +244,6 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
> >
<Switch disabled={jobRO} /> <Switch disabled={jobRO} />
</Form.Item> </Form.Item>
<Form.Item shouldUpdate>
{() => {
return (
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_taxp")}
name={["cieca_pfl", "LAM", "lbr_taxp"]}
rules={[
{
required: form.getFieldValue(["cieca_pfl", "LAM", "lbr_tax_in"])
//message: t("general.validation.required"),
}
]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")} label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
name={["cieca_pfl", "LAM", "lbr_tx_in1"]} name={["cieca_pfl", "LAM", "lbr_tx_in1"]}
@@ -407,9 +281,6 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
</Form.Item> </Form.Item>
</LayoutFormRow> </LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.lbr_types.LAR")}> <LayoutFormRow header={t("joblines.fields.lbr_types.LAR")}>
<Form.Item label={t("jobs.fields.cieca_pfl.lbr_adjp")} name={["cieca_pfl", "LAR", "lbr_adjp"]}>
<InputNumber min={-100} max={100} precision={4} disabled={jobRO} />
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tax_in")} label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
name={["cieca_pfl", "LAR", "lbr_tax_in"]} name={["cieca_pfl", "LAR", "lbr_tax_in"]}
@@ -417,24 +288,6 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
> >
<Switch disabled={jobRO} /> <Switch disabled={jobRO} />
</Form.Item> </Form.Item>
<Form.Item shouldUpdate>
{() => {
return (
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_taxp")}
name={["cieca_pfl", "LAR", "lbr_taxp"]}
rules={[
{
required: form.getFieldValue(["cieca_pfl", "LAR", "lbr_tax_in"])
//message: t("general.validation.required"),
}
]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")} label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
name={["cieca_pfl", "LAR", "lbr_tx_in1"]} name={["cieca_pfl", "LAR", "lbr_tx_in1"]}
@@ -472,9 +325,6 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
</Form.Item> </Form.Item>
</LayoutFormRow> </LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.lbr_types.LAS")}> <LayoutFormRow header={t("joblines.fields.lbr_types.LAS")}>
<Form.Item label={t("jobs.fields.cieca_pfl.lbr_adjp")} name={["cieca_pfl", "LAS", "lbr_adjp"]}>
<InputNumber min={-100} max={100} precision={4} disabled={jobRO} />
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tax_in")} label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
name={["cieca_pfl", "LAS", "lbr_tax_in"]} name={["cieca_pfl", "LAS", "lbr_tax_in"]}
@@ -482,24 +332,6 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
> >
<Switch disabled={jobRO} /> <Switch disabled={jobRO} />
</Form.Item> </Form.Item>
<Form.Item shouldUpdate>
{() => {
return (
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_taxp")}
name={["cieca_pfl", "LAS", "lbr_taxp"]}
rules={[
{
required: form.getFieldValue(["cieca_pfl", "LAS", "lbr_tax_in"])
//message: t("general.validation.required"),
}
]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")} label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
name={["cieca_pfl", "LAS", "lbr_tx_in1"]} name={["cieca_pfl", "LAS", "lbr_tx_in1"]}
@@ -537,9 +369,6 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
</Form.Item> </Form.Item>
</LayoutFormRow> </LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.lbr_types.LAU")}> <LayoutFormRow header={t("joblines.fields.lbr_types.LAU")}>
<Form.Item label={t("jobs.fields.cieca_pfl.lbr_adjp")} name={["cieca_pfl", "LAU", "lbr_adjp"]}>
<InputNumber min={-100} max={100} precision={4} disabled={jobRO} />
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tax_in")} label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
name={["cieca_pfl", "LAU", "lbr_tax_in"]} name={["cieca_pfl", "LAU", "lbr_tax_in"]}
@@ -547,24 +376,6 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
> >
<Switch disabled={jobRO} /> <Switch disabled={jobRO} />
</Form.Item> </Form.Item>
<Form.Item shouldUpdate>
{() => {
return (
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_taxp")}
name={["cieca_pfl", "LAU", "lbr_taxp"]}
rules={[
{
required: form.getFieldValue(["cieca_pfl", "LAU", "lbr_tax_in"])
//message: t("general.validation.required"),
}
]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")} label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
name={["cieca_pfl", "LAU", "lbr_tx_in1"]} name={["cieca_pfl", "LAU", "lbr_tx_in1"]}

View File

@@ -23,9 +23,7 @@ export function JobsDetailRatesMaterials({ jobRO, expanded, required = true, for
<Form.Item label={t("jobs.fields.materials.cal_opcode")} name={["materials", "MAPA", "cal_opcode"]}> <Form.Item label={t("jobs.fields.materials.cal_opcode")} name={["materials", "MAPA", "cal_opcode"]}>
<Input disabled={jobRO} /> <Input disabled={jobRO} />
</Form.Item> </Form.Item>
<Form.Item label={t("jobs.fields.materials.mat_adjp")} name={["materials", "MAPA", "mat_adjp"]}>
<InputNumber min={-100} max={100} precision={4} disabled={jobRO} />
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.materials.tax_ind")} label={t("jobs.fields.materials.tax_ind")}
name={["materials", "MAPA", "tax_ind"]} name={["materials", "MAPA", "tax_ind"]}
@@ -33,24 +31,6 @@ export function JobsDetailRatesMaterials({ jobRO, expanded, required = true, for
> >
<Switch /> <Switch />
</Form.Item> </Form.Item>
<Form.Item shouldUpdate>
{() => {
return (
<Form.Item
label={t("jobs.fields.materials.mat_taxp")}
name={["materials", "MAPA", "mat_taxp"]}
rules={[
{
required: form.getFieldValue(["materials", "MAPA", "tax_ind"])
//message: t("general.validation.required"),
}
]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.materials.mat_tx_in1")} label={t("jobs.fields.materials.mat_tx_in1")}
name={["materials", "MAPA", "mat_tx_in1"]} name={["materials", "MAPA", "mat_tx_in1"]}
@@ -94,9 +74,7 @@ export function JobsDetailRatesMaterials({ jobRO, expanded, required = true, for
<Form.Item label={t("jobs.fields.materials.cal_opcode")} name={["materials", "MASH", "cal_opcode"]}> <Form.Item label={t("jobs.fields.materials.cal_opcode")} name={["materials", "MASH", "cal_opcode"]}>
<Input disabled={jobRO} /> <Input disabled={jobRO} />
</Form.Item> </Form.Item>
<Form.Item label={t("jobs.fields.materials.mat_adjp")} name={["materials", "MAPA", "mat_adjp"]}>
<InputNumber min={-100} max={100} precision={4} disabled={jobRO} />
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.materials.tax_ind")} label={t("jobs.fields.materials.tax_ind")}
name={["materials", "MASH", "tax_ind"]} name={["materials", "MASH", "tax_ind"]}
@@ -104,24 +82,6 @@ export function JobsDetailRatesMaterials({ jobRO, expanded, required = true, for
> >
<Switch /> <Switch />
</Form.Item> </Form.Item>
<Form.Item shouldUpdate>
{() => {
return (
<Form.Item
label={t("jobs.fields.materials.mat_taxp")}
name={["materials", "MASH", "mat_taxp"]}
rules={[
{
required: form.getFieldValue(["materials", "MASH", "tax_ind"])
//message: t("general.validation.required"),
}
]}
>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.materials.mat_tx_in1")} label={t("jobs.fields.materials.mat_tx_in1")}
name={["materials", "MASH", "mat_tx_in1"]} name={["materials", "MASH", "mat_tx_in1"]}

View File

@@ -4,7 +4,6 @@ import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { selectJobReadOnly } from "../../redux/application/application.selectors"; import { selectJobReadOnly } from "../../redux/application/application.selectors";
import InstanceRenderManager from "../../utils/instanceRenderMgr";
import LayoutFormRow from "../layout-form-row/layout-form-row.component"; import LayoutFormRow from "../layout-form-row/layout-form-row.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
@@ -989,24 +988,18 @@ export function JobsDetailRatesParts({ jobRO, expanded, required = true, form })
<Form.Item label={t("jobs.fields.tax_str_rt")} name="tax_str_rt"> <Form.Item label={t("jobs.fields.tax_str_rt")} name="tax_str_rt">
<InputNumber min={0} max={100} precision={4} disabled={jobRO} /> <InputNumber min={0} max={100} precision={4} disabled={jobRO} />
</Form.Item> </Form.Item>
{InstanceRenderManager({ imex: true, rome: false, promanager: "USE_ROME" }) ? ( <Form.Item label={t("jobs.fields.tax_paint_mat_rt")} name="tax_paint_mat_rt">
<> <InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<Form.Item label={t("jobs.fields.tax_paint_mat_rt")} name="tax_paint_mat_rt"> </Form.Item>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} /> <Form.Item label={t("jobs.fields.tax_shop_mat_rt")} name="tax_shop_mat_rt">
</Form.Item> <InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<Form.Item label={t("jobs.fields.tax_shop_mat_rt")} name="tax_shop_mat_rt"> </Form.Item>
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
</Form.Item>{" "}
</>
) : null}
<Form.Item label={t("jobs.fields.tax_sub_rt")} name="tax_sub_rt"> <Form.Item label={t("jobs.fields.tax_sub_rt")} name="tax_sub_rt">
<InputNumber min={0} max={100} precision={4} disabled={jobRO} /> <InputNumber min={0} max={100} precision={4} disabled={jobRO} />
</Form.Item> </Form.Item>
{InstanceRenderManager({ imex: true, rome: false, promanager: "USE_ROME" }) ? ( <Form.Item label={t("jobs.fields.tax_lbr_rt")} name="tax_lbr_rt">
<Form.Item label={t("jobs.fields.tax_lbr_rt")} name="tax_lbr_rt"> <InputNumber min={0} max={100} precision={4} disabled={jobRO} />
<InputNumber min={0} max={100} precision={4} disabled={jobRO} /> </Form.Item>
</Form.Item>
) : null}
<Form.Item label={t("jobs.fields.tax_levies_rt")} name="tax_levies_rt"> <Form.Item label={t("jobs.fields.tax_levies_rt")} name="tax_levies_rt">
<InputNumber min={0} max={100} precision={4} disabled={jobRO} /> <InputNumber min={0} max={100} precision={4} disabled={jobRO} />
</Form.Item> </Form.Item>

View File

@@ -1,411 +0,0 @@
import { DeleteFilled, EyeFilled } from "@ant-design/icons";
import { PageHeader } from "@ant-design/pro-layout";
import { useLazyQuery, useMutation } from "@apollo/client";
import { Button, Drawer, Grid, Popconfirm, Space, Table } from "antd";
import queryString from "query-string";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { FaTasks } from "react-icons/fa";
import { connect } from "react-redux";
import { useLocation } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import { logImEXEvent } from "../../firebase/firebase.utils";
import { QUERY_BILL_BY_PK } from "../../graphql/bills.queries";
import { DELETE_PARTS_ORDER } from "../../graphql/parts-orders.queries";
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 { DateFormatter } from "../../utils/DateFormatter";
import { TemplateList } from "../../utils/TemplateConstants";
import { alphaSort } from "../../utils/sorters";
import DataLabel from "../data-label/data-label.component";
import FeatureWrapperComponent from "../feature-wrapper/feature-wrapper.component";
import PartsOrderBackorderEta from "../parts-order-backorder-eta/parts-order-backorder-eta.component";
import PartsOrderCmReceived from "../parts-order-cm-received/parts-order-cm-received.component";
import PartsOrderDeleteLine from "../parts-order-delete-line/parts-order-delete-line.component";
import PartsOrderLineBackorderButton from "../parts-order-line-backorder-button/parts-order-line-backorder-button.component";
import PartsReceiveModalContainer from "../parts-receive-modal/parts-receive-modal.container";
import PrintWrapper from "../print-wrapper/print-wrapper.component";
const mapStateToProps = createStructuredSelector({
jobRO: selectJobReadOnly,
bodyshop: selectBodyshop
});
const mapDispatchToProps = (dispatch) => ({
setBillEnterContext: (context) =>
dispatch(
setModalContext({
context: context,
modal: "billEnter"
})
),
setPartsReceiveContext: (context) =>
dispatch(
setModalContext({
context: context,
modal: "partsReceive"
})
),
setTaskUpsertContext: (context) => dispatch(setModalContext({ context, modal: "taskUpsert" }))
});
export function PartsOrderListTableDrawerComponent({
setBillEnterContext,
bodyshop,
jobRO,
job,
billsQuery,
handleOnRowClick,
setPartsReceiveContext,
setTaskUpsertContext
}) {
const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
.filter((screen) => !!screen[1])
.slice(-1)[0];
const bpoints = {
xs: "100%",
sm: "100%",
md: "100%",
lg: "75%",
xl: "75%",
xxl: "65%"
};
const drawerPercentage = selectedBreakpoint ? bpoints[selectedBreakpoint[0]] : "100%";
const responsibilityCenters = bodyshop.md_responsibility_centers;
const Templates = TemplateList("partsorder", { job });
const { t } = useTranslation();
const [state, setState] = useState({
sortedInfo: {}
});
const [returnfrombill, setReturnFromBill] = useState();
const [billData, setBillData] = useState();
const search = queryString.parse(useLocation().search);
const selectedpartsorder = search.partsorderid;
const [billQuery] = useLazyQuery(QUERY_BILL_BY_PK);
const [deletePartsOrder] = useMutation(DELETE_PARTS_ORDER);
const parts_orders = billsQuery.data ? billsQuery.data.parts_orders : [];
const { refetch } = billsQuery;
useEffect(() => {
if (returnfrombill === null) {
setBillData(null);
} else {
const fetchData = async () => {
const result = await billQuery({
variables: { billid: returnfrombill }
});
setBillData(result.data);
};
fetchData();
}
}, [returnfrombill, billQuery]);
const recordActions = (record, showView = false) => (
<Space direction="horizontal" wrap>
{showView && (
<Button
onClick={() => {
if (record.returnfrombill) {
setReturnFromBill(record.returnfrombill);
} else {
setReturnFromBill(null);
}
handleOnRowClick(record);
}}
>
<EyeFilled />
</Button>
)}
<Button
disabled={jobRO || record.return || record.vendor.id === bodyshop.inhousevendorid}
onClick={() => {
logImEXEvent("parts_order_receive_bill");
setPartsReceiveContext({
actions: { refetch: refetch },
context: {
jobId: job.id,
job: job,
partsorderlines: record.parts_order_lines.map((pol) => {
return {
joblineid: pol.job_line_id,
id: pol.id,
line_desc: pol.line_desc,
quantity: pol.quantity,
act_price: pol.act_price,
oem_partno: pol.oem_partno
};
})
}
});
}}
>
{t("parts_orders.actions.receive")}
</Button>
<Button
title={t("tasks.buttons.create")}
onClick={() => {
setTaskUpsertContext({
context: {
jobid: job.id,
partsorderid: record.id
}
});
}}
>
<FaTasks />
</Button>
<Popconfirm
title={t("parts_orders.labels.confirmdelete")}
disabled={jobRO}
onConfirm={async () => {
//Delete the parts return.!
await deletePartsOrder({
variables: { partsOrderId: record.id },
update(cache) {
cache.modify({
fields: {
parts_orders(existingPartsOrders, { readField }) {
return existingPartsOrders.filter((billref) => record.id !== readField("id", billref));
}
}
});
}
});
}}
>
<Button disabled={jobRO}>
<DeleteFilled />
</Button>
</Popconfirm>
<FeatureWrapperComponent featureName="bills" noauth={() => null}>
<Button
disabled={(jobRO ? !record.return : jobRO) || record.vendor.id === bodyshop.inhousevendorid}
onClick={() => {
logImEXEvent("parts_order_receive_bill");
setBillEnterContext({
actions: { refetch: refetch },
context: {
job: job,
bill: {
vendorid: record.vendor.id,
is_credit_memo: record.return,
billlines: record.parts_order_lines.map((pol) => {
return {
joblineid: pol.job_line_id || "noline",
line_desc: pol.line_desc,
quantity: pol.quantity,
actual_price: pol.act_price,
cost_center: pol.jobline?.part_type
? bodyshop.pbs_serialnumber || bodyshop.cdk_dealerid
? pol.jobline.part_type !== "PAE"
? pol.jobline.part_type
: null
: responsibilityCenters.defaults &&
(responsibilityCenters.defaults.costs[pol.jobline.part_type] || null)
: null
};
})
}
}
});
}}
>
{t("parts_orders.actions.receivebill")}
</Button>
</FeatureWrapperComponent>
<PrintWrapper
templateObject={{
name: record.return ? Templates.parts_return_slip.key : Templates.parts_order.key,
variables: { id: record.id }
}}
messageObject={{
subject: record.return ? Templates.parts_return_slip.subject : Templates.parts_order.subject,
to: record.vendor.email
}}
id={job.id}
/>
</Space>
);
const handleTableChange = (pagination, filters, sorter) => {
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
};
const selectedPartsOrderRecord = parts_orders.find((r) => r.id === selectedpartsorder);
const rowExpander = (record) => {
const columns = [
{
title: t("parts_orders.fields.line_desc"),
dataIndex: "line_desc",
key: "line_desc",
sorter: (a, b) => alphaSort(a.line_desc, b.line_desc),
sortOrder: state.sortedInfo.columnKey === "line_desc" && state.sortedInfo.order
},
{
title: t("parts_orders.fields.quantity"),
dataIndex: "quantity",
key: "quantity",
sorter: (a, b) => a.quantity - b.quantity,
sortOrder: state.sortedInfo.columnKey === "quantity" && state.sortedInfo.order
},
{
title: t("parts_orders.fields.act_price"),
dataIndex: "act_price",
key: "act_price",
sorter: (a, b) => a.act_price - b.act_price,
sortOrder: state.sortedInfo.columnKey === "act_price" && state.sortedInfo.order,
render: (text, record) => <CurrencyFormatter>{record.act_price}</CurrencyFormatter>
},
...(selectedPartsOrderRecord && selectedPartsOrderRecord.return
? [
{
title: t("parts_orders.fields.cost"),
dataIndex: "cost",
key: "cost",
sorter: (a, b) => a.cost - b.cost,
sortOrder: state.sortedInfo.columnKey === "cost" && state.sortedInfo.order,
render: (text, record) => <CurrencyFormatter>{record.cost}</CurrencyFormatter>
}
]
: []),
{
title: t("parts_orders.fields.part_type"),
dataIndex: "part_type",
key: "part_type",
render: (text, record) => (record.part_type ? t(`joblines.fields.part_types.${record.part_type}`) : null)
},
{
title: t("parts_orders.fields.oem_partno"),
dataIndex: "oem_partno",
key: "oem_partno",
sorter: (a, b) => alphaSort(a.oem_partno, b.oem_partno),
sortOrder: state.sortedInfo.columnKey === "oem_partno" && state.sortedInfo.order
},
{
title: t("parts_orders.fields.line_remarks"),
dataIndex: "line_remarks",
key: "line_remarks"
},
{
title: t("parts_orders.fields.status"),
dataIndex: "status",
key: "status"
},
...(selectedPartsOrderRecord && selectedPartsOrderRecord.return
? [
{
title: t("parts_orders.fields.cm_received"),
dataIndex: "cm_received",
key: "cm_received",
render: (text, record) => (
<PartsOrderCmReceived
orderLineId={record.id}
checked={record.cm_received}
partsorderid={selectedPartsOrderRecord.id}
/>
)
}
]
: []),
{
title: t("parts_orders.fields.backordered_on"),
dataIndex: "backordered_on",
key: "backordered_on",
render: (text, record) => <DateFormatter>{text}</DateFormatter>
},
{
title: t("parts_orders.fields.backordered_eta"),
dataIndex: "backordered_eta",
key: "backordered_eta",
render: (text, record) => (
<PartsOrderBackorderEta
backordered_eta={record.backordered_eta}
disabled={jobRO}
partsOrderStatus={record.status}
partsLineId={record.id}
jobLineId={record.job_line_id}
/>
)
},
{
title: t("general.labels.actions"),
dataIndex: "actions",
key: "actions",
render: (text, record) => (
<Space wrap>
<PartsOrderDeleteLine
disabled={jobRO}
partsOrderStatus={record.status}
partsLineId={record.id}
partsOrderId={selectedpartsorder}
jobLineId={record.job_line_id}
/>
<PartsOrderLineBackorderButton
disabled={jobRO}
partsOrderStatus={record.status}
partsLineId={record.id}
jobLineId={record.job_line_id}
/>
</Space>
)
}
];
return (
<div>
<PageHeader
title={
billData
? `${record.vendor.name} - ${record.order_number} - ${t("bills.labels.returnfrombill")}: ${billData.bills_by_pk.invoice_number}`
: `${record.vendor.name} - ${record.order_number}`
}
extra={recordActions(record)}
/>
<Table
scroll={{
x: true //y: "50rem"
}}
columns={columns}
rowKey="id"
dataSource={record.parts_order_lines}
onChange={handleTableChange}
/>
<DataLabel label={t("parts_orders.fields.comments")}>
<div style={{ whiteSpace: "pre" }}>{record.comments}</div>
</DataLabel>
</div>
);
};
return (
<div>
<PartsReceiveModalContainer />
<Drawer
placement="right"
onClose={() => handleOnRowClick(null)}
open={selectedpartsorder}
closable
width={drawerPercentage}
>
{selectedPartsOrderRecord && rowExpander(selectedPartsOrderRecord)}
</Drawer>
</div>
);
}
export default connect(mapStateToProps, mapDispatchToProps)(PartsOrderListTableDrawerComponent);

View File

@@ -1,23 +1,33 @@
import { DeleteFilled, EyeFilled, SyncOutlined } from "@ant-design/icons"; import { DeleteFilled, EyeFilled, SyncOutlined } from "@ant-design/icons";
import { useMutation } from "@apollo/client"; import { useLazyQuery, useMutation } from "@apollo/client";
import { Button, Card, Checkbox, Input, Popconfirm, Space, Table } from "antd"; import { Button, Card, Checkbox, Drawer, Grid, Input, Popconfirm, Space, Table } from "antd";
import React, { useState } from "react"; import { PageHeader } from "@ant-design/pro-layout";
import queryString from "query-string";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { FaTasks } from "react-icons/fa";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { useLocation } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { logImEXEvent } from "../../firebase/firebase.utils"; import { logImEXEvent } from "../../firebase/firebase.utils";
import { QUERY_BILL_BY_PK } from "../../graphql/bills.queries";
import { DELETE_PARTS_ORDER } from "../../graphql/parts-orders.queries"; import { DELETE_PARTS_ORDER } from "../../graphql/parts-orders.queries";
import { selectJobReadOnly } from "../../redux/application/application.selectors"; import { selectJobReadOnly } from "../../redux/application/application.selectors";
import { setModalContext } from "../../redux/modals/modals.actions"; import { setModalContext } from "../../redux/modals/modals.actions";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { DateFormatter } from "../../utils/DateFormatter"; import { DateFormatter } from "../../utils/DateFormatter";
import { TemplateList } from "../../utils/TemplateConstants"; import { TemplateList } from "../../utils/TemplateConstants";
import { alphaSort } from "../../utils/sorters"; import { alphaSort } from "../../utils/sorters";
import FeatureWrapperComponent from "../feature-wrapper/feature-wrapper.component"; import DataLabel from "../data-label/data-label.component";
import PartsOrderBackorderEta from "../parts-order-backorder-eta/parts-order-backorder-eta.component";
import PartsOrderCmReceived from "../parts-order-cm-received/parts-order-cm-received.component";
import PartsOrderDeleteLine from "../parts-order-delete-line/parts-order-delete-line.component";
import PartsOrderLineBackorderButton from "../parts-order-line-backorder-button/parts-order-line-backorder-button.component";
import PartsReceiveModalContainer from "../parts-receive-modal/parts-receive-modal.container"; import PartsReceiveModalContainer from "../parts-receive-modal/parts-receive-modal.container";
import PrintWrapper from "../print-wrapper/print-wrapper.component"; import PrintWrapper from "../print-wrapper/print-wrapper.component";
import PartsOrderDrawer from "./parts-order-list-table-drawer.component"; import FeatureWrapperComponent from "../feature-wrapper/feature-wrapper.component";
import { FaTasks } from "react-icons/fa";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
jobRO: selectJobReadOnly, jobRO: selectJobReadOnly,
@@ -52,6 +62,19 @@ export function PartsOrderListTableComponent({
setPartsReceiveContext, setPartsReceiveContext,
setTaskUpsertContext setTaskUpsertContext
}) { }) {
const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
.filter((screen) => !!screen[1])
.slice(-1)[0];
const bpoints = {
xs: "100%",
sm: "100%",
md: "100%",
lg: "75%",
xl: "75%",
xxl: "65%"
};
const drawerPercentage = selectedBreakpoint ? bpoints[selectedBreakpoint[0]] : "100%";
const responsibilityCenters = bodyshop.md_responsibility_centers; const responsibilityCenters = bodyshop.md_responsibility_centers;
const Templates = TemplateList("partsorder", { job }); const Templates = TemplateList("partsorder", { job });
@@ -60,17 +83,42 @@ export function PartsOrderListTableComponent({
sortedInfo: {} sortedInfo: {}
}); });
const [returnfrombill, setReturnFromBill] = useState();
const [billData, setBillData] = useState();
const search = queryString.parse(useLocation().search);
const selectedpartsorder = search.partsorderid;
const [searchText, setSearchText] = useState(""); const [searchText, setSearchText] = useState("");
const [billQuery] = useLazyQuery(QUERY_BILL_BY_PK);
const [deletePartsOrder] = useMutation(DELETE_PARTS_ORDER); const [deletePartsOrder] = useMutation(DELETE_PARTS_ORDER);
const parts_orders = billsQuery.data ? billsQuery.data.parts_orders : []; const parts_orders = billsQuery.data ? billsQuery.data.parts_orders : [];
const { refetch } = billsQuery; const { refetch } = billsQuery;
useEffect(() => {
if (returnfrombill === null) {
setBillData(null);
} else {
const fetchData = async () => {
const result = await billQuery({
variables: { billid: returnfrombill }
});
setBillData(result.data);
};
fetchData();
}
}, [returnfrombill, billQuery]);
const recordActions = (record, showView = false) => ( const recordActions = (record, showView = false) => (
<Space direction="horizontal" wrap> <Space direction="horizontal" wrap>
{showView && ( {showView && (
<Button <Button
onClick={() => { onClick={() => {
if (record.returnfrombill) {
setReturnFromBill(record.returnfrombill);
} else {
setReturnFromBill(null);
}
handleOnRowClick(record); handleOnRowClick(record);
}} }}
> >
@@ -250,6 +298,154 @@ export function PartsOrderListTableComponent({
setState({ ...state, filteredInfo: filters, sortedInfo: sorter }); setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
}; };
const selectedPartsOrderRecord = parts_orders.find((r) => r.id === selectedpartsorder);
const rowExpander = (record) => {
const columns = [
{
title: t("parts_orders.fields.line_desc"),
dataIndex: "line_desc",
key: "line_desc",
sorter: (a, b) => alphaSort(a.line_desc, b.line_desc),
sortOrder: state.sortedInfo.columnKey === "line_desc" && state.sortedInfo.order
},
{
title: t("parts_orders.fields.quantity"),
dataIndex: "quantity",
key: "quantity",
sorter: (a, b) => a.quantity - b.quantity,
sortOrder: state.sortedInfo.columnKey === "quantity" && state.sortedInfo.order
},
{
title: t("parts_orders.fields.act_price"),
dataIndex: "act_price",
key: "act_price",
sorter: (a, b) => a.act_price - b.act_price,
sortOrder: state.sortedInfo.columnKey === "act_price" && state.sortedInfo.order,
render: (text, record) => <CurrencyFormatter>{record.act_price}</CurrencyFormatter>
},
...(selectedPartsOrderRecord && selectedPartsOrderRecord.return
? [
{
title: t("parts_orders.fields.cost"),
dataIndex: "cost",
key: "cost",
sorter: (a, b) => a.cost - b.cost,
sortOrder: state.sortedInfo.columnKey === "cost" && state.sortedInfo.order,
render: (text, record) => <CurrencyFormatter>{record.cost}</CurrencyFormatter>
}
]
: []),
{
title: t("parts_orders.fields.part_type"),
dataIndex: "part_type",
key: "part_type",
render: (text, record) => (record.part_type ? t(`joblines.fields.part_types.${record.part_type}`) : null)
},
{
title: t("parts_orders.fields.oem_partno"),
dataIndex: "oem_partno",
key: "oem_partno",
sorter: (a, b) => alphaSort(a.oem_partno, b.oem_partno),
sortOrder: state.sortedInfo.columnKey === "oem_partno" && state.sortedInfo.order
},
{
title: t("parts_orders.fields.line_remarks"),
dataIndex: "line_remarks",
key: "line_remarks"
},
{
title: t("parts_orders.fields.status"),
dataIndex: "status",
key: "status"
},
...(selectedPartsOrderRecord && selectedPartsOrderRecord.return
? [
{
title: t("parts_orders.fields.cm_received"),
dataIndex: "cm_received",
key: "cm_received",
render: (text, record) => (
<PartsOrderCmReceived
orderLineId={record.id}
checked={record.cm_received}
partsorderid={selectedPartsOrderRecord.id}
/>
)
}
]
: []),
{
title: t("parts_orders.fields.backordered_on"),
dataIndex: "backordered_on",
key: "backordered_on",
render: (text, record) => <DateFormatter>{text}</DateFormatter>
},
{
title: t("parts_orders.fields.backordered_eta"),
dataIndex: "backordered_eta",
key: "backordered_eta",
render: (text, record) => (
<PartsOrderBackorderEta
backordered_eta={record.backordered_eta}
disabled={jobRO}
partsOrderStatus={record.status}
partsLineId={record.id}
jobLineId={record.job_line_id}
/>
)
},
{
title: t("general.labels.actions"),
dataIndex: "actions",
key: "actions",
render: (text, record) => (
<Space wrap>
<PartsOrderDeleteLine
disabled={jobRO}
partsOrderStatus={record.status}
partsLineId={record.id}
partsOrderId={selectedpartsorder}
jobLineId={record.job_line_id}
/>
<PartsOrderLineBackorderButton
disabled={jobRO}
partsOrderStatus={record.status}
partsLineId={record.id}
jobLineId={record.job_line_id}
/>
</Space>
)
}
];
return (
<div>
<PageHeader
title={
billData
? `${record.vendor.name} - ${record.order_number} - ${t("bills.labels.returnfrombill")}: ${billData.bills_by_pk.invoice_number}`
: `${record.vendor.name} - ${record.order_number}`
}
extra={recordActions(record)}
/>
<Table
scroll={{
x: true //y: "50rem"
}}
columns={columns}
rowKey="id"
dataSource={record.parts_order_lines}
/>
<DataLabel label={t("parts_orders.fields.comments")}>
<div style={{ whiteSpace: "pre" }}>{record.comments}</div>
</DataLabel>
</div>
);
};
const filteredPartsOrders = parts_orders const filteredPartsOrders = parts_orders
? searchText === "" ? searchText === ""
? parts_orders ? parts_orders
@@ -280,13 +476,15 @@ export function PartsOrderListTableComponent({
} }
> >
<PartsReceiveModalContainer /> <PartsReceiveModalContainer />
<PartsOrderDrawer <Drawer
job={job} placement="right"
billsQuery={billsQuery} onClose={() => handleOnRowClick(null)}
handleOnRowClick={handleOnRowClick} open={selectedpartsorder}
setPartsReceiveContext={setPartsReceiveContext} closable
setTaskUpsertContext={setTaskUpsertContext} width={drawerPercentage}
/> >
{selectedPartsOrderRecord && rowExpander(selectedPartsOrderRecord)}
</Drawer>
<Table <Table
loading={billsQuery.loading} loading={billsQuery.loading}
scroll={{ scroll={{

View File

@@ -1,11 +1,11 @@
import { useMutation } from "@apollo/client"; import { useMutation } from "@apollo/client";
import { Button, Card, Dropdown, Space, TimePicker } from "antd"; import { Button, Card, Dropdown, TimePicker } from "antd";
import dayjs from "../../utils/day";
import React, { useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { logImEXEvent } from "../../firebase/firebase.utils"; import { logImEXEvent } from "../../firebase/firebase.utils";
import { UPDATE_JOB } from "../../graphql/jobs.queries"; import { UPDATE_JOB } from "../../graphql/jobs.queries";
import { DateFormatter } from "../../utils/DateFormatter"; import { DateFormatter } from "../../utils/DateFormatter";
import dayjs from "../../utils/day";
import FormDatePicker from "../form-date-picker/form-date-picker.component"; import FormDatePicker from "../form-date-picker/form-date-picker.component";
export default function ProductionListDate({ record, field, time, pastIndicator }) { export default function ProductionListDate({ record, field, time, pastIndicator }) {
@@ -56,25 +56,23 @@ export default function ProductionListDate({ record, field, time, pastIndicator
key: "overlayItem1", key: "overlayItem1",
label: ( label: (
<Card style={{ padding: "1rem" }} onClick={(e) => e.stopPropagation()}> <Card style={{ padding: "1rem" }} onClick={(e) => e.stopPropagation()}>
<Space direction={"vertical"}> <FormDatePicker
<FormDatePicker onClick={(e) => e.stopPropagation()}
value={(record[field] && dayjs(record[field])) || null}
onChange={handleChange}
format="MM/DD/YYYY"
isDateOnly={!time}
/>
{time && (
<TimePicker
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
value={(record[field] && dayjs(record[field])) || null} value={(record[field] && dayjs(record[field])) || null}
onChange={handleChange} onChange={handleChange}
format="MM/DD/YYYY" minuteStep={15}
isDateOnly={!time} format="hh:mm a"
/> />
{time && ( )}
<TimePicker <Button onClick={() => setOpen(false)}>{t("general.actions.close")}</Button>
onClick={(e) => e.stopPropagation()}
value={(record[field] && dayjs(record[field])) || null}
onChange={handleChange}
minuteStep={15}
format="hh:mm a"
/>
)}
<Button onClick={() => setOpen(false)}>{t("general.actions.close")}</Button>
</Space>
</Card> </Card>
) )
} }

View File

@@ -63,7 +63,7 @@ export default function ShopEmployeesListComponent({ loading, employees }) {
value: false value: false
} }
], ],
onFilter: (value, record) => value === record.flat_rate, onFilter: (value, record) => value === record.flate_rate,
render: (text, record) => render: (text, record) =>
record.flat_rate ? t("employees.labels.flat_rate") : t("employees.labels.straight_time") record.flat_rate ? t("employees.labels.flat_rate") : t("employees.labels.straight_time")
}, },

View File

@@ -319,18 +319,6 @@ export default function ShopInfoIntakeChecklistComponent({ form }) {
))} ))}
</Select> </Select>
</Form.Item> </Form.Item>
<Form.Item
name={["deliverchecklist", "actual_delivery"]}
label={t("bodyshop.fields.deliver.require_actual_delivery_date")}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
>
<Switch />
</Form.Item>
</SelectorDiv> </SelectorDiv>
</div> </div>
); );

View File

@@ -4,7 +4,6 @@ import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import InstanceRenderManager from "../../utils/instanceRenderMgr";
import LayoutFormRow from "../layout-form-row/layout-form-row.component"; import LayoutFormRow from "../layout-form-row/layout-form-row.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
@@ -52,12 +51,6 @@ export function ShopInfoResponsibilityCenters({ bodyshop, form }) {
<Collapse> <Collapse>
<Collapse.Panel forceRender header={t("jobs.labels.cieca_pfl")} key="cieca_pfl"> <Collapse.Panel forceRender header={t("jobs.labels.cieca_pfl")} key="cieca_pfl">
<LayoutFormRow header={t("joblines.fields.lbr_types.LAB")}> <LayoutFormRow header={t("joblines.fields.lbr_types.LAB")}>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_adjp")}
name={["md_responsibility_centers", "cieca_pfl", "LAB", "lbr_adjp"]}
>
<InputNumber min={-100} max={100} precision={4} />
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tax_in")} label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
name={["md_responsibility_centers", "cieca_pfl", "LAB", "lbr_tax_in"]} name={["md_responsibility_centers", "cieca_pfl", "LAB", "lbr_tax_in"]}
@@ -65,24 +58,6 @@ export function ShopInfoResponsibilityCenters({ bodyshop, form }) {
> >
<Switch /> <Switch />
</Form.Item> </Form.Item>
<Form.Item shouldUpdate>
{() => {
return (
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_taxp")}
name={["md_responsibility_centers", "cieca_pfl", "LAB", "lbr_taxp"]}
rules={[
{
required: form.getFieldValue(["md_responsibility_centers", "cieca_pfl", "LAB", "lbr_tax_in"])
//message: t("general.validation.required"),
}
]}
>
<InputNumber min={0} max={100} precision={4} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")} label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
name={["md_responsibility_centers", "cieca_pfl", "LAB", "lbr_tx_in1"]} name={["md_responsibility_centers", "cieca_pfl", "LAB", "lbr_tx_in1"]}
@@ -120,12 +95,6 @@ export function ShopInfoResponsibilityCenters({ bodyshop, form }) {
</Form.Item> </Form.Item>
</LayoutFormRow> </LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.lbr_types.LAD")}> <LayoutFormRow header={t("joblines.fields.lbr_types.LAD")}>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_adjp")}
name={["md_responsibility_centers", "cieca_pfl", "LAD", "lbr_adjp"]}
>
<InputNumber min={-100} max={100} precision={4} />
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tax_in")} label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
name={["md_responsibility_centers", "cieca_pfl", "LAD", "lbr_tax_in"]} name={["md_responsibility_centers", "cieca_pfl", "LAD", "lbr_tax_in"]}
@@ -133,24 +102,6 @@ export function ShopInfoResponsibilityCenters({ bodyshop, form }) {
> >
<Switch /> <Switch />
</Form.Item> </Form.Item>
<Form.Item shouldUpdate>
{() => {
return (
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_taxp")}
name={["md_responsibility_centers", "cieca_pfl", "LAD", "lbr_taxp"]}
rules={[
{
required: form.getFieldValue(["md_responsibility_centers", "cieca_pfl", "LAD", "lbr_tax_in"])
//message: t("general.validation.required"),
}
]}
>
<InputNumber min={0} max={100} precision={4} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")} label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
name={["md_responsibility_centers", "cieca_pfl", "LAD", "lbr_tx_in1"]} name={["md_responsibility_centers", "cieca_pfl", "LAD", "lbr_tx_in1"]}
@@ -188,12 +139,6 @@ export function ShopInfoResponsibilityCenters({ bodyshop, form }) {
</Form.Item> </Form.Item>
</LayoutFormRow> </LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.lbr_types.LAE")}> <LayoutFormRow header={t("joblines.fields.lbr_types.LAE")}>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_adjp")}
name={["md_responsibility_centers", "cieca_pfl", "LAE", "lbr_adjp"]}
>
<InputNumber min={-100} max={100} precision={4} />
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tax_in")} label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
name={["md_responsibility_centers", "cieca_pfl", "LAE", "lbr_tax_in"]} name={["md_responsibility_centers", "cieca_pfl", "LAE", "lbr_tax_in"]}
@@ -201,24 +146,6 @@ export function ShopInfoResponsibilityCenters({ bodyshop, form }) {
> >
<Switch /> <Switch />
</Form.Item> </Form.Item>
<Form.Item shouldUpdate>
{() => {
return (
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_taxp")}
name={["md_responsibility_centers", "cieca_pfl", "LAE", "lbr_taxp"]}
rules={[
{
required: form.getFieldValue(["md_responsibility_centers", "cieca_pfl", "LAE", "lbr_tax_in"])
//message: t("general.validation.required"),
}
]}
>
<InputNumber min={0} max={100} precision={4} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")} label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
name={["md_responsibility_centers", "cieca_pfl", "LAE", "lbr_tx_in1"]} name={["md_responsibility_centers", "cieca_pfl", "LAE", "lbr_tx_in1"]}
@@ -256,12 +183,6 @@ export function ShopInfoResponsibilityCenters({ bodyshop, form }) {
</Form.Item> </Form.Item>
</LayoutFormRow> </LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.lbr_types.LAF")}> <LayoutFormRow header={t("joblines.fields.lbr_types.LAF")}>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_adjp")}
name={["md_responsibility_centers", "cieca_pfl", "LAF", "lbr_adjp"]}
>
<InputNumber min={-100} max={100} precision={4} />
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tax_in")} label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
name={["md_responsibility_centers", "cieca_pfl", "LAF", "lbr_tax_in"]} name={["md_responsibility_centers", "cieca_pfl", "LAF", "lbr_tax_in"]}
@@ -269,24 +190,6 @@ export function ShopInfoResponsibilityCenters({ bodyshop, form }) {
> >
<Switch /> <Switch />
</Form.Item> </Form.Item>
<Form.Item shouldUpdate>
{() => {
return (
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_taxp")}
name={["md_responsibility_centers", "cieca_pfl", "LAF", "lbr_taxp"]}
rules={[
{
required: form.getFieldValue(["md_responsibility_centers", "cieca_pfl", "LAF", "lbr_tax_in"])
//message: t("general.validation.required"),
}
]}
>
<InputNumber min={0} max={100} precision={4} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")} label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
name={["md_responsibility_centers", "cieca_pfl", "LAF", "lbr_tx_in1"]} name={["md_responsibility_centers", "cieca_pfl", "LAF", "lbr_tx_in1"]}
@@ -324,12 +227,6 @@ export function ShopInfoResponsibilityCenters({ bodyshop, form }) {
</Form.Item> </Form.Item>
</LayoutFormRow> </LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.lbr_types.LAG")}> <LayoutFormRow header={t("joblines.fields.lbr_types.LAG")}>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_adjp")}
name={["md_responsibility_centers", "cieca_pfl", "LAG", "lbr_adjp"]}
>
<InputNumber min={-100} max={100} precision={4} />
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tax_in")} label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
name={["md_responsibility_centers", "cieca_pfl", "LAG", "lbr_tax_in"]} name={["md_responsibility_centers", "cieca_pfl", "LAG", "lbr_tax_in"]}
@@ -337,24 +234,6 @@ export function ShopInfoResponsibilityCenters({ bodyshop, form }) {
> >
<Switch /> <Switch />
</Form.Item> </Form.Item>
<Form.Item shouldUpdate>
{() => {
return (
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_taxp")}
name={["md_responsibility_centers", "cieca_pfl", "LAG", "lbr_taxp"]}
rules={[
{
required: form.getFieldValue(["md_responsibility_centers", "cieca_pfl", "LAG", "lbr_tax_in"])
//message: t("general.validation.required"),
}
]}
>
<InputNumber min={0} max={100} precision={4} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")} label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
name={["md_responsibility_centers", "cieca_pfl", "LAG", "lbr_tx_in1"]} name={["md_responsibility_centers", "cieca_pfl", "LAG", "lbr_tx_in1"]}
@@ -392,12 +271,6 @@ export function ShopInfoResponsibilityCenters({ bodyshop, form }) {
</Form.Item> </Form.Item>
</LayoutFormRow> </LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.lbr_types.LAM")}> <LayoutFormRow header={t("joblines.fields.lbr_types.LAM")}>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_adjp")}
name={["md_responsibility_centers", "cieca_pfl", "LAM", "lbr_adjp"]}
>
<InputNumber min={-100} max={100} precision={4} />
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tax_in")} label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
name={["md_responsibility_centers", "cieca_pfl", "LAM", "lbr_tax_in"]} name={["md_responsibility_centers", "cieca_pfl", "LAM", "lbr_tax_in"]}
@@ -405,24 +278,6 @@ export function ShopInfoResponsibilityCenters({ bodyshop, form }) {
> >
<Switch /> <Switch />
</Form.Item> </Form.Item>
<Form.Item shouldUpdate>
{() => {
return (
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_taxp")}
name={["md_responsibility_centers", "cieca_pfl", "LAM", "lbr_taxp"]}
rules={[
{
required: form.getFieldValue(["md_responsibility_centers", "cieca_pfl", "LAM", "lbr_tax_in"])
//message: t("general.validation.required"),
}
]}
>
<InputNumber min={0} max={100} precision={4} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")} label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
name={["md_responsibility_centers", "cieca_pfl", "LAM", "lbr_tx_in1"]} name={["md_responsibility_centers", "cieca_pfl", "LAM", "lbr_tx_in1"]}
@@ -460,12 +315,6 @@ export function ShopInfoResponsibilityCenters({ bodyshop, form }) {
</Form.Item> </Form.Item>
</LayoutFormRow> </LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.lbr_types.LAR")}> <LayoutFormRow header={t("joblines.fields.lbr_types.LAR")}>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_adjp")}
name={["md_responsibility_centers", "cieca_pfl", "LAR", "lbr_adjp"]}
>
<InputNumber min={-100} max={100} precision={4} />
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tax_in")} label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
name={["md_responsibility_centers", "cieca_pfl", "LAR", "lbr_tax_in"]} name={["md_responsibility_centers", "cieca_pfl", "LAR", "lbr_tax_in"]}
@@ -473,24 +322,6 @@ export function ShopInfoResponsibilityCenters({ bodyshop, form }) {
> >
<Switch /> <Switch />
</Form.Item> </Form.Item>
<Form.Item shouldUpdate>
{() => {
return (
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_taxp")}
name={["md_responsibility_centers", "cieca_pfl", "LAR", "lbr_taxp"]}
rules={[
{
required: form.getFieldValue(["md_responsibility_centers", "cieca_pfl", "LAR", "lbr_tax_in"])
//message: t("general.validation.required"),
}
]}
>
<InputNumber min={0} max={100} precision={4} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")} label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
name={["md_responsibility_centers", "cieca_pfl", "LAR", "lbr_tx_in1"]} name={["md_responsibility_centers", "cieca_pfl", "LAR", "lbr_tx_in1"]}
@@ -528,12 +359,6 @@ export function ShopInfoResponsibilityCenters({ bodyshop, form }) {
</Form.Item> </Form.Item>
</LayoutFormRow> </LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.lbr_types.LAS")}> <LayoutFormRow header={t("joblines.fields.lbr_types.LAS")}>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_adjp")}
name={["md_responsibility_centers", "cieca_pfl", "LAS", "lbr_adjp"]}
>
<InputNumber min={-100} max={100} precision={4} />
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tax_in")} label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
name={["md_responsibility_centers", "cieca_pfl", "LAS", "lbr_tax_in"]} name={["md_responsibility_centers", "cieca_pfl", "LAS", "lbr_tax_in"]}
@@ -541,24 +366,6 @@ export function ShopInfoResponsibilityCenters({ bodyshop, form }) {
> >
<Switch /> <Switch />
</Form.Item> </Form.Item>
<Form.Item shouldUpdate>
{() => {
return (
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_taxp")}
name={["md_responsibility_centers", "cieca_pfl", "LAS", "lbr_taxp"]}
rules={[
{
required: form.getFieldValue(["md_responsibility_centers", "cieca_pfl", "LAS", "lbr_tax_in"])
//message: t("general.validation.required"),
}
]}
>
<InputNumber min={0} max={100} precision={4} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")} label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
name={["md_responsibility_centers", "cieca_pfl", "LAS", "lbr_tx_in1"]} name={["md_responsibility_centers", "cieca_pfl", "LAS", "lbr_tx_in1"]}
@@ -596,12 +403,6 @@ export function ShopInfoResponsibilityCenters({ bodyshop, form }) {
</Form.Item> </Form.Item>
</LayoutFormRow> </LayoutFormRow>
<LayoutFormRow header={t("joblines.fields.lbr_types.LAU")}> <LayoutFormRow header={t("joblines.fields.lbr_types.LAU")}>
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_adjp")}
name={["md_responsibility_centers", "cieca_pfl", "LAU", "lbr_adjp"]}
>
<InputNumber min={-100} max={100} precision={4} />
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tax_in")} label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
name={["md_responsibility_centers", "cieca_pfl", "LAU", "lbr_tax_in"]} name={["md_responsibility_centers", "cieca_pfl", "LAU", "lbr_tax_in"]}
@@ -609,24 +410,6 @@ export function ShopInfoResponsibilityCenters({ bodyshop, form }) {
> >
<Switch /> <Switch />
</Form.Item> </Form.Item>
<Form.Item shouldUpdate>
{() => {
return (
<Form.Item
label={t("jobs.fields.cieca_pfl.lbr_taxp")}
name={["md_responsibility_centers", "cieca_pfl", "LAU", "lbr_taxp"]}
rules={[
{
required: form.getFieldValue(["md_responsibility_centers", "cieca_pfl", "LAU", "lbr_tax_in"])
//message: t("general.validation.required"),
}
]}
>
<InputNumber min={0} max={100} precision={2} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")} label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
name={["md_responsibility_centers", "cieca_pfl", "LAU", "lbr_tx_in1"]} name={["md_responsibility_centers", "cieca_pfl", "LAU", "lbr_tx_in1"]}
@@ -679,12 +462,7 @@ export function ShopInfoResponsibilityCenters({ bodyshop, form }) {
> >
<Input /> <Input />
</Form.Item> </Form.Item>
<Form.Item
label={t("jobs.fields.materials.mat_adjp")}
name={["md_responsibility_centers", "cieca_pfm", "MAPA", "mat_adjp"]}
>
<InputNumber min={-100} max={100} precision={4} />
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.materials.tax_ind")} label={t("jobs.fields.materials.tax_ind")}
name={["md_responsibility_centers", "cieca_pfm", "MAPA", "tax_ind"]} name={["md_responsibility_centers", "cieca_pfm", "MAPA", "tax_ind"]}
@@ -692,24 +470,6 @@ export function ShopInfoResponsibilityCenters({ bodyshop, form }) {
> >
<Switch /> <Switch />
</Form.Item> </Form.Item>
<Form.Item shouldUpdate>
{() => {
return (
<Form.Item
label={t("jobs.fields.materials.mat_taxp")}
name={["md_responsibility_centers", "cieca_pfm", "MAPA", "mat_taxp"]}
rules={[
{
required: form.getFieldValue(["md_responsibility_centers", "cieca_pfm", "MAPA", "tax_ind"])
//message: t("general.validation.required"),
}
]}
>
<InputNumber min={0} max={100} precision={4} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.materials.mat_tx_in1")} label={t("jobs.fields.materials.mat_tx_in1")}
name={["md_responsibility_centers", "cieca_pfm", "MAPA", "mat_tx_in1"]} name={["md_responsibility_centers", "cieca_pfm", "MAPA", "mat_tx_in1"]}
@@ -759,12 +519,7 @@ export function ShopInfoResponsibilityCenters({ bodyshop, form }) {
> >
<Input /> <Input />
</Form.Item> </Form.Item>
<Form.Item
label={t("jobs.fields.materials.mat_adjp")}
name={["md_responsibility_centers", "cieca_pfm", "MASH", "mat_adjp"]}
>
<InputNumber min={-100} max={100} precision={4} />
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.materials.tax_ind")} label={t("jobs.fields.materials.tax_ind")}
name={["md_responsibility_centers", "cieca_pfm", "MASH", "tax_ind"]} name={["md_responsibility_centers", "cieca_pfm", "MASH", "tax_ind"]}
@@ -772,24 +527,6 @@ export function ShopInfoResponsibilityCenters({ bodyshop, form }) {
> >
<Switch /> <Switch />
</Form.Item> </Form.Item>
<Form.Item shouldUpdate>
{() => {
return (
<Form.Item
label={t("jobs.fields.materials.mat_taxp")}
name={["md_responsibility_centers", "cieca_pfm", "MASH", "mat_taxp"]}
rules={[
{
required: form.getFieldValue(["md_responsibility_centers", "cieca_pfm", "MASH", "tax_ind"])
//message: t("general.validation.required"),
}
]}
>
<InputNumber min={0} max={100} precision={4} />
</Form.Item>
);
}}
</Form.Item>
<Form.Item <Form.Item
label={t("jobs.fields.materials.mat_tx_in1")} label={t("jobs.fields.materials.mat_tx_in1")}
name={["md_responsibility_centers", "cieca_pfm", "MASH", "mat_tx_in1"]} name={["md_responsibility_centers", "cieca_pfm", "MASH", "mat_tx_in1"]}
@@ -2028,37 +1765,25 @@ export function ShopInfoResponsibilityCenters({ bodyshop, form }) {
</Form.Item> </Form.Item>
</LayoutFormRow> </LayoutFormRow>
<LayoutFormRow> <LayoutFormRow>
<Form.Item label={t("jobs.fields.tax_tow_rt")} name={["md_responsibility_centers", "tax_tow_rt"]}> <Form.Item label={t("jobs.fields.tax_tow_rt")} name="tax_tow_rt">
<InputNumber min={0} max={100} precision={4} /> <InputNumber min={0} max={100} precision={4} />
</Form.Item> </Form.Item>
<Form.Item label={t("jobs.fields.tax_str_rt")} name={["md_responsibility_centers", "tax_str_rt"]}> <Form.Item label={t("jobs.fields.tax_str_rt")} name="tax_str_rt">
<InputNumber min={0} max={100} precision={4} /> <InputNumber min={0} max={100} precision={4} />
</Form.Item> </Form.Item>
{InstanceRenderManager({ imex: true, rome: false, promanager: "USE_ROME" }) ? ( <Form.Item label={t("jobs.fields.tax_paint_mat_rt")} name="tax_paint_mat_rt">
<>
<Form.Item
label={t("jobs.fields.tax_paint_mat_rt")}
name={["md_responsibility_centers", "tax_paint_mat_rt"]}
>
<InputNumber min={0} max={100} precision={4} />
</Form.Item>
<Form.Item
label={t("jobs.fields.tax_shop_mat_rt")}
name={["md_responsibility_centers", "tax_shop_mat_rt"]}
>
<InputNumber min={0} max={100} precision={4} />
</Form.Item>
</>
) : null}
<Form.Item label={t("jobs.fields.tax_sub_rt")} name={["md_responsibility_centers", "tax_sub_rt"]}>
<InputNumber min={0} max={100} precision={4} /> <InputNumber min={0} max={100} precision={4} />
</Form.Item> </Form.Item>
{InstanceRenderManager({ imex: true, rome: false, promanager: "USE_ROME" }) ? ( <Form.Item label={t("jobs.fields.tax_shop_mat_rt")} name="tax_shop_mat_rt">
<Form.Item label={t("jobs.fields.tax_lbr_rt")} name={["md_responsibility_centers", "tax_lbr_rt"]}> <InputNumber min={0} max={100} precision={4} />
<InputNumber min={0} max={100} precision={4} /> </Form.Item>
</Form.Item> <Form.Item label={t("jobs.fields.tax_sub_rt")} name="tax_sub_rt">
) : null} <InputNumber min={0} max={100} precision={4} />
<Form.Item label={t("jobs.fields.tax_levies_rt")} name={["md_responsibility_centers", "tax_levies_rt"]}> </Form.Item>
<Form.Item label={t("jobs.fields.tax_lbr_rt")} name="tax_lbr_rt">
<InputNumber min={0} max={100} precision={4} />
</Form.Item>
<Form.Item label={t("jobs.fields.tax_levies_rt")} name="tax_levies_rt">
<InputNumber min={0} max={100} precision={4} /> <InputNumber min={0} max={100} precision={4} />
</Form.Item> </Form.Item>
</LayoutFormRow> </LayoutFormRow>

View File

@@ -50,7 +50,7 @@ export const QUERY_ALL_BILLS_PAGINATED = gql`
} }
`; `;
export const QUERY_PARTS_BILLS_BY_JOBID = gql` export const QUERY_BILLS_BY_JOBID = gql`
query QUERY_PARTS_BILLS_BY_JOBID($jobid: uuid!) { query QUERY_PARTS_BILLS_BY_JOBID($jobid: uuid!) {
parts_orders(where: { jobid: { _eq: $jobid } }, order_by: { order_date: desc }) { parts_orders(where: { jobid: { _eq: $jobid } }, order_by: { order_date: desc }) {
id id

View File

@@ -905,7 +905,7 @@ export const QUERY_JOB_CARD_DETAILS = gql`
} }
joblines( joblines(
where: { removed: { _eq: false } } where: { removed: { _eq: false }, part_type: { _is_null: false, _nin: ["PAE", "PAS", "PASL"] } }
order_by: { line_no: asc } order_by: { line_no: asc }
) { ) {
id id
@@ -1149,7 +1149,6 @@ export const UPDATE_JOB = gql`
suspended suspended
queued_for_parts queued_for_parts
scheduled_completion scheduled_completion
scheduled_delivery
actual_in actual_in
date_repairstarted date_repairstarted
date_void date_void

View File

@@ -1,5 +1,5 @@
import { PageHeader } from "@ant-design/pro-layout";
import { Button, Result, Space, Steps } from "antd"; import { Button, Result, Space, Steps } from "antd";
import { PageHeader } from "@ant-design/pro-layout";
import React, { useContext, useState } from "react"; import React, { useContext, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -9,6 +9,7 @@ import JobsCreateJobsInfo from "../../components/jobs-create-jobs-info/jobs-crea
import JobsCreateOwnerInfoContainer from "../../components/jobs-create-owner-info/jobs-create-owner-info.container"; import JobsCreateOwnerInfoContainer from "../../components/jobs-create-owner-info/jobs-create-owner-info.container";
import JobsCreateVehicleInfoContainer from "../../components/jobs-create-vehicle-info/jobs-create-vehicle-info.container"; import JobsCreateVehicleInfoContainer from "../../components/jobs-create-vehicle-info/jobs-create-vehicle-info.container";
import JobCreateContext from "../../pages/jobs-create/jobs-create.context"; import JobCreateContext from "../../pages/jobs-create/jobs-create.context";
import FormsFieldChanged from "../../components/form-fields-changed-alert/form-fields-changed-alert.component";
export default function JobsCreateComponent({ form }) { export default function JobsCreateComponent({ form }) {
const [pageIndex, setPageIndex] = useState(0); const [pageIndex, setPageIndex] = useState(0);
@@ -40,11 +41,10 @@ export default function JobsCreateComponent({ form }) {
const next = () => { const next = () => {
setPageIndex(pageIndex + 1); setPageIndex(pageIndex + 1);
console.log("Next"); console.log("NExt");
}; };
const prev = () => { const prev = () => {
setPageIndex(pageIndex - 1); setPageIndex(pageIndex - 1);
console.log("Previous");
}; };
const { Step } = Steps; const { Step } = Steps;
@@ -53,26 +53,26 @@ export default function JobsCreateComponent({ form }) {
<PageHeader <PageHeader
extra={ extra={
<Space wrap> <Space wrap>
{pageIndex > 0 && <Button onClick={() => prev()}>{t("general.actions.previous")}</Button>} {pageIndex > 0 && <Button onClick={() => prev()}>Previous</Button>}
{pageIndex < steps.length - 1 && ( {pageIndex < steps.length - 1 && (
<Button <Button
type="primary" type="primary"
onClick={() => { onClick={() => {
next(); next();
form // form
.validateFields() // .validateFields()
.then((r) => { // .then((r) => {
if (steps[pageIndex].validation) { // if (steps[pageIndex].validation) {
setErrorMessage(null); // setErrorMessage(null);
next(); // next();
} else { // } else {
setErrorMessage(steps[pageIndex].error); // setErrorMessage(steps[pageIndex].error);
} // }
}) // })
.catch((error) => console.log("error", error)); // .catch((error) => console.log("error", error));
}} }}
> >
{t("general.actions.next")} Next
</Button> </Button>
)} )}
{pageIndex === steps.length - 1 && ( {pageIndex === steps.length - 1 && (
@@ -104,17 +104,17 @@ export default function JobsCreateComponent({ form }) {
}} }}
onClick={() => { onClick={() => {
setPageIndex(idx); setPageIndex(idx);
form // form
.validateFields() // .validateFields()
.then((r) => { // .then((r) => {
if (steps[pageIndex].validation) { // if (steps[pageIndex].validation) {
setErrorMessage(null); // setErrorMessage(null);
setPageIndex(idx); // setPageIndex(idx);
} else { // } else {
setErrorMessage(steps[pageIndex].error); // setErrorMessage(steps[pageIndex].error);
} // }
}) // })
.catch((error) => console.log("error", error)); // .catch((error) => console.log("error", error));
}} }}
/> />
))} ))}
@@ -144,7 +144,7 @@ export default function JobsCreateComponent({ form }) {
) : ( ) : (
<div> <div>
<ProgressButtons top /> <ProgressButtons top />
<FormsFieldChanged form={form} />
{errorMessage ? ( {errorMessage ? (
<div> <div>
<AlertComponent message={errorMessage} type="error" /> <AlertComponent message={errorMessage} type="error" />

View File

@@ -10,9 +10,9 @@ import { INSERT_NEW_JOB } from "../../graphql/jobs.queries";
import { QUERY_OWNER_FOR_JOB_CREATION } from "../../graphql/owners.queries"; import { QUERY_OWNER_FOR_JOB_CREATION } from "../../graphql/owners.queries";
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions"; import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import InstanceRenderManager from "../../utils/instanceRenderMgr";
import JobsCreateComponent from "./jobs-create.component"; import JobsCreateComponent from "./jobs-create.component";
import JobCreateContext from "./jobs-create.context"; import JobCreateContext from "./jobs-create.context";
import InstanceRenderManager from "../../utils/instanceRenderMgr";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop bodyshop: selectBodyshop
@@ -159,6 +159,13 @@ function JobsCreateContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
layout="vertical" layout="vertical"
autoComplete={"off"} autoComplete={"off"}
initialValues={{ initialValues={{
tax_tow_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
tax_str_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
tax_paint_mat_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
tax_shop_mat_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
tax_sub_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
tax_lbr_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
tax_levies_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
federal_tax_rate: bodyshop.bill_tax_rates.federal_tax_rate / 100, federal_tax_rate: bodyshop.bill_tax_rates.federal_tax_rate / 100,
state_tax_rate: bodyshop.bill_tax_rates.state_tax_rate / 100, state_tax_rate: bodyshop.bill_tax_rates.state_tax_rate / 100,
local_tax_rate: bodyshop.bill_tax_rates.local_tax_rate / 100, local_tax_rate: bodyshop.bill_tax_rates.local_tax_rate / 100,
@@ -254,34 +261,19 @@ function JobsCreateContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100 prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100
} }
}, },
tax_tow_rt: bodyshop.bill_tax_rates.state_tax_rate / 100, rome: {
tax_str_rt: bodyshop.bill_tax_rates.state_tax_rate / 100, cieca_pft: {
tax_paint_mat_rt: bodyshop.bill_tax_rates.state_tax_rate / 100, ...bodyshop.md_responsibility_centers.taxes.tax_ty1,
tax_shop_mat_rt: bodyshop.bill_tax_rates.state_tax_rate / 100, ...bodyshop.md_responsibility_centers.taxes.tax_ty2,
tax_sub_rt: bodyshop.bill_tax_rates.state_tax_rate / 100, ...bodyshop.md_responsibility_centers.taxes.tax_ty3,
tax_lbr_rt: bodyshop.bill_tax_rates.state_tax_rate / 100, ...bodyshop.md_responsibility_centers.taxes.tax_ty4,
tax_levies_rt: bodyshop.bill_tax_rates.state_tax_rate / 100 ...bodyshop.md_responsibility_centers.taxes.tax_ty5
}, },
rome: { materials: bodyshop.md_responsibility_centers.cieca_pfm,
cieca_pft: { cieca_pfl: bodyshop.md_responsibility_centers.cieca_pfl,
...bodyshop.md_responsibility_centers.taxes.tax_ty1, parts_tax_rates: bodyshop.md_responsibility_centers.parts_tax_rates
...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,
tax_tow_rt: bodyshop.md_responsibility_centers.tax_tow_rt,
tax_str_rt: bodyshop.md_responsibility_centers.tax_str_rt,
tax_paint_mat_rt: bodyshop.md_responsibility_centers.tax_paint_mat_rt,
tax_shop_mat_rt: bodyshop.md_responsibility_centers.tax_shop_mat_rt,
tax_sub_rt: bodyshop.md_responsibility_centers.tax_sub_rt,
tax_lbr_rt: bodyshop.md_responsibility_centers.tax_lbr_rt,
tax_levies_rt: bodyshop.md_responsibility_centers.tax_levies_rt
},
promanager: "USE_ROME"
}) })
}} }}
> >

View File

@@ -8,11 +8,11 @@ import Icon, {
SyncOutlined, SyncOutlined,
ToolFilled ToolFilled
} from "@ant-design/icons"; } from "@ant-design/icons";
import { PageHeader } from "@ant-design/pro-layout";
import { useQuery } from "@apollo/client";
import { Badge, Button, Divider, Form, notification, Space, Tabs } from "antd"; import { Badge, Button, Divider, Form, notification, Space, Tabs } from "antd";
import { PageHeader } from "@ant-design/pro-layout";
import Axios from "axios"; import Axios from "axios";
import _ from "lodash"; import dayjs from "../../utils/day";
import queryString from "query-string"; import queryString from "query-string";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -20,13 +20,11 @@ import { FaHardHat, FaRegStickyNote, FaShieldAlt, FaTasks } from "react-icons/fa
import { connect } from "react-redux"; import { connect } from "react-redux";
import { useLocation, useNavigate } from "react-router-dom"; import { useLocation, useNavigate } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { HasFeatureAccess } from "../../components/feature-wrapper/feature-wrapper.component";
import FormFieldsChanged from "../../components/form-fields-changed-alert/form-fields-changed-alert.component"; import FormFieldsChanged from "../../components/form-fields-changed-alert/form-fields-changed-alert.component";
import JobAuditTrail from "../../components/job-audit-trail/job-audit-trail.component"; import JobAuditTrail from "../../components/job-audit-trail/job-audit-trail.component";
import JobsLinesContainer from "../../components/job-detail-lines/job-lines.container"; import JobsLinesContainer from "../../components/job-detail-lines/job-lines.container";
import JobLifecycleComponent from "../../components/job-lifecycle/job-lifecycle.component"; import JobLifecycleComponent from "../../components/job-lifecycle/job-lifecycle.component";
import JobLineUpsertModalContainer from "../../components/job-lines-upsert-modal/job-lines-upsert-modal.container"; import JobLineUpsertModalContainer from "../../components/job-lines-upsert-modal/job-lines-upsert-modal.container";
import JobProfileDataWarning from "../../components/job-profile-data-warning/job-profile-data-warning.component";
import JobReconciliationModal from "../../components/job-reconciliation-modal/job-reconciliation.modal.container"; import JobReconciliationModal from "../../components/job-reconciliation-modal/job-reconciliation.modal.container";
import JobSyncButton from "../../components/job-sync-button/job-sync-button.component"; import JobSyncButton from "../../components/job-sync-button/job-sync-button.component";
import JobsChangeStatus from "../../components/jobs-change-status/jobs-change-status.component"; import JobsChangeStatus from "../../components/jobs-change-status/jobs-change-status.component";
@@ -44,18 +42,19 @@ import JobsDocumentsLocalGallery from "../../components/jobs-documents-local-gal
import JobNotesContainer from "../../components/jobs-notes/jobs-notes.container"; import JobNotesContainer from "../../components/jobs-notes/jobs-notes.container";
import NoteUpsertModalComponent from "../../components/note-upsert-modal/note-upsert-modal.container"; import NoteUpsertModalComponent from "../../components/note-upsert-modal/note-upsert-modal.container";
import ScheduleJobModalContainer from "../../components/schedule-job-modal/schedule-job-modal.container"; import ScheduleJobModalContainer from "../../components/schedule-job-modal/schedule-job-modal.container";
import TaskListContainer from "../../components/task-list/task-list.container.jsx";
import { QUERY_PARTS_BILLS_BY_JOBID } from "../../graphql/bills.queries.js";
import { QUERY_JOB_TASKS_PAGINATED } from "../../graphql/tasks.queries.js";
import { insertAuditTrail } from "../../redux/application/application.actions"; import { insertAuditTrail } from "../../redux/application/application.actions";
import { selectJobReadOnly } from "../../redux/application/application.selectors"; import { selectJobReadOnly } from "../../redux/application/application.selectors";
import { setModalContext } from "../../redux/modals/modals.actions"; import { setModalContext } from "../../redux/modals/modals.actions";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import AuditTrailMapping from "../../utils/AuditTrailMappings"; import AuditTrailMapping from "../../utils/AuditTrailMappings";
import { DateTimeFormat } from "../../utils/DateFormatter";
import dayjs from "../../utils/day";
import InstanceRenderManager from "../../utils/instanceRenderMgr";
import UndefinedToNull from "../../utils/undefinedtonull"; import UndefinedToNull from "../../utils/undefinedtonull";
import _ from "lodash";
import JobProfileDataWarning from "../../components/job-profile-data-warning/job-profile-data-warning.component";
import { DateTimeFormat } from "../../utils/DateFormatter";
import InstanceRenderManager from "../../utils/instanceRenderMgr";
import { HasFeatureAccess } from "../../components/feature-wrapper/feature-wrapper.component";
import TaskListContainer from "../../components/task-list/task-list.container.jsx";
import { QUERY_JOB_TASKS_PAGINATED } from "../../graphql/tasks.queries.js";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
@@ -96,11 +95,6 @@ export function JobsDetailPage({
const formItemLayout = { const formItemLayout = {
layout: "vertical" layout: "vertical"
}; };
const billsQuery = useQuery(QUERY_PARTS_BILLS_BY_JOBID, {
variables: { jobid: job.id },
fetchPolicy: "network-only",
nextFetchPolicy: "network-only"
});
useEffect(() => { useEffect(() => {
//form.setFieldsValue(transormJobToForm(job)); //form.setFieldsValue(transormJobToForm(job));
@@ -109,42 +103,6 @@ export function JobsDetailPage({
//useKeyboardSaveShortcut(form.submit); //useKeyboardSaveShortcut(form.submit);
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({ 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) });
}
};
const handleFinish = async (values) => { const handleFinish = async (values) => {
setLoading(true); setLoading(true);
@@ -344,18 +302,7 @@ export function JobsDetailPage({
id: "job-details-repairdata", id: "job-details-repairdata",
label: t("menus.jobsdetail.repairdata"), label: t("menus.jobsdetail.repairdata"),
forceRender: true, forceRender: true,
children: ( children: <JobsLinesContainer job={job} joblines={job.joblines} refetch={refetch} form={form} />
<JobsLinesContainer
job={job}
joblines={job.joblines}
billsQuery={billsQuery}
handleBillOnRowClick={handleBillOnRowClick}
handlePartsOrderOnRowClick={handlePartsOrderOnRowClick}
handlePartsDispatchOnRowClick={handlePartsDispatchOnRowClick}
refetch={refetch}
form={form}
/>
)
}, },
{ {
key: "rates", key: "rates",
@@ -379,15 +326,7 @@ export function JobsDetailPage({
label: HasFeatureAccess({ featureName: "bills", bodyshop }) label: HasFeatureAccess({ featureName: "bills", bodyshop })
? t("menus.jobsdetail.partssublet") ? t("menus.jobsdetail.partssublet")
: t("menus.jobsdetail.parts"), : t("menus.jobsdetail.parts"),
children: ( children: <JobsDetailPliContainer job={job} />
<JobsDetailPliContainer
job={job}
billsQuery={billsQuery}
handleBillOnRowClick={handleBillOnRowClick}
handlePartsOrderOnRowClick={handlePartsOrderOnRowClick}
handlePartsDispatchOnRowClick={handlePartsDispatchOnRowClick}
/>
)
}, },
...(InstanceRenderManager({ ...(InstanceRenderManager({
imex: true, imex: true,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1081,32 +1081,6 @@ export const TemplateList = (type, context) => {
}, },
group: "purchases" group: "purchases"
}, },
purchases_by_ro_detail_date: {
title: i18n.t("reportcenter.templates.purchases_by_ro_detail_date"),
description: "",
subject: i18n.t("reportcenter.templates.purchases_by_ro_detail_date"),
key: "purchases_by_ro_detail_date",
//idtype: "vendor",
disabled: false,
rangeFilter: {
object: i18n.t("reportcenter.labels.objects.jobs"),
field: i18n.t("jobs.fields.date_invoiced")
},
group: "purchases"
},
purchases_by_ro_summary_date: {
title: i18n.t("reportcenter.templates.purchases_by_ro_summary_date"),
description: "",
subject: i18n.t("reportcenter.templates.purchases_by_ro_summary_date"),
key: "purchases_by_ro_summary_date",
//idtype: "vendor",
disabled: false,
rangeFilter: {
object: i18n.t("reportcenter.labels.objects.jobs"),
field: i18n.t("jobs.fields.date_invoiced")
},
group: "purchases"
},
job_costing_ro_date_summary: { job_costing_ro_date_summary: {
title: i18n.t("reportcenter.templates.job_costing_ro_date_summary"), title: i18n.t("reportcenter.templates.job_costing_ro_date_summary"),
description: "", description: "",
@@ -1194,17 +1168,6 @@ export const TemplateList = (type, context) => {
}, },
group: "customers" group: "customers"
}, },
payments_by_date_payment: {
title: i18n.t("reportcenter.templates.payments_by_date_payment"),
subject: i18n.t("reportcenter.templates.payments_by_date_payment"),
key: "payments_by_date_payment",
disabled: false,
rangeFilter: {
object: i18n.t("reportcenter.labels.objects.payments"),
field: i18n.t("payments.fields.date")
},
group: "customers"
},
schedule: { schedule: {
title: i18n.t("reportcenter.templates.schedule"), title: i18n.t("reportcenter.templates.schedule"),
subject: i18n.t("reportcenter.templates.schedule"), subject: i18n.t("reportcenter.templates.schedule"),

View File

@@ -1,10 +0,0 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- CREATE OR REPLACE VIEW "public"."joblines_status" AS
-- SELECT j.jobid,
-- j.status,
-- count(1) AS count,
-- j.part_type
-- FROM joblines j
-- WHERE ((j.part_type IS NOT NULL) AND (j.part_type <> 'PAE'::text) AND (j.part_type <> 'PAS'::text) AND (j.part_type <> 'PASL'::text) AND (j.part_qty <> 0) AND (j.act_price <> 0) AND (j.removed IS FALSE))
-- GROUP BY j.jobid, j.status, j.part_type;

View File

@@ -1,8 +0,0 @@
CREATE OR REPLACE VIEW "public"."joblines_status" AS
SELECT j.jobid,
j.status,
count(1) AS count,
j.part_type
FROM joblines j
WHERE ((j.part_type IS NOT NULL) AND (j.part_type <> 'PAE'::text) AND (j.part_type <> 'PAS'::text) AND (j.part_type <> 'PASL'::text) AND (j.part_qty <> 0) AND (j.act_price <> 0) AND (j.removed IS FALSE))
GROUP BY j.jobid, j.status, j.part_type;

View File

@@ -1,10 +0,0 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- CREATE OR REPLACE VIEW "public"."joblines_status" AS
-- SELECT j.jobid,
-- j.status,
-- count(1) AS count,
-- j.part_type
-- FROM joblines j
-- WHERE ((j.part_type IS NOT NULL) AND (j.part_type <> 'PAE'::text) AND (j.part_type <> 'PAS'::text) AND (j.part_type <> 'PASL'::text) AND (j.part_qty <> (0)::numeric) AND (j.act_price <> (0)::numeric) AND (j.removed IS FALSE))
-- GROUP BY j.jobid, j.status, j.part_type;

View File

@@ -1,8 +0,0 @@
CREATE OR REPLACE VIEW "public"."joblines_status" AS
SELECT j.jobid,
j.status,
count(1) AS count,
j.part_type
FROM joblines j
WHERE ((j.part_type IS NOT NULL) AND (j.part_type <> 'PAE'::text) AND (j.part_type <> 'PAS'::text) AND (j.part_type <> 'PASL'::text) AND (j.part_qty <> (0)::numeric) AND (j.act_price <> (0)::numeric) AND (j.removed IS FALSE))
GROUP BY j.jobid, j.status, j.part_type;

480
package-lock.json generated
View File

@@ -19,8 +19,6 @@
"better-queue": "^3.8.12", "better-queue": "^3.8.12",
"bluebird": "^3.7.2", "bluebird": "^3.7.2",
"body-parser": "^1.20.2", "body-parser": "^1.20.2",
"canvas": "^2.11.2",
"chart.js": "^4.4.3",
"cloudinary": "^2.0.2", "cloudinary": "^2.0.2",
"compression": "^1.7.4", "compression": "^1.7.4",
"cookie-parser": "^1.4.6", "cookie-parser": "^1.4.6",
@@ -1689,45 +1687,6 @@
"@jridgewell/sourcemap-codec": "^1.4.14" "@jridgewell/sourcemap-codec": "^1.4.14"
} }
}, },
"node_modules/@kurkle/color": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz",
"integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw=="
},
"node_modules/@mapbox/node-pre-gyp": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz",
"integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==",
"dependencies": {
"detect-libc": "^2.0.0",
"https-proxy-agent": "^5.0.0",
"make-dir": "^3.1.0",
"node-fetch": "^2.6.7",
"nopt": "^5.0.0",
"npmlog": "^5.0.1",
"rimraf": "^3.0.2",
"semver": "^7.3.5",
"tar": "^6.1.11"
},
"bin": {
"node-pre-gyp": "bin/node-pre-gyp"
}
},
"node_modules/@mapbox/node-pre-gyp/node_modules/rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
"deprecated": "Rimraf versions prior to v4 are no longer supported",
"dependencies": {
"glob": "^7.1.3"
},
"bin": {
"rimraf": "bin.js"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/@oozcitak/dom": { "node_modules/@oozcitak/dom": {
"version": "1.15.10", "version": "1.15.10",
"resolved": "https://registry.npmjs.org/@oozcitak/dom/-/dom-1.15.10.tgz", "resolved": "https://registry.npmjs.org/@oozcitak/dom/-/dom-1.15.10.tgz",
@@ -2650,11 +2609,6 @@
"node": ">=10.0.0" "node": ">=10.0.0"
} }
}, },
"node_modules/abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
},
"node_modules/abort-controller": { "node_modules/abort-controller": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
@@ -2751,24 +2705,6 @@
"resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
"integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw=="
}, },
"node_modules/aproba": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz",
"integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ=="
},
"node_modules/are-we-there-yet": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz",
"integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==",
"deprecated": "This package is no longer supported.",
"dependencies": {
"delegates": "^1.0.0",
"readable-stream": "^3.6.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/array-flatten": { "node_modules/array-flatten": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
@@ -3070,20 +3006,6 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/canvas": {
"version": "2.11.2",
"resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz",
"integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==",
"hasInstallScript": true,
"dependencies": {
"@mapbox/node-pre-gyp": "^1.0.0",
"nan": "^2.17.0",
"simple-get": "^3.0.3"
},
"engines": {
"node": ">=6"
}
},
"node_modules/caseless": { "node_modules/caseless": {
"version": "0.12.0", "version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
@@ -3117,17 +3039,6 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/chart.js": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.3.tgz",
"integrity": "sha512-qK1gkGSRYcJzqrrzdR6a+I0vQ4/R+SoODXyAjscQ/4mzuNzySaMCd+hyVxitSY1+L2fjPD1Gbn+ibNqRmwQeLw==",
"dependencies": {
"@kurkle/color": "^0.3.0"
},
"engines": {
"pnpm": ">=8"
}
},
"node_modules/cheerio": { "node_modules/cheerio": {
"version": "1.0.0-rc.12", "version": "1.0.0-rc.12",
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz",
@@ -3164,14 +3075,6 @@
"url": "https://github.com/sponsors/fb55" "url": "https://github.com/sponsors/fb55"
} }
}, },
"node_modules/chownr": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
"engines": {
"node": ">=10"
}
},
"node_modules/cliui": { "node_modules/cliui": {
"version": "8.0.1", "version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
@@ -3232,14 +3135,6 @@
"simple-swizzle": "^0.2.2" "simple-swizzle": "^0.2.2"
} }
}, },
"node_modules/color-support": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
"integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
"bin": {
"color-support": "bin.js"
}
},
"node_modules/color/node_modules/color-convert": { "node_modules/color/node_modules/color-convert": {
"version": "1.9.3", "version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@@ -3333,7 +3228,8 @@
"node_modules/concat-map": { "node_modules/concat-map": {
"version": "0.0.1", "version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"dev": true
}, },
"node_modules/concat-stream": { "node_modules/concat-stream": {
"version": "1.6.2", "version": "1.6.2",
@@ -3398,11 +3294,6 @@
"url": "https://github.com/open-cli-tools/concurrently?sponsor=1" "url": "https://github.com/open-cli-tools/concurrently?sponsor=1"
} }
}, },
"node_modules/console-control-strings": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
"integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ=="
},
"node_modules/content-disposition": { "node_modules/content-disposition": {
"version": "0.5.4", "version": "0.5.4",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
@@ -3649,17 +3540,6 @@
"node": ">=0.10" "node": ">=0.10"
} }
}, },
"node_modules/decompress-response": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz",
"integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==",
"dependencies": {
"mimic-response": "^2.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/deeks": { "node_modules/deeks": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/deeks/-/deeks-3.1.0.tgz", "resolved": "https://registry.npmjs.org/deeks/-/deeks-3.1.0.tgz",
@@ -3708,11 +3588,6 @@
"node": ">=0.4.0" "node": ">=0.4.0"
} }
}, },
"node_modules/delegates": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
"integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ=="
},
"node_modules/depd": { "node_modules/depd": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
@@ -3739,14 +3614,6 @@
"npm": "1.2.8000 || >= 1.4.16" "npm": "1.2.8000 || >= 1.4.16"
} }
}, },
"node_modules/detect-libc": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
"integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==",
"engines": {
"node": ">=8"
}
},
"node_modules/dev-null": { "node_modules/dev-null": {
"version": "0.1.1", "version": "0.1.1",
"resolved": "https://registry.npmjs.org/dev-null/-/dev-null-0.1.1.tgz", "resolved": "https://registry.npmjs.org/dev-null/-/dev-null-0.1.1.tgz",
@@ -4419,32 +4286,11 @@
"node": ">=6 <7 || >=8" "node": ">=6 <7 || >=8"
} }
}, },
"node_modules/fs-minipass": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
"integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
"dependencies": {
"minipass": "^3.0.0"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/fs-minipass/node_modules/minipass": {
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
"integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/fs.realpath": { "node_modules/fs.realpath": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"dev": true
}, },
"node_modules/ftp": { "node_modules/ftp": {
"version": "0.3.10", "version": "0.3.10",
@@ -4493,31 +4339,6 @@
"integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==",
"optional": true "optional": true
}, },
"node_modules/gauge": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz",
"integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==",
"deprecated": "This package is no longer supported.",
"dependencies": {
"aproba": "^1.0.3 || ^2.0.0",
"color-support": "^1.1.2",
"console-control-strings": "^1.0.0",
"has-unicode": "^2.0.1",
"object-assign": "^4.1.1",
"signal-exit": "^3.0.0",
"string-width": "^4.2.3",
"strip-ansi": "^6.0.1",
"wide-align": "^1.1.2"
},
"engines": {
"node": ">=10"
}
},
"node_modules/gauge/node_modules/signal-exit": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
},
"node_modules/gaxios": { "node_modules/gaxios": {
"version": "6.1.1", "version": "6.1.1",
"resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.1.1.tgz", "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.1.1.tgz",
@@ -4629,46 +4450,6 @@
"assert-plus": "^1.0.0" "assert-plus": "^1.0.0"
} }
}, },
"node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"deprecated": "Glob versions prior to v9 are no longer supported",
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/glob/node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/glob/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/globals": { "node_modules/globals": {
"version": "11.12.0", "version": "11.12.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
@@ -4853,11 +4634,6 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/has-unicode": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
"integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ=="
},
"node_modules/hasown": { "node_modules/hasown": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz",
@@ -4985,6 +4761,7 @@
"version": "1.0.6", "version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"dev": true,
"dependencies": { "dependencies": {
"once": "^1.3.0", "once": "^1.3.0",
"wrappy": "1" "wrappy": "1"
@@ -5552,28 +5329,6 @@
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
"integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==" "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A=="
}, },
"node_modules/make-dir": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
"integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
"dependencies": {
"semver": "^6.0.0"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/make-dir/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/make-error": { "node_modules/make-error": {
"version": "1.3.6", "version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
@@ -5647,17 +5402,6 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/mimic-response": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz",
"integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==",
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/minimalistic-assert": { "node_modules/minimalistic-assert": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
@@ -5691,29 +5435,6 @@
"node": ">=16 || 14 >=14.17" "node": ">=16 || 14 >=14.17"
} }
}, },
"node_modules/minizlib": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
"integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
"dependencies": {
"minipass": "^3.0.0",
"yallist": "^4.0.0"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/minizlib/node_modules/minipass": {
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
"integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/mkdirp": { "node_modules/mkdirp": {
"version": "0.5.6", "version": "0.5.6",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
@@ -5769,7 +5490,8 @@
"node_modules/nan": { "node_modules/nan": {
"version": "2.18.0", "version": "2.18.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.18.0.tgz", "resolved": "https://registry.npmjs.org/nan/-/nan-2.18.0.tgz",
"integrity": "sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==" "integrity": "sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==",
"optional": true
}, },
"node_modules/negotiator": { "node_modules/negotiator": {
"version": "0.6.3", "version": "0.6.3",
@@ -5909,32 +5631,6 @@
"node": ">=6.0.0" "node": ">=6.0.0"
} }
}, },
"node_modules/nopt": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
"integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
"dependencies": {
"abbrev": "1"
},
"bin": {
"nopt": "bin/nopt.js"
},
"engines": {
"node": ">=6"
}
},
"node_modules/npmlog": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz",
"integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==",
"deprecated": "This package is no longer supported.",
"dependencies": {
"are-we-there-yet": "^2.0.0",
"console-control-strings": "^1.1.0",
"gauge": "^3.0.0",
"set-blocking": "^2.0.0"
}
},
"node_modules/nth-check": { "node_modules/nth-check": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
@@ -6128,6 +5824,7 @@
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
"dev": true,
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
@@ -6794,11 +6491,6 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
},
"node_modules/set-function-length": { "node_modules/set-function-length": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz",
@@ -6870,35 +6562,6 @@
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/simple-concat": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
"integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/simple-get": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz",
"integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==",
"dependencies": {
"decompress-response": "^4.2.0",
"once": "^1.3.1",
"simple-concat": "^1.0.0"
}
},
"node_modules/simple-swizzle": { "node_modules/simple-swizzle": {
"version": "0.2.2", "version": "0.2.2",
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
@@ -7059,6 +6722,16 @@
"node": ">=12" "node": ">=12"
} }
}, },
"node_modules/source-map-explorer/node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/source-map-explorer/node_modules/cliui": { "node_modules/source-map-explorer/node_modules/cliui": {
"version": "7.0.4", "version": "7.0.4",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
@@ -7070,6 +6743,38 @@
"wrap-ansi": "^7.0.0" "wrap-ansi": "^7.0.0"
} }
}, },
"node_modules/source-map-explorer/node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"dev": true,
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/source-map-explorer/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/source-map-explorer/node_modules/source-map": { "node_modules/source-map-explorer/node_modules/source-map": {
"version": "0.7.4", "version": "0.7.4",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
@@ -7453,41 +7158,6 @@
"url": "https://github.com/chalk/supports-color?sponsor=1" "url": "https://github.com/chalk/supports-color?sponsor=1"
} }
}, },
"node_modules/tar": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
"integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
"dependencies": {
"chownr": "^2.0.0",
"fs-minipass": "^2.0.0",
"minipass": "^5.0.0",
"minizlib": "^2.1.1",
"mkdirp": "^1.0.3",
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/tar/node_modules/minipass": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
"integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
"engines": {
"node": ">=8"
}
},
"node_modules/tar/node_modules/mkdirp": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
"bin": {
"mkdirp": "bin/cmd.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/teeny-request": { "node_modules/teeny-request": {
"version": "9.0.0", "version": "9.0.0",
"resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-9.0.0.tgz", "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-9.0.0.tgz",
@@ -7540,6 +7210,48 @@
"node": ">=6.0.0" "node": ">=6.0.0"
} }
}, },
"node_modules/temp/node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/temp/node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"dev": true,
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/temp/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/temp/node_modules/rimraf": { "node_modules/temp/node_modules/rimraf": {
"version": "2.6.3", "version": "2.6.3",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
@@ -7887,14 +7599,6 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/wide-align": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz",
"integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==",
"dependencies": {
"string-width": "^1.0.2 || 2 || 3 || 4"
}
},
"node_modules/winston": { "node_modules/winston": {
"version": "3.11.0", "version": "3.11.0",
"resolved": "https://registry.npmjs.org/winston/-/winston-3.11.0.tgz", "resolved": "https://registry.npmjs.org/winston/-/winston-3.11.0.tgz",

View File

@@ -12,6 +12,9 @@
"admin": "cd admin && npm start", "admin": "cd admin && npm start",
"client": "cd client && npm start", "client": "cd client && npm start",
"server": "nodemon server.js", "server": "nodemon server.js",
"server:imex": "nodemon server.js imex",
"server:rome": "nodemon server.js rome",
"server:promanager": "nodemon server.js promanager",
"build": "cd client && npm run build", "build": "cd client && npm run build",
"dev": "concurrently --kill-others-on-fail \"npm run server\" \"npm run client\"", "dev": "concurrently --kill-others-on-fail \"npm run server\" \"npm run client\"",
"deva": "concurrently --kill-others-on-fail \"npm run server\" \"npm run client\" \"npm run admin\"", "deva": "concurrently --kill-others-on-fail \"npm run server\" \"npm run client\" \"npm run admin\"",
@@ -29,8 +32,6 @@
"better-queue": "^3.8.12", "better-queue": "^3.8.12",
"bluebird": "^3.7.2", "bluebird": "^3.7.2",
"body-parser": "^1.20.2", "body-parser": "^1.20.2",
"canvas": "^2.11.2",
"chart.js": "^4.4.3",
"cloudinary": "^2.0.2", "cloudinary": "^2.0.2",
"compression": "^1.7.4", "compression": "^1.7.4",
"cookie-parser": "^1.4.6", "cookie-parser": "^1.4.6",

View File

@@ -8,9 +8,11 @@ const cookieParser = require("cookie-parser");
const http = require("http"); const http = require("http");
const { Server } = require("socket.io"); const { Server } = require("socket.io");
const instanceName = process.argv[2];
// Load environment variables // Load environment variables
require("dotenv").config({ require("dotenv").config({
path: path.resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`) path: path.resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}${instanceName ? `.${instanceName}` : ''}`)
}); });
// Import custom utilities and handlers // Import custom utilities and handlers

View File

@@ -632,7 +632,7 @@ exports.default = function ({ bodyshop, jobs_by_pk, qbo = false, items, taxCodes
} }
} }
//QB USA with GST and PST //QB USA with GST
//This was required for the No. 1 Collision Group. //This was required for the No. 1 Collision Group.
if ( if (
bodyshop.accountingconfig && bodyshop.accountingconfig &&
@@ -651,20 +651,9 @@ exports.default = function ({ bodyshop, jobs_by_pk, qbo = false, items, taxCodes
Qty: 1 Qty: 1
} }
}); });
InvoiceLineAdd.push({
DetailType: "SalesItemLineDetail",
Amount: Dinero(jobs_by_pk.job_totals.totals.state_tax).toFormat(DineroQbFormat),
SalesItemLineDetail: {
...(jobs_by_pk.class ? { ClassRef: { value: classes[jobs_by_pk.class] } } : {}),
ItemRef: {
value: items[bodyshop.md_responsibility_centers.taxes.state.accountitem]
},
Qty: 1
}
});
} }
} else { } else {
//Handle insurance profile adjustments for Parts //Handle insurance profile adjustments
Object.keys(job_totals.parts.adjustments).forEach((key) => { Object.keys(job_totals.parts.adjustments).forEach((key) => {
if (qbo) { if (qbo) {
//Going to always assume that we need to apply GST and PST for labor. //Going to always assume that we need to apply GST and PST for labor.
@@ -718,67 +707,6 @@ exports.default = function ({ bodyshop, jobs_by_pk, qbo = false, items, taxCodes
} }
}); });
//Handle insurance profile adjustments for Labor and Materials
Object.keys(job_totals.rates).forEach((key) => {
if (
job_totals.rates[key] &&
job_totals.rates[key].adjustment &&
Dinero(job_totals.rates[key].adjustment).isZero() === false
) {
if (qbo) {
//Going to always assume that we need to apply GST and PST for labor.
const taxAccountCode = findTaxCode(
{
local: false,
federal: process.env.COUNTRY === "USA" ? false : true,
state: jobs_by_pk.state_tax_rate === 0 ? false : true
},
bodyshop.md_responsibility_centers.sales_tax_codes
);
const account = responsibilityCenters.profits.find(
(c) => c.name === responsibilityCenters.defaults.profits[key.toUpperCase()]
);
const QboTaxId =
process.env.COUNTRY === "USA"
? CheckQBOUSATaxID({
// jobline: jobline,
job: jobs_by_pk,
type: "storage"
})
: taxCodes[taxAccountCode];
InvoiceLineAdd.push({
DetailType: "SalesItemLineDetail",
Amount: Dinero(job_totals.rates[key].adjustment).toFormat(DineroQbFormat),
Description: `${account.accountdesc} - Adjustment`,
SalesItemLineDetail: {
...(jobs_by_pk.class ? { ClassRef: { value: classes[jobs_by_pk.class] } } : {}),
ItemRef: {
value: items[account.accountitem]
},
TaxCodeRef: {
value: QboTaxId
},
Qty: 1
}
});
} else {
InvoiceLineAdd.push({
ItemRef: {
FullName: responsibilityCenters.profits.find(
(c) => c.name === responsibilityCenters.defaults.profits[key.toUpperCase()]
).accountitem
},
Desc: "Storage",
Quantity: 1,
Amount: Dinero(job_totals.rates[key].adjustment).toFormat(DineroQbFormat),
SalesTaxCodeRef: {
FullName: bodyshop.md_responsibility_centers.taxes.itemexemptcode || "NON"
}
});
}
}
});
const QboTaxId = const QboTaxId =
process.env.COUNTRY === "USA" process.env.COUNTRY === "USA"
? CheckQBOUSATaxID({ ? CheckQBOUSATaxID({
@@ -963,11 +891,7 @@ function checkStateTax(jobline, jobs_by_pk) {
} }
const isAdditionalCost = const isAdditionalCost =
(jobline.lbr_op === "OP13" || (jobline.lbr_op === "OP13" || (jobline.db_ref && jobline.db_ref.startsWith("9360"))) && !isPaintOrShopMat;
(jobline.lbr_op === "OP14" && jobline.act_price > 0 && jobline.mod_lb_hrs === 0) ||
(jobline.db_ref && jobline.db_ref.startsWith("9360")) ||
(jobline.db_ref && jobline.db_ref.startsWith("90051"))) &&
!isPaintOrShopMat;
if (!jobline.part_type && isAdditionalCost) { if (!jobline.part_type && isAdditionalCost) {
if (jobs_by_pk.tax_lbr_rt === 0) { if (jobs_by_pk.tax_lbr_rt === 0) {
@@ -977,12 +901,18 @@ function checkStateTax(jobline, jobs_by_pk) {
} }
} }
if (
jobline.db_ref === "900511" ||
jobline.db_ref === "900510" ||
(jobline.mod_lb_hrs === 0 && jobline.act_price > 0 && jobline.lbr_op === "OP14")
)
return true; //Extending IO-1375 as a part of IO-2023
if (jobline.tax_part === false) { if (jobline.tax_part === false) {
return false; return false;
} else { } else {
if (jobline.part_type) { if (jobline.part_type) {
if ( if (
!jobs_by_pk.parts_tax_rates[`${jobline.part_type.toUpperCase()}`] ||
jobs_by_pk.parts_tax_rates[`${jobline.part_type.toUpperCase()}`].prt_tax_in === false || jobs_by_pk.parts_tax_rates[`${jobline.part_type.toUpperCase()}`].prt_tax_in === false ||
jobs_by_pk.parts_tax_rates[`${jobline.part_type.toUpperCase()}`].prt_tax_rt === 0 jobs_by_pk.parts_tax_rates[`${jobline.part_type.toUpperCase()}`].prt_tax_rt === 0
) { ) {

View File

@@ -16,418 +16,403 @@ const { DiscountNotAlreadyCounted } = InstanceManager({
promanager: "USE_ROME" promanager: "USE_ROME"
}); });
exports.defaultRoute = async function (req, res) {
try {
CdkBase.createLogEvent(req, "DEBUG", `Received request to calculate allocations for ${req.body.jobid}`);
const jobData = await QueryJobData(req, req.BearerToken, req.body.jobid);
return res.status(200).json({ data: calculateAllocations(req, jobData) });
} catch (error) {
console.log(error);
CdkBase.createLogEvent(req, "ERROR", `Error encountered in CdkCalculateAllocations. ${error}`);
res.status(500).json({ error: `Error encountered in CdkCalculateAllocations. ${error}` });
}
};
exports.default = async function (socket, jobid) { exports.default = async function (socket, jobid) {
try { try {
const jobData = await QueryJobData(socket, "Bearer " + socket.handshake.auth.token, jobid); CdkBase.createLogEvent(socket, "DEBUG", `Received request to calculate allocations for ${jobid}`);
return calculateAllocations(socket, jobData); const job = await QueryJobData(socket, jobid);
const { bodyshop } = job;
const taxAllocations = InstanceManager({
executeFunction: true,
deubg: true,
args: [],
imex: () => ({
local: {
center: bodyshop.md_responsibility_centers.taxes.local.name,
sale: Dinero(job.job_totals.totals.local_tax),
cost: Dinero(),
profitCenter: bodyshop.md_responsibility_centers.taxes.local,
costCenter: bodyshop.md_responsibility_centers.taxes.local
},
state: {
center: bodyshop.md_responsibility_centers.taxes.state.name,
sale: Dinero(job.job_totals.totals.state_tax),
cost: Dinero(),
profitCenter: bodyshop.md_responsibility_centers.taxes.state,
costCenter: bodyshop.md_responsibility_centers.taxes.state
},
federal: {
center: bodyshop.md_responsibility_centers.taxes.federal.name,
sale: Dinero(job.job_totals.totals.federal_tax),
cost: Dinero(),
profitCenter: bodyshop.md_responsibility_centers.taxes.federal,
costCenter: bodyshop.md_responsibility_centers.taxes.federal
}
}),
rome: () => ({
tax_ty1: {
center: bodyshop.md_responsibility_centers.taxes[`tax_ty1`].name,
sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty1Tax`]),
cost: Dinero(),
profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty1`],
costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty1`]
},
tax_ty2: {
center: bodyshop.md_responsibility_centers.taxes[`tax_ty2`].name,
sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty2Tax`]),
cost: Dinero(),
profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty2`],
costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty2`]
},
tax_ty3: {
center: bodyshop.md_responsibility_centers.taxes[`tax_ty3`].name,
sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty3Tax`]),
cost: Dinero(),
profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty3`],
costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty3`]
},
tax_ty4: {
center: bodyshop.md_responsibility_centers.taxes[`tax_ty4`].name,
sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty4Tax`]),
cost: Dinero(),
profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty4`],
costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty4`]
},
tax_ty5: {
center: bodyshop.md_responsibility_centers.taxes[`tax_ty5`].name,
sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty5Tax`]),
cost: Dinero(),
profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty5`],
costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty5`]
}
})
});
//Determine if there are MAPA and MASH lines already on the estimate.
//If there are, don't do anything extra (mitchell estimate)
//Otherwise, calculate them and add them to the default MAPA and MASH centers.
let hasMapaLine = false;
let hasMashLine = false;
const profitCenterHash = job.joblines.reduce((acc, val) => {
//Check the Parts Assignment
if (val.db_ref === "936008") {
//If either of these DB REFs change, they also need to change in job-totals/job-costing calculations.
hasMapaLine = true;
}
if (val.db_ref === "936007") {
hasMashLine = true;
}
if (val.profitcenter_part) {
if (!acc[val.profitcenter_part]) acc[val.profitcenter_part] = Dinero();
let DineroAmount = Dinero({
amount: Math.round(val.act_price * 100)
}).multiply(val.part_qty || 1);
DineroAmount = DineroAmount.add(
((val.prt_dsmk_m && val.prt_dsmk_m !== 0) || (val.prt_dsmk_p && val.prt_dsmk_p !== 0)) &&
DiscountNotAlreadyCounted(val, job.joblines)
? val.prt_dsmk_m
? Dinero({ amount: Math.round(val.prt_dsmk_m * 100) })
: Dinero({
amount: Math.round(val.act_price * 100)
})
.multiply(val.part_qty || 0)
.percentage(Math.abs(val.prt_dsmk_p || 0))
.multiply(val.prt_dsmk_p > 0 ? 1 : -1)
: Dinero()
);
acc[val.profitcenter_part] = acc[val.profitcenter_part].add(DineroAmount);
}
if (val.profitcenter_labor && val.mod_lbr_ty) {
//Check the Labor Assignment.
if (!acc[val.profitcenter_labor]) acc[val.profitcenter_labor] = Dinero();
acc[val.profitcenter_labor] = acc[val.profitcenter_labor].add(
Dinero({
amount: Math.round(job[`rate_${val.mod_lbr_ty.toLowerCase()}`] * 100)
}).multiply(val.mod_lb_hrs)
);
}
return acc;
}, {});
const selectedDmsAllocationConfig = bodyshop.md_responsibility_centers.dms_defaults.find(
(d) => d.name === job.dms_allocation
);
CdkBase.createLogEvent(
socket,
"DEBUG",
`Using DMS Allocation ${selectedDmsAllocationConfig && selectedDmsAllocationConfig.name} for cost export.`
);
let costCenterHash = {};
//Check whether to skip this if PBS and using AP module.
const disablebillwip = !!bodyshop?.pbs_configuration?.disablebillwip;
if (!disablebillwip) {
costCenterHash = job.bills.reduce((bill_acc, bill_val) => {
bill_val.billlines.map((line_val) => {
if (!bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]])
bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]] = Dinero();
let lineDinero = Dinero({
amount: Math.round((line_val.actual_cost || 0) * 100)
})
.multiply(line_val.quantity)
.multiply(bill_val.is_credit_memo ? -1 : 1);
bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]] =
bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]].add(lineDinero);
return null;
});
return bill_acc;
}, {});
}
job.timetickets.forEach((ticket) => {
//Get the total amount of the ticket.
let TicketTotal = Dinero({
amount: Math.round(
ticket.rate *
(ticket.employee && ticket.employee.flat_rate ? ticket.productivehrs || 0 : ticket.actualhrs || 0) *
100
)
});
//Add it to the right cost center.
if (!costCenterHash[selectedDmsAllocationConfig.costs[ticket.ciecacode]])
costCenterHash[selectedDmsAllocationConfig.costs[ticket.ciecacode]] = Dinero();
costCenterHash[selectedDmsAllocationConfig.costs[ticket.ciecacode]] =
costCenterHash[selectedDmsAllocationConfig.costs[ticket.ciecacode]].add(TicketTotal);
});
if (!hasMapaLine && job.job_totals.rates.mapa.total.amount > 0) {
// console.log("Adding MAPA Line Manually.");
const mapaAccountName = selectedDmsAllocationConfig.profits.MAPA;
const mapaAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === mapaAccountName);
if (mapaAccount) {
if (!profitCenterHash[mapaAccountName]) profitCenterHash[mapaAccountName] = Dinero();
profitCenterHash[mapaAccountName] = profitCenterHash[mapaAccountName].add(
Dinero(job.job_totals.rates.mapa.total)
);
} else {
//console.log("NO MAPA ACCOUNT FOUND!!");
}
}
if (!hasMashLine && job.job_totals.rates.mash.total.amount > 0) {
// console.log("Adding MASH Line Manually.");
const mashAccountName = selectedDmsAllocationConfig.profits.MASH;
const mashAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === mashAccountName);
if (mashAccount) {
if (!profitCenterHash[mashAccountName]) profitCenterHash[mashAccountName] = Dinero();
profitCenterHash[mashAccountName] = profitCenterHash[mashAccountName].add(
Dinero(job.job_totals.rates.mash.total)
);
} else {
// console.log("NO MASH ACCOUNT FOUND!!");
}
}
console.log(
Number.isInteger(bodyshop?.cdk_configuration?.sendmaterialscosting),
typeof Number.isInteger(bodyshop?.cdk_configuration?.sendmaterialscosting)
);
if (!!bodyshop?.cdk_configuration?.sendmaterialscosting) {
//Manually send the percentage of the costing.
//Paint Mat
const mapaAccountName = selectedDmsAllocationConfig.costs.MAPA;
const mapaAccount = bodyshop.md_responsibility_centers.costs.find((c) => c.name === mapaAccountName);
if (mapaAccount) {
if (!costCenterHash[mapaAccountName])
costCenterHash[mapaAccountName] = Dinero();
if (job.bodyshop.use_paint_scale_data === true) {
if (job.mixdata.length > 0) {
costCenterHash[mapaAccountName] = costCenterHash[
mapaAccountName
].add(
Dinero({
amount: Math.round(
((job.mixdata[0] && job.mixdata[0].totalliquidcost) || 0) *
100
),
})
);
} else {
costCenterHash[mapaAccountName] = costCenterHash[
mapaAccountName
].add(
Dinero(job.job_totals.rates.mapa.total).percentage(
bodyshop?.cdk_configuration?.sendmaterialscosting
)
);
}
} else {
costCenterHash[mapaAccountName] = costCenterHash[mapaAccountName].add(
Dinero(job.job_totals.rates.mapa.total).percentage(
bodyshop?.cdk_configuration?.sendmaterialscosting
)
);
}
} else {
//console.log("NO MAPA ACCOUNT FOUND!!");
}
//Shop Mat
const mashAccountName = selectedDmsAllocationConfig.costs.MASH;
const mashAccount = bodyshop.md_responsibility_centers.costs.find((c) => c.name === mashAccountName);
if (mashAccount) {
if (!costCenterHash[mashAccountName]) costCenterHash[mashAccountName] = Dinero();
costCenterHash[mashAccountName] = costCenterHash[mashAccountName].add(
Dinero(job.job_totals.rates.mash.total).percentage(bodyshop?.cdk_configuration?.sendmaterialscosting)
);
} else {
// console.log("NO MASH ACCOUNT FOUND!!");
}
}
const { ca_bc_pvrt } = job;
if (ca_bc_pvrt) {
// const pvrtAccount = bodyshop.md_responsibility_centers.profits.find(
// (c) => c.name === mashAccountName
// );
taxAllocations.state.sale = taxAllocations.state.sale.add(
Dinero({ amount: Math.round((ca_bc_pvrt || 0) * 100) })
);
}
if (job.towing_payable && job.towing_payable !== 0) {
const towAccountName = selectedDmsAllocationConfig.profits.TOW;
const towAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === towAccountName);
if (towAccount) {
if (!profitCenterHash[towAccountName]) profitCenterHash[towAccountName] = Dinero();
profitCenterHash[towAccountName] = profitCenterHash[towAccountName].add(
Dinero({
amount: Math.round((job.towing_payable || 0) * 100)
})
);
} else {
// console.log("NO MASH ACCOUNT FOUND!!");
}
}
if (job.storage_payable && job.storage_payable !== 0) {
const storageAccountName = selectedDmsAllocationConfig.profits.TOW;
const towAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === storageAccountName);
if (towAccount) {
if (!profitCenterHash[storageAccountName]) profitCenterHash[storageAccountName] = Dinero();
profitCenterHash[storageAccountName] = profitCenterHash[storageAccountName].add(
Dinero({
amount: Math.round((job.storage_payable || 0) * 100)
})
);
} else {
// console.log("NO MASH ACCOUNT FOUND!!");
}
}
if (job.adjustment_bottom_line && job.adjustment_bottom_line !== 0) {
const otherAccountName = selectedDmsAllocationConfig.profits.PAO;
const otherAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === otherAccountName);
if (otherAccount) {
if (!profitCenterHash[otherAccountName]) profitCenterHash[otherAccountName] = Dinero();
profitCenterHash[otherAccountName] = profitCenterHash[otherAccountName].add(
Dinero({
amount: Math.round((job.adjustment_bottom_line || 0) * 100)
})
);
} else {
// console.log("NO MASH ACCOUNT FOUND!!");
}
}
if (InstanceManager({ rome: true })) {
//profile level adjustments
Object.keys(job.job_totals.parts.adjustments).forEach((key) => {
const accountName = selectedDmsAllocationConfig.profits[key];
const otherAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === accountName);
if (otherAccount) {
if (!profitCenterHash[accountName]) profitCenterHash[accountName] = Dinero();
profitCenterHash[accountName] = profitCenterHash[accountName].add(
Dinero(job.job_totals.parts.adjustments[key])
);
} else {
CdkBase.createLogEvent(
socket,
"ERROR",
`Error encountered in CdkCalculateAllocations. Unable to find adjustment account. ${error}`
);
}
});
}
const jobAllocations = _.union(Object.keys(profitCenterHash), Object.keys(costCenterHash)).map((key) => {
const profitCenter = bodyshop.md_responsibility_centers.profits.find((c) => c.name === key);
const costCenter = bodyshop.md_responsibility_centers.costs.find((c) => c.name === key);
return {
center: key,
sale: profitCenterHash[key] ? profitCenterHash[key] : Dinero(),
cost: costCenterHash[key] ? costCenterHash[key] : Dinero(),
profitCenter,
costCenter
};
});
return [
...jobAllocations,
...Object.keys(taxAllocations)
.filter((key) => taxAllocations[key].sale.getAmount() > 0 || taxAllocations[key].cost.getAmount() > 0)
.map((key) => {
if (
key === "federal" &&
selectedDmsAllocationConfig.gst_override &&
selectedDmsAllocationConfig.gst_override !== ""
) {
const ret = { ...taxAllocations[key], tax: key };
ret.costCenter.dms_acctnumber = selectedDmsAllocationConfig.gst_override;
ret.profitCenter.dms_acctnumber = selectedDmsAllocationConfig.gst_override;
return ret;
} else {
return { ...taxAllocations[key], tax: key };
}
})
];
} catch (error) { } catch (error) {
console.log(error); console.log(error);
CdkBase.createLogEvent(socket, "ERROR", `Error encountered in CdkCalculateAllocations. ${error}`); CdkBase.createLogEvent(socket, "ERROR", `Error encountered in CdkCalculateAllocations. ${error}`);
} }
}; };
async function QueryJobData(connectionData, token, jobid) { async function QueryJobData(socket, jobid) {
CdkBase.createLogEvent(connectionData, "DEBUG", `Querying job data for id ${jobid}`); CdkBase.createLogEvent(socket, "DEBUG", `Querying job data for id ${jobid}`);
const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {}); const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {});
const result = await client.setHeaders({ Authorization: token }).request(queries.GET_CDK_ALLOCATIONS, { id: jobid }); const result = await client
CdkBase.createLogEvent(connectionData, "TRACE", `Job data query result ${JSON.stringify(result, null, 2)}`); .setHeaders({ Authorization: `Bearer ${socket.handshake.auth.token}` })
.request(queries.GET_CDK_ALLOCATIONS, { id: jobid });
CdkBase.createLogEvent(socket, "TRACE", `Job data query result ${JSON.stringify(result, null, 2)}`);
return result.jobs_by_pk; return result.jobs_by_pk;
} }
function calculateAllocations(connectionData, job) {
const { bodyshop } = job;
const taxAllocations = InstanceManager({
executeFunction: true,
deubg: true,
args: [],
imex: () => ({
local: {
center: bodyshop.md_responsibility_centers.taxes.local.name,
sale: Dinero(job.job_totals.totals.local_tax),
cost: Dinero(),
profitCenter: bodyshop.md_responsibility_centers.taxes.local,
costCenter: bodyshop.md_responsibility_centers.taxes.local
},
state: {
center: bodyshop.md_responsibility_centers.taxes.state.name,
sale: Dinero(job.job_totals.totals.state_tax),
cost: Dinero(),
profitCenter: bodyshop.md_responsibility_centers.taxes.state,
costCenter: bodyshop.md_responsibility_centers.taxes.state
},
federal: {
center: bodyshop.md_responsibility_centers.taxes.federal.name,
sale: Dinero(job.job_totals.totals.federal_tax),
cost: Dinero(),
profitCenter: bodyshop.md_responsibility_centers.taxes.federal,
costCenter: bodyshop.md_responsibility_centers.taxes.federal
}
}),
rome: () => ({
tax_ty1: {
center: bodyshop.md_responsibility_centers.taxes[`tax_ty1`].name,
sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty1Tax`]),
cost: Dinero(),
profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty1`],
costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty1`]
},
tax_ty2: {
center: bodyshop.md_responsibility_centers.taxes[`tax_ty2`].name,
sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty2Tax`]),
cost: Dinero(),
profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty2`],
costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty2`]
},
tax_ty3: {
center: bodyshop.md_responsibility_centers.taxes[`tax_ty3`].name,
sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty3Tax`]),
cost: Dinero(),
profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty3`],
costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty3`]
},
tax_ty4: {
center: bodyshop.md_responsibility_centers.taxes[`tax_ty4`].name,
sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty4Tax`]),
cost: Dinero(),
profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty4`],
costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty4`]
},
tax_ty5: {
center: bodyshop.md_responsibility_centers.taxes[`tax_ty5`].name,
sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty5Tax`]),
cost: Dinero(),
profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty5`],
costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty5`]
}
})
});
//Determine if there are MAPA and MASH lines already on the estimate.
//If there are, don't do anything extra (mitchell estimate)
//Otherwise, calculate them and add them to the default MAPA and MASH centers.
let hasMapaLine = false;
let hasMashLine = false;
const profitCenterHash = job.joblines.reduce((acc, val) => {
//Check the Parts Assignment
if (val.db_ref === "936008") {
//If either of these DB REFs change, they also need to change in job-totals/job-costing calculations.
hasMapaLine = true;
}
if (val.db_ref === "936007") {
hasMashLine = true;
}
if (val.profitcenter_part) {
if (!acc[val.profitcenter_part]) acc[val.profitcenter_part] = Dinero();
let DineroAmount = Dinero({
amount: Math.round(val.act_price * 100)
}).multiply(val.part_qty || 1);
DineroAmount = DineroAmount.add(
((val.prt_dsmk_m && val.prt_dsmk_m !== 0) || (val.prt_dsmk_p && val.prt_dsmk_p !== 0)) &&
DiscountNotAlreadyCounted(val, job.joblines)
? val.prt_dsmk_m
? Dinero({ amount: Math.round(val.prt_dsmk_m * 100) })
: Dinero({
amount: Math.round(val.act_price * 100)
})
.multiply(val.part_qty || 0)
.percentage(Math.abs(val.prt_dsmk_p || 0))
.multiply(val.prt_dsmk_p > 0 ? 1 : -1)
: Dinero()
);
acc[val.profitcenter_part] = acc[val.profitcenter_part].add(DineroAmount);
}
if (val.profitcenter_labor && val.mod_lbr_ty) {
//Check the Labor Assignment.
if (!acc[val.profitcenter_labor]) acc[val.profitcenter_labor] = Dinero();
acc[val.profitcenter_labor] = acc[val.profitcenter_labor].add(
Dinero({
amount: Math.round(job[`rate_${val.mod_lbr_ty.toLowerCase()}`] * 100)
}).multiply(val.mod_lb_hrs)
);
}
return acc;
}, {});
const selectedDmsAllocationConfig = bodyshop.md_responsibility_centers.dms_defaults.find(
(d) => d.name === job.dms_allocation
);
CdkBase.createLogEvent(
connectionData,
"DEBUG",
`Using DMS Allocation ${selectedDmsAllocationConfig && selectedDmsAllocationConfig.name} for cost export.`
);
let costCenterHash = {};
//Check whether to skip this if PBS and using AP module.
const disablebillwip = !!bodyshop?.pbs_configuration?.disablebillwip;
if (!disablebillwip) {
costCenterHash = job.bills.reduce((bill_acc, bill_val) => {
bill_val.billlines.map((line_val) => {
if (!bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]])
bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]] = Dinero();
let lineDinero = Dinero({
amount: Math.round((line_val.actual_cost || 0) * 100)
})
.multiply(line_val.quantity)
.multiply(bill_val.is_credit_memo ? -1 : 1);
bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]] =
bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]].add(lineDinero);
return null;
});
return bill_acc;
}, {});
}
job.timetickets.forEach((ticket) => {
//Get the total amount of the ticket.
let TicketTotal = Dinero({
amount: Math.round(
ticket.rate *
(ticket.employee && ticket.employee.flat_rate ? ticket.productivehrs || 0 : ticket.actualhrs || 0) *
100
)
});
//Add it to the right cost center.
if (!costCenterHash[selectedDmsAllocationConfig.costs[ticket.ciecacode]])
costCenterHash[selectedDmsAllocationConfig.costs[ticket.ciecacode]] = Dinero();
costCenterHash[selectedDmsAllocationConfig.costs[ticket.ciecacode]] =
costCenterHash[selectedDmsAllocationConfig.costs[ticket.ciecacode]].add(TicketTotal);
});
if (!hasMapaLine && job.job_totals.rates.mapa.total.amount > 0) {
// console.log("Adding MAPA Line Manually.");
const mapaAccountName = selectedDmsAllocationConfig.profits.MAPA;
const mapaAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === mapaAccountName);
if (mapaAccount) {
if (!profitCenterHash[mapaAccountName]) profitCenterHash[mapaAccountName] = Dinero();
profitCenterHash[mapaAccountName] = profitCenterHash[mapaAccountName].add(
Dinero(job.job_totals.rates.mapa.total)
);
} else {
//console.log("NO MAPA ACCOUNT FOUND!!");
}
}
if (!hasMashLine && job.job_totals.rates.mash.total.amount > 0) {
// console.log("Adding MASH Line Manually.");
const mashAccountName = selectedDmsAllocationConfig.profits.MASH;
const mashAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === mashAccountName);
if (mashAccount) {
if (!profitCenterHash[mashAccountName]) profitCenterHash[mashAccountName] = Dinero();
profitCenterHash[mashAccountName] = profitCenterHash[mashAccountName].add(
Dinero(job.job_totals.rates.mash.total)
);
} else {
// console.log("NO MASH ACCOUNT FOUND!!");
}
}
// console.log(
// Number.isInteger(bodyshop?.cdk_configuration?.sendmaterialscosting),
// typeof Number.isInteger(bodyshop?.cdk_configuration?.sendmaterialscosting)
// );
if (!!bodyshop?.cdk_configuration?.sendmaterialscosting) {
//Manually send the percentage of the costing.
//Paint Mat
const mapaAccountName = selectedDmsAllocationConfig.costs.MAPA;
const mapaAccount = bodyshop.md_responsibility_centers.costs.find((c) => c.name === mapaAccountName);
if (mapaAccount) {
if (!costCenterHash[mapaAccountName]) costCenterHash[mapaAccountName] = Dinero();
if (job.bodyshop.use_paint_scale_data === true) {
if (job.mixdata.length > 0) {
costCenterHash[mapaAccountName] = costCenterHash[mapaAccountName].add(
Dinero({
amount: Math.round(((job.mixdata[0] && job.mixdata[0].totalliquidcost) || 0) * 100)
})
);
} else {
costCenterHash[mapaAccountName] = costCenterHash[mapaAccountName].add(
Dinero(job.job_totals.rates.mapa.total).percentage(bodyshop?.cdk_configuration?.sendmaterialscosting)
);
}
} else {
costCenterHash[mapaAccountName] = costCenterHash[mapaAccountName].add(
Dinero(job.job_totals.rates.mapa.total).percentage(bodyshop?.cdk_configuration?.sendmaterialscosting)
);
}
} else {
//console.log("NO MAPA ACCOUNT FOUND!!");
}
//Shop Mat
const mashAccountName = selectedDmsAllocationConfig.costs.MASH;
const mashAccount = bodyshop.md_responsibility_centers.costs.find((c) => c.name === mashAccountName);
if (mashAccount) {
if (!costCenterHash[mashAccountName]) costCenterHash[mashAccountName] = Dinero();
costCenterHash[mashAccountName] = costCenterHash[mashAccountName].add(
Dinero(job.job_totals.rates.mash.total).percentage(bodyshop?.cdk_configuration?.sendmaterialscosting)
);
} else {
// console.log("NO MASH ACCOUNT FOUND!!");
}
}
const { ca_bc_pvrt } = job;
if (ca_bc_pvrt) {
// const pvrtAccount = bodyshop.md_responsibility_centers.profits.find(
// (c) => c.name === mashAccountName
// );
taxAllocations.state.sale = taxAllocations.state.sale.add(Dinero({ amount: Math.round((ca_bc_pvrt || 0) * 100) }));
}
if (job.towing_payable && job.towing_payable !== 0) {
const towAccountName = selectedDmsAllocationConfig.profits.TOW;
const towAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === towAccountName);
if (towAccount) {
if (!profitCenterHash[towAccountName]) profitCenterHash[towAccountName] = Dinero();
profitCenterHash[towAccountName] = profitCenterHash[towAccountName].add(
Dinero({
amount: Math.round((job.towing_payable || 0) * 100)
})
);
} else {
// console.log("NO MASH ACCOUNT FOUND!!");
}
}
if (job.storage_payable && job.storage_payable !== 0) {
const storageAccountName = selectedDmsAllocationConfig.profits.TOW;
const towAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === storageAccountName);
if (towAccount) {
if (!profitCenterHash[storageAccountName]) profitCenterHash[storageAccountName] = Dinero();
profitCenterHash[storageAccountName] = profitCenterHash[storageAccountName].add(
Dinero({
amount: Math.round((job.storage_payable || 0) * 100)
})
);
} else {
// console.log("NO MASH ACCOUNT FOUND!!");
}
}
if (job.adjustment_bottom_line && job.adjustment_bottom_line !== 0) {
const otherAccountName = selectedDmsAllocationConfig.profits.PAO;
const otherAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === otherAccountName);
if (otherAccount) {
if (!profitCenterHash[otherAccountName]) profitCenterHash[otherAccountName] = Dinero();
profitCenterHash[otherAccountName] = profitCenterHash[otherAccountName].add(
Dinero({
amount: Math.round((job.adjustment_bottom_line || 0) * 100)
})
);
} else {
// console.log("NO MASH ACCOUNT FOUND!!");
}
}
if (InstanceManager({ rome: true })) {
//profile level adjustments for parts
Object.keys(job.job_totals.parts.adjustments).forEach((key) => {
const accountName = selectedDmsAllocationConfig.profits[key];
const otherAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === accountName);
if (otherAccount) {
if (!profitCenterHash[accountName]) profitCenterHash[accountName] = Dinero();
profitCenterHash[accountName] = profitCenterHash[accountName].add(
Dinero(job.job_totals.parts.adjustments[key])
);
} else {
CdkBase.createLogEvent(
connectionData,
"ERROR",
`Error encountered in CdkCalculateAllocations. Unable to find adjustment account. ${error}`
);
}
});
//profile level adjustments for labor and materials
Object.keys(job.job_totals.rates).forEach((key) => {
if (job.job_totals.rates[key] && job.job_totals.rates[key].adjustment && Dinero(job.job_totals.rates[key].adjustment).isZero() === false) {
const accountName = selectedDmsAllocationConfig.profits[key.toUpperCase()];
const otherAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === accountName);
if (otherAccount) {
if (!profitCenterHash[accountName]) profitCenterHash[accountName] = Dinero();
profitCenterHash[accountName] = profitCenterHash[accountName].add(Dinero(job.job_totals.rates[key].adjustments));
} else {
CdkBase.createLogEvent(
connectionData,
"ERROR",
`Error encountered in CdkCalculateAllocations. Unable to find adjustment account. ${error}`
);
}
}
});
}
const jobAllocations = _.union(Object.keys(profitCenterHash), Object.keys(costCenterHash)).map((key) => {
const profitCenter = bodyshop.md_responsibility_centers.profits.find((c) => c.name === key);
const costCenter = bodyshop.md_responsibility_centers.costs.find((c) => c.name === key);
return {
center: key,
sale: profitCenterHash[key] ? profitCenterHash[key] : Dinero(),
cost: costCenterHash[key] ? costCenterHash[key] : Dinero(),
profitCenter,
costCenter
};
});
return [
...jobAllocations,
...Object.keys(taxAllocations)
.filter((key) => taxAllocations[key].sale.getAmount() > 0 || taxAllocations[key].cost.getAmount() > 0)
.map((key) => {
if (
key === "federal" &&
selectedDmsAllocationConfig.gst_override &&
selectedDmsAllocationConfig.gst_override !== ""
) {
const ret = { ...taxAllocations[key], tax: key };
ret.costCenter.dms_acctnumber = selectedDmsAllocationConfig.gst_override;
ret.profitCenter.dms_acctnumber = selectedDmsAllocationConfig.gst_override;
return ret;
} else {
return { ...taxAllocations[key], tax: key };
}
})
];
}

View File

@@ -211,8 +211,6 @@ const CreateRepairOrderTag = (job, errorCallback) => {
} }
const repairCosts = CreateCosts(job); const repairCosts = CreateCosts(job);
const jobline = CreateJobLines(job.joblines);
const timeticket = CreateTimeTickets(job.timetickets);
try { try {
const ret = { const ret = {
@@ -244,7 +242,6 @@ const CreateRepairOrderTag = (job, errorCallback) => {
}, },
InsuranceCompany: job.ins_co_nm || "", InsuranceCompany: job.ins_co_nm || "",
Claim: job.clm_no || "", Claim: job.clm_no || "",
DMSAllocation: job.dms_allocation || "",
Contacts: { Contacts: {
CSR: job.employee_csr_rel CSR: job.employee_csr_rel
? `${ ? `${
@@ -279,11 +276,8 @@ const CreateRepairOrderTag = (job, errorCallback) => {
DateInvoiced: DateInvoiced:
(job.date_invoiced && moment(job.date_invoiced).tz(job.bodyshop.timezone).format(DateFormat)) || "", (job.date_invoiced && moment(job.date_invoiced).tz(job.bodyshop.timezone).format(DateFormat)) || "",
DateExported: DateExported:
(job.date_exported && moment(job.date_exported).tz(job.bodyshop.timezone).format(DateFormat)) || "", (job.date_exported && moment(job.date_exported).tz(job.bodyshop.timezone).format(DateFormat)) || ""
DateVoid: (job.date_void && moment(job.date_void).tz(job.bodyshop.timezone).format(DateFormat)) || ""
}, },
JobLineDetails: { jobline },
TimeTicketDetails: { timeticket },
Sales: { Sales: {
Labour: { Labour: {
Aluminum: Dinero(job.job_totals.rates.laa.total).toFormat(DineroFormat), Aluminum: Dinero(job.job_totals.rates.laa.total).toFormat(DineroFormat),
@@ -631,42 +625,3 @@ const CreateCosts = (job) => {
}, 0) }, 0)
}; };
}; };
const CreateJobLines = (joblines) => {
const repairLines = [];
joblines.forEach((jobline) => {
repairLines.push({
line_description: jobline.line_desc,
oem_part_no: jobline.oem_partno,
alt_part_no: jobline.alt_partno,
op_code_desc: jobline.op_code_desc,
part_type: jobline.part_type,
part_qty: jobline.part_qty,
part_price: jobline.act_price,
labor_type: jobline.mod_lbr_ty,
labor_hours: jobline.mod_lb_hrs,
labor_sale: jobline.lbr_amt
});
});
return repairLines;
};
const CreateTimeTickets = (timetickets) => {
const timeTickets = [];
timetickets.forEach((ticket) => {
timeTickets.push({
date: ticket.date,
employee: ticket.employee.employee_number
.trim()
.concat(" - ", ticket.employee.first_name.trim(), " ", ticket.employee.last_name.trim())
.trim(),
productive_hrs: ticket.productivehrs,
actual_hrs: ticket.actualhrs,
cost_center: ticket.cost_center,
flat_rate: ticket.flat_rate,
rate: ticket.rate,
ticket_cost: ticket.flat_rate ? ticket.rate * ticket.productive_hrs : ticket.rate * ticket.actual_hrs
});
});
return timeTickets;
};

View File

@@ -1113,7 +1113,7 @@ exports.KAIZEN_QUERY = `query KAIZEN_EXPORT($start: timestamptz, $bodyshopid: uu
use_paint_scale_data use_paint_scale_data
timezone timezone
} }
jobs(where: {_and: [{updated_at: {_gt: $start}}, {updated_at: {_lte: $end}}, {converted: {_eq: true}}, {shopid: {_eq: $bodyshopid}}]}) { jobs(where: {_and: [{updated_at: {_gt: $start}}, {updated_at: {_lte: $end}}, {shopid: {_eq: $bodyshopid}}]}) {
actual_completion actual_completion
actual_delivery actual_delivery
actual_in actual_in
@@ -1138,8 +1138,6 @@ exports.KAIZEN_QUERY = `query KAIZEN_EXPORT($start: timestamptz, $bodyshopid: uu
date_invoiced date_invoiced
date_open date_open
date_repairstarted date_repairstarted
date_void
dms_allocation
employee_body_rel { employee_body_rel {
first_name first_name
last_name last_name
@@ -1170,7 +1168,6 @@ exports.KAIZEN_QUERY = `query KAIZEN_EXPORT($start: timestamptz, $bodyshopid: uu
ins_co_nm ins_co_nm
joblines(where: {removed: {_eq: false}}) { joblines(where: {removed: {_eq: false}}) {
act_price act_price
alt_partno
billlines(order_by: {bill: {date: desc_nulls_last}} limit: 1) { billlines(order_by: {bill: {date: desc_nulls_last}} limit: 1) {
actual_cost actual_cost
actual_price actual_price
@@ -1185,15 +1182,12 @@ exports.KAIZEN_QUERY = `query KAIZEN_EXPORT($start: timestamptz, $bodyshopid: uu
} }
db_price db_price
id id
lbr_amt
lbr_op lbr_op
line_desc line_desc
line_ind line_ind
line_no line_no
mod_lb_hrs mod_lb_hrs
mod_lbr_ty mod_lbr_ty
oem_partno
op_code_desc
parts_order_lines(order_by: {parts_order: {order_date: desc_nulls_last}} limit: 1){ parts_order_lines(order_by: {parts_order: {order_date: desc_nulls_last}} limit: 1){
parts_order{ parts_order{
id id
@@ -1206,6 +1200,7 @@ exports.KAIZEN_QUERY = `query KAIZEN_EXPORT($start: timestamptz, $bodyshopid: uu
profitcenter_labor profitcenter_labor
prt_dsmk_m prt_dsmk_m
prt_dsmk_p prt_dsmk_p
oem_partno
status status
} }
job_totals job_totals
@@ -1256,18 +1251,12 @@ exports.KAIZEN_QUERY = `query KAIZEN_EXPORT($start: timestamptz, $bodyshopid: uu
scheduled_in scheduled_in
status status
timetickets { timetickets {
actualhrs
cost_center
date
employee {
employee_number
first_name
last_name
}
flat_rate
id id
productivehrs
rate rate
cost_center
actualhrs
productivehrs
flat_rate
} }
tlos_ind tlos_ind
v_color v_color
@@ -1527,8 +1516,6 @@ exports.QUERY_JOB_COSTING_DETAILS = ` query QUERY_JOB_COSTING_DETAILS($id: uuid!
ca_bc_pvrt ca_bc_pvrt
ca_customer_gst ca_customer_gst
dms_allocation dms_allocation
cieca_pfl
materials
joblines(where: { removed: { _eq: false } }) { joblines(where: { removed: { _eq: false } }) {
id id
db_ref db_ref
@@ -1643,8 +1630,6 @@ exports.QUERY_JOB_COSTING_DETAILS_MULTI = ` query QUERY_JOB_COSTING_DETAILS_MULT
ca_bc_pvrt ca_bc_pvrt
ca_customer_gst ca_customer_gst
dms_allocation dms_allocation
cieca_pfl
materials
joblines(where: {removed: {_eq: false}}) { joblines(where: {removed: {_eq: false}}) {
id id
db_ref db_ref
@@ -1870,8 +1855,6 @@ exports.GET_CDK_ALLOCATIONS = `query QUERY_JOB_CLOSE_DETAILS($id: uuid!) {
scheduled_in scheduled_in
actual_in actual_in
ca_bc_pvrt ca_bc_pvrt
cieca_pfl
materials
timetickets { timetickets {
id id
actualhrs actualhrs
@@ -2498,6 +2481,7 @@ query QUERY_TASK_BY_ID($id: uuid!) {
`; `;
exports.GET_JOBS_BY_PKS = `query GET_JOBS_BY_PKS($ids: [uuid!]!) { exports.GET_JOBS_BY_PKS = `query GET_JOBS_BY_PKS($ids: [uuid!]!) {
jobs(where: {id: {_in: $ids}}) { jobs(where: {id: {_in: $ids}}) {
id id

View File

@@ -286,45 +286,9 @@ function GenerateCostingData(job) {
const rateName = `rate_${(val.mod_lbr_ty || "").toLowerCase()}`; const rateName = `rate_${(val.mod_lbr_ty || "").toLowerCase()}`;
let laborAmount = Dinero(); const laborAmount = Dinero({
laborAmount = Dinero({
amount: Math.round((job[rateName] || 0) * 100) amount: Math.round((job[rateName] || 0) * 100)
}).multiply(val.mod_lb_hrs || 0); }).multiply(val.mod_lb_hrs || 0);
if (
job.cieca_pfl &&
job.cieca_pfl[val.mod_lbr_ty.toUpperCase()] &&
job.cieca_pfl[val.mod_lbr_ty.toUpperCase()].lbr_adjp !== 0
) {
let adjp = 0;
if (
val.mod_lbr_ty === "la1" ||
val.mod_lbr_ty === "la2" ||
val.mod_lbr_ty === "la3" ||
val.mod_lbr_ty === "la4"
) {
adjp =
Math.abs(job.cieca_pfl["LAU"].lbr_adjp) > 1
? job.cieca_pfl["LAU"].lbr_adjp
: job.cieca_pfl["LAU"].lbr_adjp * 100; //Adjust lbr_adjp to whole number
} else {
if (job.cieca_pfl[val.mod_lbr_ty.toUpperCase()]) {
adjp =
Math.abs(job.cieca_pfl[val.mod_lbr_ty.toUpperCase()].lbr_adjp) > 1
? job.cieca_pfl[val.mod_lbr_ty.toUpperCase()].lbr_adjp
: job.cieca_pfl[val.mod_lbr_ty.toUpperCase()].lbr_adjp * 100; //Adjust lbr_adjp to whole number
} else {
adjp =
Math.abs(job.cieca_pfl["LAB"].lbr_adjp) > 1
? job.cieca_pfl["LAB"].lbr_adjp
: job.cieca_pfl["LAB"].lbr_adjp * 100; //Adjust lbr_adjp to whole number
}
}
laborAmount = laborAmount.add(
laborAmount.percentage(adjp < 0 ? adjp * -1 : adjp).multiply(adjp < 0 ? -1 : 1)
);
}
if (!acc.labor[laborProfitCenter]) acc.labor[laborProfitCenter] = Dinero(); if (!acc.labor[laborProfitCenter]) acc.labor[laborProfitCenter] = Dinero();
acc.labor[laborProfitCenter] = acc.labor[laborProfitCenter].add(laborAmount); acc.labor[laborProfitCenter] = acc.labor[laborProfitCenter].add(laborAmount);
@@ -353,10 +317,8 @@ function GenerateCostingData(job) {
if (!partsProfitCenter) if (!partsProfitCenter)
console.log("Unknown cost/profit center mapping for parts.", val.line_desc, val.part_type); console.log("Unknown cost/profit center mapping for parts.", val.line_desc, val.part_type);
let partsAmount = Dinero({ const partsAmount = Dinero({
amount: val.act_price_before_ppc amount: val.act_price_before_ppc ? Math.round(val.act_price_before_ppc * 100) : Math.round(val.act_price * 100)
? Math.round(val.act_price_before_ppc * 100)
: Math.round(val.act_price * 100)
}) })
.multiply(val.part_qty || 1) .multiply(val.part_qty || 1)
.add( .add(
@@ -365,42 +327,13 @@ function GenerateCostingData(job) {
? val.prt_dsmk_m ? val.prt_dsmk_m
? Dinero({ amount: Math.round(val.prt_dsmk_m * 100) }) ? Dinero({ amount: Math.round(val.prt_dsmk_m * 100) })
: Dinero({ : Dinero({
amount: val.act_price_before_ppc amount: val.act_price_before_ppc ? Math.round(val.act_price_before_ppc * 100) : Math.round(val.act_price * 100)
? Math.round(val.act_price_before_ppc * 100)
: Math.round(val.act_price * 100)
}) })
.multiply(val.part_qty || 0) .multiply(val.part_qty || 0)
.percentage(Math.abs(val.prt_dsmk_p || 0)) .percentage(Math.abs(val.prt_dsmk_p || 0))
.multiply(val.prt_dsmk_p > 0 ? 1 : -1) .multiply(val.prt_dsmk_p > 0 ? 1 : -1)
: Dinero() : Dinero()
); );
// Profile Discount for Parts
if (job.parts_tax_rates && job.parts_tax_rates[val.part_type.toUpperCase()]) {
if (
job.parts_tax_rates[val.part_type.toUpperCase()].prt_discp !== undefined &&
job.parts_tax_rates[val.part_type.toUpperCase()].prt_discp >= 0
) {
const discountRate =
Math.abs(job.parts_tax_rates[val.part_type.toUpperCase()].prt_discp) > 1
? parts_tajob.parts_tax_rates_rates[val.part_type.toUpperCase()].prt_discp
: job.parts_tax_rates[val.part_type.toUpperCase()].prt_discp * 100;
const disc = partsAmount.percentage(discountRate).multiply(-1);
partsAmount = partsAmount.add(disc);
}
if (
job.parts_tax_rates[val.part_type.toUpperCase()].prt_mkupp !== undefined &&
job.parts_tax_rates[val.part_type.toUpperCase()].prt_mkupp >= 0
) {
const markupRate =
Math.abs(job.parts_tax_rates[val.part_type.toUpperCase()].prt_mkupp) > 1
? job.parts_tax_rates[val.part_type.toUpperCase()].prt_mkupp
: job.parts_tax_rates[val.part_type.toUpperCase()].prt_mkupp * 100;
const markup = partsAmount.percentage(markupRate);
partsAmount = partsAmount.add(markup);
}
}
if (!acc.parts[partsProfitCenter]) acc.parts[partsProfitCenter] = Dinero(); if (!acc.parts[partsProfitCenter]) acc.parts[partsProfitCenter] = Dinero();
acc.parts[partsProfitCenter] = acc.parts[partsProfitCenter].add(partsAmount); acc.parts[partsProfitCenter] = acc.parts[partsProfitCenter].add(partsAmount);
} }
@@ -435,10 +368,7 @@ function GenerateCostingData(job) {
} }
//Additional Profit Center //Additional Profit Center
if ( if ((!val.part_type && !val.mod_lbr_ty) || (!val.part_type && val.mod_lbr_ty)) {
(!val.part_type && !val.mod_lbr_ty) ||
(!val.part_type && val.mod_lbr_ty && val.act_price > 0 && val.lbr_op !== "OP14")
) {
//Does it already have a defined profit center? //Does it already have a defined profit center?
//If so, use it, otherwise try to use the same from the auto-allocate logic in IO app jobs-close-auto-allocate. //If so, use it, otherwise try to use the same from the auto-allocate logic in IO app jobs-close-auto-allocate.
const partsProfitCenter = val.profitcenter_part || getAdditionalCostCenter(val, defaultProfits) || "Unknown"; const partsProfitCenter = val.profitcenter_part || getAdditionalCostCenter(val, defaultProfits) || "Unknown";
@@ -476,7 +406,6 @@ function GenerateCostingData(job) {
if (!hasMapaLine) { if (!hasMapaLine) {
if (!jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]]) if (!jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]])
jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]] = Dinero(); jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]] = Dinero();
jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]] = jobLineTotalsByProfitCenter.additional[ jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]] = jobLineTotalsByProfitCenter.additional[
defaultProfits["MAPA"] defaultProfits["MAPA"]
].add( ].add(
@@ -484,26 +413,10 @@ function GenerateCostingData(job) {
amount: Math.round((job.rate_mapa || 0) * 100) amount: Math.round((job.rate_mapa || 0) * 100)
}).multiply(materialsHours.mapaHrs || 0) }).multiply(materialsHours.mapaHrs || 0)
); );
let adjp = 0;
if (job.materials["MAPA"] && job.materials["MAPA"].mat_adjp) {
adjp =
Math.abs(job.materials["MAPA"].mat_adjp) > 1
? job.materials["MAPA"].mat_adjp
: job.materials["MAPA"].mat_adjp * 100; //Adjust mat_adjp to whole number
}
jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]] = jobLineTotalsByProfitCenter.additional[
defaultProfits["MAPA"]
].add(
jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]]
.percentage(adjp < 0 ? adjp * -1 : adjp)
.multiply(adjp < 0 ? -1 : 1)
);
} }
if (!hasMashLine) { if (!hasMashLine) {
if (!jobLineTotalsByProfitCenter.additional[defaultProfits["MASH"]]) if (!jobLineTotalsByProfitCenter.additional[defaultProfits["MASH"]])
jobLineTotalsByProfitCenter.additional[defaultProfits["MASH"]] = Dinero(); jobLineTotalsByProfitCenter.additional[defaultProfits["MASH"]] = Dinero();
jobLineTotalsByProfitCenter.additional[defaultProfits["MASH"]] = jobLineTotalsByProfitCenter.additional[ jobLineTotalsByProfitCenter.additional[defaultProfits["MASH"]] = jobLineTotalsByProfitCenter.additional[
defaultProfits["MASH"] defaultProfits["MASH"]
].add( ].add(
@@ -511,21 +424,6 @@ function GenerateCostingData(job) {
amount: Math.round((job.rate_mash || 0) * 100) amount: Math.round((job.rate_mash || 0) * 100)
}).multiply(materialsHours.mashHrs || 0) }).multiply(materialsHours.mashHrs || 0)
); );
let adjp = 0;
if (job.materials["MASH"] && job.materials["MASH"].mat_adjp) {
adjp =
Math.abs(job.materials["MASH"].mat_adjp) > 1
? job.materials["MASH"].mat_adjp
: job.materials["MASH"].mat_adjp * 100; //Adjust mat_adjp to whole number
}
jobLineTotalsByProfitCenter.additional[defaultProfits["MASH"]] = jobLineTotalsByProfitCenter.additional[
defaultProfits["MASH"]
].add(
jobLineTotalsByProfitCenter.additional[defaultProfits["MASH"]]
.percentage(adjp < 0 ? adjp * -1 : adjp)
.multiply(adjp < 0 ? -1 : 1)
);
} }
//Is it a DMS Setup? //Is it a DMS Setup?

View File

@@ -331,8 +331,6 @@ async function CalculateRatesTotals({ job, client }) {
//Skip calculating mapa and mash if we got the amounts. //Skip calculating mapa and mash if we got the amounts.
if (!((property === "mapa" && hasMapaLine) || (property === "mash" && hasMashLine))) { if (!((property === "mapa" && hasMapaLine) || (property === "mash" && hasMashLine))) {
if (!ret[property].total) { if (!ret[property].total) {
ret[property].base = Dinero();
ret[property].adjustment = Dinero();
ret[property].total = Dinero(); ret[property].total = Dinero();
} }
let threshold; let threshold;
@@ -351,50 +349,13 @@ async function CalculateRatesTotals({ job, client }) {
} }
} }
const base = Dinero({ const total = Dinero({
amount: Math.round((ret[property].rate || 0) * 100) amount: Math.round((ret[property].rate || 0) * 100)
}).multiply(ret[property].hours); }).multiply(ret[property].hours);
let adjp = 0;
if (property === "mapa" || property === "mash") {
if (job.materials[property.toUpperCase()] && job.materials[property.toUpperCase()].mat_adjp) {
adjp =
Math.abs(job.materials[property.toUpperCase()].mat_adjp) > 1
? job.materials[property.toUpperCase()].mat_adjp
: job.materials[property.toUpperCase()].mat_adjp * 100; //Adjust mat_adjp to whole number
}
} else {
if (property === "la1" || property === "la2" || property === "la3" || property === "la4") {
if (job.cieca_pfl["LAU"] && job.cieca_pfl["LAU"].lbr_adjp) {
adjp =
Math.abs(job.cieca_pfl["LAU"].lbr_adjp) > 1
? job.cieca_pfl["LAU"].lbr_adjp
: job.cieca_pfl["LAU"].lbr_adjp * 100; //Adjust lbr_adjp to whole number
}
} else {
if (job.cieca_pfl[property.toUpperCase()] && job.cieca_pfl[property.toUpperCase()].lbr_adjp) {
adjp =
Math.abs(job.cieca_pfl[property.toUpperCase()].lbr_adjp) > 1
? job.cieca_pfl[property.toUpperCase()].lbr_adjp
: job.cieca_pfl[property.toUpperCase()].lbr_adjp * 100; //Adjust lbr_adjp to whole number
} else {
if (job.cieca_pfl["LAB"].lbr_adjp) {
adjp =
Math.abs(job.cieca_pfl["LAB"].lbr_adjp) > 1
? job.cieca_pfl["LAB"].lbr_adjp
: job.cieca_pfl["LAB"].lbr_adjp * 100; //Adjust lbr_adjp to whole number
}
}
}
}
const adjustment = base.percentage(adjp < 0 ? adjp * -1 : adjp).multiply(adjp < 0 ? -1 : 1);
const total = base.add(adjustment);
if (threshold && total.greaterThanOrEqual(threshold)) { if (threshold && total.greaterThanOrEqual(threshold)) {
ret[property].total = ret[property].total.add(threshold); ret[property].total = ret[property].total.add(threshold);
} else { } else {
ret[property].base = ret[property].base.add(base);
ret[property].adjustment = ret[property].adjustment.add(adjustment);
ret[property].total = ret[property].total.add(total); ret[property].total = ret[property].total.add(total);
} }
} }
@@ -682,7 +643,7 @@ function CalculateAdditional(job) {
additionalCosts: null, additionalCosts: null,
additionalCostItems: [], additionalCostItems: [],
adjustments: null, adjustments: null,
towing: Dinero(), towing: null,
shipping: Dinero(), shipping: Dinero(),
storage: null, storage: null,
pvrt: null, pvrt: null,
@@ -707,7 +668,7 @@ function CalculateAdditional(job) {
} }
if (val.line_desc.toLowerCase().includes("towing")) { if (val.line_desc.toLowerCase().includes("towing")) {
ret.towing = ret.towing.add(lineValue); ret.towing = lineValue;
return acc; return acc;
} else { } else {
ret.additionalCostItems.push({ key: val.line_desc, total: lineValue }); ret.additionalCostItems.push({ key: val.line_desc, total: lineValue });
@@ -742,19 +703,18 @@ function CalculateTaxesTotals(job, otherTotals) {
//Potential issue here with Sublet Calculation. Sublets are calculated under labor in Mitchell, but it's done in IO //Potential issue here with Sublet Calculation. Sublets are calculated under labor in Mitchell, but it's done in IO
//Under the parts rates. //Under the parts rates.
let stateTax = Dinero(); let statePartsTax = Dinero();
// let additionalItemsTax = Dinero(); //This is not used. let additionalItemsTax = Dinero();
let us_sales_tax_breakdown; let us_sales_tax_breakdown;
// This is not referenced in the code base.
//Audatex sends additional glass part types. IO-774 //Audatex sends additional glass part types. IO-774
// const BackupGlassTax = const BackupGlassTax =
// job.parts_tax_rates && job.parts_tax_rates &&
// (job.parts_tax_rates.PAGD || (job.parts_tax_rates.PAGD ||
// job.parts_tax_rates.PAGF || job.parts_tax_rates.PAGF ||
// job.parts_tax_rates.PAGP || job.parts_tax_rates.PAGP ||
// job.parts_tax_rates.PAGQ || job.parts_tax_rates.PAGQ ||
// job.parts_tax_rates.PAGR); job.parts_tax_rates.PAGR);
const taxableAmounts = { const taxableAmounts = {
PAA: Dinero(), PAA: Dinero(),
@@ -918,27 +878,11 @@ function CalculateTaxesTotals(job, otherTotals) {
} else if (key.startsWith("LA")) { } else if (key.startsWith("LA")) {
//Labor. //Labor.
for (let tyCounter = 1; tyCounter <= 5; tyCounter++) { for (let tyCounter = 1; tyCounter <= 5; tyCounter++) {
if (key === "LA1" || key === "LA2" || key === "LA3" || key === "LA4") { if (IsTrueOrYes(pfl[key][`lbr_tx_in${tyCounter}`])) {
if (IsTrueOrYes(pfl["LAU"][`lbr_tx_in${tyCounter}`])) { //This amount is taxable for this type.
//This amount is taxable for this type. taxableAmountsByTier[`ty${tyCounter}Tax`] = taxableAmountsByTier[`ty${tyCounter}Tax`].add(
taxableAmountsByTier[`ty${tyCounter}Tax`] = taxableAmountsByTier[`ty${tyCounter}Tax`].add( taxableAmounts[key]
taxableAmounts[key] );
);
}
} else if (key === "LAA" && !pfl[key]) {
if (IsTrueOrYes(pfl["LAB"][`lbr_tx_in${tyCounter}`])) {
//This amount is taxable for this type.
taxableAmountsByTier[`ty${tyCounter}Tax`] = taxableAmountsByTier[`ty${tyCounter}Tax`].add(
taxableAmounts[key]
);
}
} else {
if (IsTrueOrYes(pfl[key][`lbr_tx_in${tyCounter}`])) {
//This amount is taxable for this type.
taxableAmountsByTier[`ty${tyCounter}Tax`] = taxableAmountsByTier[`ty${tyCounter}Tax`].add(
taxableAmounts[key]
);
}
} }
} }
} else if (key === "TOW") { } else if (key === "TOW") {
@@ -965,24 +909,6 @@ function CalculateTaxesTotals(job, otherTotals) {
} }
}); });
if (job.adjustment_bottom_line) {
const subtotal_before_adjustment = subtotal.add(Dinero({ amount: Math.round(job.adjustment_bottom_line * -100) }));
const percent_of_adjustment =
Math.round(
subtotal_before_adjustment.toUnit() /
(job.adjustment_bottom_line > 0 ? job.adjustment_bottom_line : job.adjustment_bottom_line * -1)
) / 100;
Object.keys(taxableAmountsByTier).forEach((taxTierKey) => {
taxable_adjustment = taxableAmountsByTier[taxTierKey].multiply(percent_of_adjustment);
if (job.adjustment_bottom_line > 0) {
taxableAmountsByTier[taxTierKey] = taxableAmountsByTier[taxTierKey].add(taxable_adjustment);
} else {
taxableAmountsByTier[taxTierKey] = taxableAmountsByTier[taxTierKey].subtract(taxable_adjustment);
}
});
}
const remainingTaxableAmounts = taxableAmountsByTier; const remainingTaxableAmounts = taxableAmountsByTier;
console.log("*** Taxable Amounts by Tier***"); console.log("*** Taxable Amounts by Tier***");
console.table(JSON.parse(JSON.stringify(taxableAmountsByTier))); console.table(JSON.parse(JSON.stringify(taxableAmountsByTier)));
@@ -992,8 +918,8 @@ function CalculateTaxesTotals(job, otherTotals) {
let tyCounter = taxTierKey[2]; //Get the number from the key. let tyCounter = taxTierKey[2]; //Get the number from the key.
//i represents the tax number. If we got here, this type of tax is applicable. Now we need to add based on the thresholds. //i represents the tax number. If we got here, this type of tax is applicable. Now we need to add based on the thresholds.
for (let threshCounter = 1; threshCounter <= 5; threshCounter++) { for (let threshCounter = 1; threshCounter <= 5; threshCounter++) {
const thresholdAmount = parseFloat(job.cieca_pft[`ty${tyCounter}_thres${threshCounter}`]) || 0; const thresholdAmount = parseFloat(job.cieca_pft[`ty${tyCounter}_thres${threshCounter}`]);
const thresholdTaxRate = parseFloat(job.cieca_pft[`ty${tyCounter}_rate${threshCounter}`]) || 0; const thresholdTaxRate = parseFloat(job.cieca_pft[`ty${tyCounter}_rate${threshCounter}`]);
let taxableAmountInThisThreshold; let taxableAmountInThisThreshold;
if ( if (
@@ -1001,7 +927,7 @@ function CalculateTaxesTotals(job, otherTotals) {
InstanceMgr({ InstanceMgr({
imex: false, imex: false,
rome: thresholdAmount === 0 && parseInt(tyCounter) === 1, rome: thresholdAmount === 0 && parseInt(tyCounter) === 1,
promanager: "USE_ROME" promanager: thresholdAmount === 0 && parseInt(tyCounter) === 1
}) })
) { ) {
// //
@@ -1035,10 +961,10 @@ function CalculateTaxesTotals(job, otherTotals) {
} }
}); });
console.log("*** Total Tax by Tier Amounts***"); // console.log("*** Total Tax by Tier Amounts***");
console.table(JSON.parse(JSON.stringify(totalTaxByTier))); // console.table(JSON.parse(JSON.stringify(totalTaxByTier)));
stateTax = stateTax statePartsTax = statePartsTax
.add(totalTaxByTier.ty1Tax) .add(totalTaxByTier.ty1Tax)
.add(totalTaxByTier.ty2Tax) .add(totalTaxByTier.ty2Tax)
.add(totalTaxByTier.ty3Tax) .add(totalTaxByTier.ty3Tax)
@@ -1046,18 +972,17 @@ function CalculateTaxesTotals(job, otherTotals) {
.add(totalTaxByTier.ty5Tax) .add(totalTaxByTier.ty5Tax)
.add(totalTaxByTier.ty6Tax); .add(totalTaxByTier.ty6Tax);
us_sales_tax_breakdown = totalTaxByTier; us_sales_tax_breakdown = totalTaxByTier;
//console.log("Tiered Taxes Total for Parts/Labor", stateTax.toFormat()); //console.log("Tiered Taxes Total for Parts/Labor", statePartsTax.toFormat());
// This is not in use as such commented out. let laborTaxTotal = Dinero();
// let laborTaxTotal = Dinero();
// if (Object.keys(job.cieca_pfl).length > 0) { if (Object.keys(job.cieca_pfl).length > 0) {
// //Ignore it now, we have calculated it above. //Ignore it now, we have calculated it above.
// //This was previously used for JCS before parts were also calculated at a different rate. //This was previously used for JCS before parts were also calculated at a different rate.
// } else { } else {
// //We don't have it, just add in how it was before. //We don't have it, just add in how it was before.
// laborTaxTotal = otherTotals.rates.subtotal.percentage((job.tax_lbr_rt || 0) * 100); // THis is currently using the lbr tax rate from PFH not PFL. laborTaxTotal = otherTotals.rates.subtotal.percentage((job.tax_lbr_rt || 0) * 100); // THis is currently using the lbr tax rate from PFH not PFL.
// } }
//console.log("Labor Tax Total", laborTaxTotal.toFormat()); //console.log("Labor Tax Total", laborTaxTotal.toFormat());
@@ -1066,9 +991,9 @@ function CalculateTaxesTotals(job, otherTotals) {
federal_tax: subtotal federal_tax: subtotal
.percentage((job.federal_tax_rate || 0) * 100) .percentage((job.federal_tax_rate || 0) * 100)
.add(otherTotals.additional.pvrt.percentage((job.federal_tax_rate || 0) * 100)), .add(otherTotals.additional.pvrt.percentage((job.federal_tax_rate || 0) * 100)),
stateTax, statePartsTax,
us_sales_tax_breakdown, us_sales_tax_breakdown,
state_tax: stateTax, state_tax: statePartsTax,
local_tax: subtotal.percentage((job.local_tax_rate || 0) * 100) local_tax: subtotal.percentage((job.local_tax_rate || 0) * 100)
}; };
ret.total_repairs = ret.subtotal ret.total_repairs = ret.subtotal

View File

@@ -489,7 +489,7 @@ function CalculateAdditional(job) {
additionalCosts: null, additionalCosts: null,
additionalCostItems: [], additionalCostItems: [],
adjustments: null, adjustments: null,
towing: Dinero(), towing: null,
shipping: Dinero(), shipping: Dinero(),
storage: null, storage: null,
pvrt: null, pvrt: null,
@@ -512,7 +512,7 @@ function CalculateAdditional(job) {
} }
if (val.line_desc.toLowerCase().includes("towing")) { if (val.line_desc.toLowerCase().includes("towing")) {
ret.towing = ret.towing.add(lineValue); ret.towing = lineValue;
return acc; return acc;
} else { } else {
ret.additionalCostItems.push({ key: val.line_desc, total: lineValue }); ret.additionalCostItems.push({ key: val.line_desc, total: lineValue });

View File

@@ -1,76 +0,0 @@
const borderColors = [
"rgba(193, 0, 50, 1)",
"rgba(0, 101, 68, 1)",
"rgba(0, 45, 98, 1)",
"rgba(253, 184, 0, 1)",
"rgba(200, 112, 126, 1)",
"rgba(228, 142, 88, 1)",
"rgba(90, 160, 141, 1)",
"rgba(103, 143, 174, 1)",
"rgba(192, 136, 99, 1)",
"rgba(234, 3, 55, 1)",
"rgba(0, 149, 67, 1)",
"rgba(0, 81, 155, 1)",
"rgba(226, 143, 173, 1)",
"rgba(237, 170, 125, 1)",
"rgba(76, 146, 177, 1)",
"rgba(172, 153, 193, 1)",
"rgba(173, 167, 89, 1)",
"rgba(254, 197, 222, 1)",
"rgba(177, 231, 223, 1)",
"rgba(120, 199, 235, 1)",
"rgba(239, 180, 193, 1)",
"rgba(240, 199, 171, 1)",
"rgba(168, 200, 121, 1)",
"rgba(150, 177, 208, 1)",
"rgba(200, 194, 189, 1)",
"rgba(244, 244, 244, 1)",
"rgba(255, 99, 132, 1)",
"rgba(54, 162, 235, 1)",
"rgba(255, 206, 86, 1)",
"rgba(75, 192, 192, 1)",
"rgba(153, 102, 255, 1)",
"rgba(255, 159, 64, 1)",
"rgba(170, 183, 184, 1)",
];
const backgroundColors = [
'rgba(193, 0, 50, 0.2)',
'rgba(0, 101, 68, 0.2)',
'rgba(0, 45, 98, 0.2)',
'rgba(253, 184, 0, 0.2)',
'rgba(200, 112, 126, 0.2)',
'rgba(228, 142, 88, 0.2)',
'rgba(90, 160, 141, 0.2)',
'rgba(103, 143, 174, 0.2)',
'rgba(192, 136, 99, 0.2)',
'rgba(234, 3, 55, 0.2)',
'rgba(0, 149, 67, 0.2)',
'rgba(0, 81, 155, 0.2)',
'rgba(226, 143, 173, 0.2)',
'rgba(237, 170, 125, 0.2)',
'rgba(76, 146, 177, 0.2)',
'rgba(172, 153, 193, 0.2)',
'rgba(173, 167, 89, 0.2)',
'rgba(254, 197, 222, 0.2)',
'rgba(177, 231, 223, 0.2)',
'rgba(120, 199, 235, 0.2)',
'rgba(239, 180, 193, 0.2)',
'rgba(240, 199, 171, 0.2)',
'rgba(168, 200, 121, 0.2)',
'rgba(150, 177, 208, 0.2)',
'rgba(200, 194, 189, 0.2)',
'rgba(244, 244, 244, 0.2)',
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)',
'rgba(170, 183, 184, 0.2)',
];
module.exports = {
borderColors,
backgroundColors,
};

View File

@@ -1,92 +0,0 @@
const { createCanvas } = require("canvas");
const Chart = require("chart.js/auto");
const { backgroundColors, borderColors } = require("./canvas-colors");
const { isObject, defaultsDeep, isNumber } = require("lodash");
exports.canvastest = function (req, res) {
console.log("Incoming test request.", req);
res.status(200).send("OK");
};
exports.canvas = function (req, res) {
const { w, h, values, keys, override } = req.body;
console.log("Incoming Canvas Request:", w, h, values, keys, override);
// Gate required values
if (!values || !keys) {
res.status(400).send("Missing required data");
return;
}
// Override must be an object if it exists
if (override && !isObject(override)) {
res.status(400).send("Override must be an object");
return;
}
// Set the default Width and Height
let [width, height] = [500, 275];
// Allow for custom width and height
if (isNumber(w)) {
width = w;
}
if (isNumber(h)) {
height = h;
}
const configuration = {
type: "doughnut",
data: {
labels: keys,
datasets: [
{
data: values,
backgroundColor: backgroundColors,
borderColor: borderColors,
borderWidth: 1
}
]
},
options: {
devicePixelRatio: 4,
responsive: false,
maintainAspectRatio: true,
circumference: 180,
rotation: -90,
plugins: {
legend: {
labels: {
boxWidth: 20,
font: {
family: "'Montserrat'",
size: 10,
style: "normal",
weight: "normal"
}
},
position: "left"
}
}
}
};
// If we have a valid override object, merge it with the default configuration object.
// This allows for you to override the default configuration with a custom one.
const defaults = () => {
if (!override || !isObject(override)) {
return configuration;
}
return defaultsDeep(override, configuration);
};
res.status(200).send(
(() => {
const canvas = createCanvas(width, height);
const ctx = canvas.getContext("2d");
new Chart(ctx, defaults());
return canvas.toDataURL();
})()
);
};

View File

@@ -1,13 +1,11 @@
const express = require("express"); const express = require("express");
const router = express.Router(); const router = express.Router();
const cdkGetMake = require("../cdk/cdk-get-makes"); const cdkGetMake = require("../cdk/cdk-get-makes");
const cdkCalculateAllocations = require("../cdk/cdk-calculate-allocations");
const validateFirebaseIdTokenMiddleware = require("../middleware/validateFirebaseIdTokenMiddleware"); const validateFirebaseIdTokenMiddleware = require("../middleware/validateFirebaseIdTokenMiddleware");
const withUserGraphQLClientMiddleware = require("../middleware/withUserGraphQLClientMiddleware"); const withUserGraphQLClientMiddleware = require("../middleware/withUserGraphQLClientMiddleware");
router.use(validateFirebaseIdTokenMiddleware); router.use(validateFirebaseIdTokenMiddleware);
router.post("/getvehicles", withUserGraphQLClientMiddleware, cdkGetMake.default); router.post("/getvehicles", withUserGraphQLClientMiddleware, cdkGetMake.default);
router.post("/calculate-allocations", withUserGraphQLClientMiddleware, cdkCalculateAllocations.defaultRoute);
module.exports = router; module.exports = router;

View File

@@ -11,7 +11,6 @@ const eventAuthorizationMiddleware = require("../middleware/eventAuthorizationMI
const validateFirebaseIdTokenMiddleware = require("../middleware/validateFirebaseIdTokenMiddleware"); const validateFirebaseIdTokenMiddleware = require("../middleware/validateFirebaseIdTokenMiddleware");
const withUserGraphQLClientMiddleware = require("../middleware/withUserGraphQLClientMiddleware"); const withUserGraphQLClientMiddleware = require("../middleware/withUserGraphQLClientMiddleware");
const { taskAssignedEmail, tasksRemindEmail } = require("../email/tasksEmails"); const { taskAssignedEmail, tasksRemindEmail } = require("../email/tasksEmails");
const { canvastest } = require("../render/canvas-handler");
//Test route to ensure Express is responding. //Test route to ensure Express is responding.
router.get("/test", async function (req, res) { router.get("/test", async function (req, res) {
@@ -50,7 +49,4 @@ router.post("/tasks-remind-handler", eventAuthorizationMiddleware, tasksRemindEm
router.post("/record-handler/arms", data.arms); router.post("/record-handler/arms", data.arms);
router.post("/taskHandler", validateFirebaseIdTokenMiddleware, taskHandler.taskHandler); router.post("/taskHandler", validateFirebaseIdTokenMiddleware, taskHandler.taskHandler);
// Canvas Test
router.post("/canvastest", validateFirebaseIdTokenMiddleware, canvastest);
module.exports = router; module.exports = router;

View File

@@ -2,10 +2,8 @@ const express = require("express");
const router = express.Router(); const router = express.Router();
const { inlinecss } = require("../render/inlinecss"); const { inlinecss } = require("../render/inlinecss");
const validateFirebaseIdTokenMiddleware = require("../middleware/validateFirebaseIdTokenMiddleware"); const validateFirebaseIdTokenMiddleware = require("../middleware/validateFirebaseIdTokenMiddleware");
const { canvas } = require("../render/canvas-handler");
// Define the route for inline CSS rendering // Define the route for inline CSS rendering
router.post("/inlinecss", validateFirebaseIdTokenMiddleware, inlinecss); router.post("/inlinecss", validateFirebaseIdTokenMiddleware, inlinecss);
router.post("/canvas", validateFirebaseIdTokenMiddleware, canvas);
module.exports = router; module.exports = router;