Compare commits

...

23 Commits

Author SHA1 Message Date
Allan Carr
8dd0e12398 Dinero Object
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-08-02 15:12:51 -07:00
Allan Carr
a8b0931659 Correct for Dinero type
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-08-02 14:49:20 -07:00
Allan Carr
11a182c68a Correct query and object call
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-08-02 14:19:58 -07:00
Allan Carr
f1940a320c IO-2854 Handle Exporting to Accounting
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-08-02 11:30:08 -07:00
Allan Carr
49a1f0c42c Correct for Labor Adjustment being null
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-08-01 14:42:07 -07:00
Allan Carr
7126cc0d56 Correction for upsteam change
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-08-01 13:31:44 -07:00
Allan Carr
5cf2345dca IO-2854 Profile Adjustments for LA and MA
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-07-31 14:15:31 -07:00
Allan Carr
171f40819c Merged in release/2024-07-26 (pull request #1546)
Release/2024 07 26

Approved-by: Dave Richer
2024-07-29 21:27:54 +00:00
Allan Carr
01da7fde31 Merged in feature/IO-2564-Row-Expander-Links (pull request #1543)
IO-2564 Row Expander Links

Approved-by: Dave Richer
2024-07-29 18:57:50 +00:00
Allan Carr
3c8234d715 Merged in feature/IO-2853-Production-Board-Date-Modal (pull request #1544)
IO-2853 Production Board Date Modal

Approved-by: Dave Richer
2024-07-29 18:53:48 +00:00
Allan Carr
866f242465 IO-2853 Production Board Date Modal
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-07-29 11:30:52 -07:00
Allan Carr
f690596825 IO-2564 Row Expander Links
Move Drawer from Parts Order into seperate componenet and pass props down from main page and then link the BillDetailEdit Container into joblines

Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-07-29 11:21:40 -07:00
Allan Carr
5f494e4b78 IO-2564 Revert location of query
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-07-26 13:28:29 -07:00
Allan Carr
2fc0e1cf50 Merged in feature/IO-2564-Row-Expander-Links (pull request #1541)
IO-2564 Revert location of query
2024-07-26 20:26:20 +00:00
Allan Carr
3550c97966 Merged in feature/IO-2849-Missing-Translation-from-Shop-Config (pull request #1538)
IO-2849 Missing Translation from Shop Config

Approved-by: Dave Richer
2024-07-25 16:57:22 +00:00
Allan Carr
956c686360 Merged in feature/IO-2850-Missing-Fields-from-Shop-Config (pull request #1537)
IO-2850 Missing fields from save on Shop Config Taxes
2024-07-25 16:56:26 +00:00
Allan Carr
508b0d7711 Merged in feature/IO-2851-Rome-Manual-Job-Creation-Taxes (pull request #1536)
IO-2851 Manual Job Creation Taxes

Approved-by: Dave Richer
2024-07-25 16:55:41 +00:00
Allan Carr
abb1464e30 IO-2849 Missing Translation from Shop Config
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-07-25 08:39:42 -07:00
Allan Carr
704d5415d6 IO-2850 Missing fields from save on Shop Config Taxes
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-07-25 08:38:01 -07:00
Allan Carr
6cc1cfd1b0 IO-2851 Manual Job Creation Taxes
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-07-25 08:36:08 -07:00
Allan Carr
1bf745345d Merged in feature/IO-2564-Row-Expander-Links (pull request #1533)
IO-2564 Row Expander Links

Approved-by: Dave Richer
2024-07-23 03:36:53 +00:00
Allan Carr
63c71ed923 Merged in feature/IO-2848-Update_Job-Query (pull request #1534)
IO-2848 UPDATE_JOB query

Approved-by: Dave Richer
2024-07-23 03:35:53 +00:00
Allan Carr
93c92e8976 IO-2564 Row Expander Links
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-07-22 13:30:08 -07:00
24 changed files with 11939 additions and 10798 deletions

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_BILLS_BY_JOBID } from "../../graphql/bills.queries"; import { QUERY_PARTS_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_BILLS_BY_JOBID, { const { loading, error, data } = useQuery(QUERY_PARTS_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

@@ -2,17 +2,18 @@ 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 { connect } from "react-redux"; import BillDetailEditcontainer from "../bill-detail-edit/bill-detail-edit.container.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 FeatureWrapper from "../feature-wrapper/feature-wrapper.component.jsx"; import FeatureWrapper from "../feature-wrapper/feature-wrapper.component.jsx";
import TaskListContainer from "../task-list/task-list.container.jsx";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop bodyshop: selectBodyshop
@@ -84,17 +85,17 @@ export function JobLinesExpander({ jobline, jobid, bodyshop }) {
key: line.id, key: line.id,
children: ( children: (
<Row> <Row>
<Col span={8}> <Col span={8}>{line.parts_dispatch.number}</Col>
<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>
) )
@@ -111,6 +112,7 @@ 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,19 +31,20 @@ 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,
@@ -54,6 +55,7 @@ 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" }))
}); });
@@ -63,6 +65,7 @@ export function JobLinesComponent({
jobRO, jobRO,
technician, technician,
setPartsOrderContext, setPartsOrderContext,
setPartsReceiveContext,
loading, loading,
refetch, refetch,
jobLines, jobLines,
@@ -71,7 +74,11 @@ 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 {
@@ -437,6 +444,13 @@ 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,7 +1,17 @@
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({ job, joblines, refetch, form, ...rest }) { function JobLinesContainer({
job,
joblines,
billsQuery,
handleBillOnRowClick,
handlePartsOrderOnRowClick,
handlePartsDispatchOnRowClick,
refetch,
form,
...rest
}) {
const [searchText, setSearchText] = useState(""); const [searchText, setSearchText] = useState("");
const jobLines = useMemo(() => { const jobLines = useMemo(() => {
@@ -22,7 +32,19 @@ function JobLinesContainer({ job, joblines, refetch, form, ...rest }) {
}, [joblines, searchText]); }, [joblines, searchText]);
return ( return (
<JobLinesComponent refetch={refetch} jobLines={jobLines} setSearchText={setSearchText} job={job} form={form} /> <div>
<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 { alphaSort } from "../../utils/sorters";
import InstanceRenderManager from "../../utils/instanceRenderMgr"; import InstanceRenderManager from "../../utils/instanceRenderMgr";
import { alphaSort } from "../../utils/sorters";
export default function JobTotalsTableLabor({ job }) { export default function JobTotalsTableLabor({ job }) {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -56,6 +56,35 @@ 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"),
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()
},
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"), title: t("joblines.fields.total"),
dataIndex: "total", dataIndex: "total",
@@ -63,9 +92,11 @@ export default function JobTotalsTableLabor({ job }) {
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()
} }
],
promanager: "USE_ROME"
})
]; ];
const handleTableChange = (pagination, filters, sorter) => { const handleTableChange = (pagination, filters, sorter) => {
@@ -91,6 +122,16 @@ 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>
@@ -122,7 +163,29 @@ 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>
<Table.Summary.Cell align="right">{Dinero(job.job_totals.rates.mapa.total).toFormat()}</Table.Summary.Cell> {InstanceRenderManager({
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>
@@ -151,7 +214,29 @@ 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>
<Table.Summary.Cell align="right">{Dinero(job.job_totals.rates.mash.total).toFormat()}</Table.Summary.Cell> {InstanceRenderManager({
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>
@@ -159,6 +244,16 @@ 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

@@ -1,55 +1,13 @@
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({ job }) { export default function JobsDetailPliContainer({
const billsQuery = useQuery(QUERY_BILLS_BY_JOBID, { job,
variables: { jobid: job.id }, billsQuery,
fetchPolicy: "network-only", handleBillOnRowClick,
nextFetchPolicy: "network-only" handlePartsOrderOnRowClick,
}); 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, Switch } from "antd"; import { Collapse, Form, InputNumber, 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,6 +17,9 @@ 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"]}
@@ -24,6 +27,24 @@ 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"]}
@@ -61,6 +82,9 @@ 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"]}
@@ -68,6 +92,24 @@ 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"]}
@@ -105,6 +147,9 @@ 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"]}
@@ -112,6 +157,24 @@ 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"]}
@@ -149,6 +212,9 @@ 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"]}
@@ -156,6 +222,24 @@ 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"]}
@@ -193,6 +277,9 @@ 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"]}
@@ -200,6 +287,24 @@ 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"]}
@@ -237,6 +342,9 @@ 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"]}
@@ -244,6 +352,24 @@ 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"]}
@@ -281,6 +407,9 @@ 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"]}
@@ -288,6 +417,24 @@ 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"]}
@@ -325,6 +472,9 @@ 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"]}
@@ -332,6 +482,24 @@ 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"]}
@@ -369,6 +537,9 @@ 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"]}
@@ -376,6 +547,24 @@ 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,7 +23,9 @@ 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"]}
@@ -31,6 +33,24 @@ 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"]}
@@ -74,7 +94,9 @@ 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"]}
@@ -82,6 +104,24 @@ 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,6 +4,7 @@ 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({
@@ -988,18 +989,24 @@ 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"> <Form.Item label={t("jobs.fields.tax_paint_mat_rt")} name="tax_paint_mat_rt">
<InputNumber min={0} max={100} precision={4} disabled={jobRO} /> <InputNumber min={0} max={100} precision={4} disabled={jobRO} />
</Form.Item> </Form.Item>
<Form.Item label={t("jobs.fields.tax_shop_mat_rt")} name="tax_shop_mat_rt"> <Form.Item label={t("jobs.fields.tax_shop_mat_rt")} name="tax_shop_mat_rt">
<InputNumber min={0} max={100} precision={4} disabled={jobRO} /> <InputNumber min={0} max={100} precision={4} disabled={jobRO} />
</Form.Item> </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

@@ -0,0 +1,411 @@
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,33 +1,23 @@
import { DeleteFilled, EyeFilled, SyncOutlined } from "@ant-design/icons"; import { DeleteFilled, EyeFilled, SyncOutlined } from "@ant-design/icons";
import { useLazyQuery, useMutation } from "@apollo/client"; import { useMutation } from "@apollo/client";
import { Button, Card, Checkbox, Drawer, Grid, Input, Popconfirm, Space, Table } from "antd"; import { Button, Card, Checkbox, Input, Popconfirm, Space, Table } from "antd";
import { PageHeader } from "@ant-design/pro-layout"; import React, { useState } from "react";
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 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 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 FeatureWrapperComponent from "../feature-wrapper/feature-wrapper.component"; import PartsOrderDrawer from "./parts-order-list-table-drawer.component";
import { FaTasks } from "react-icons/fa";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
jobRO: selectJobReadOnly, jobRO: selectJobReadOnly,
@@ -62,19 +52,6 @@ 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 });
@@ -83,42 +60,17 @@ 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);
}} }}
> >
@@ -298,154 +250,6 @@ 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
@@ -476,15 +280,13 @@ export function PartsOrderListTableComponent({
} }
> >
<PartsReceiveModalContainer /> <PartsReceiveModalContainer />
<Drawer <PartsOrderDrawer
placement="right" job={job}
onClose={() => handleOnRowClick(null)} billsQuery={billsQuery}
open={selectedpartsorder} handleOnRowClick={handleOnRowClick}
closable setPartsReceiveContext={setPartsReceiveContext}
width={drawerPercentage} setTaskUpsertContext={setTaskUpsertContext}
> />
{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, TimePicker } from "antd"; import { Button, Card, Dropdown, Space, 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,6 +56,7 @@ 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()} onClick={(e) => e.stopPropagation()}
value={(record[field] && dayjs(record[field])) || null} value={(record[field] && dayjs(record[field])) || null}
@@ -73,6 +74,7 @@ export default function ProductionListDate({ record, field, time, pastIndicator
/> />
)} )}
<Button onClick={() => setOpen(false)}>{t("general.actions.close")}</Button> <Button onClick={() => setOpen(false)}>{t("general.actions.close")}</Button>
</Space>
</Card> </Card>
) )
} }

View File

@@ -4,6 +4,7 @@ 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({
@@ -51,6 +52,12 @@ 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"]}
@@ -58,6 +65,24 @@ 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"]}
@@ -95,6 +120,12 @@ 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"]}
@@ -102,6 +133,24 @@ 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"]}
@@ -139,6 +188,12 @@ 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"]}
@@ -146,6 +201,24 @@ 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"]}
@@ -183,6 +256,12 @@ 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"]}
@@ -190,6 +269,24 @@ 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"]}
@@ -227,6 +324,12 @@ 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"]}
@@ -234,6 +337,24 @@ 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"]}
@@ -271,6 +392,12 @@ 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"]}
@@ -278,6 +405,24 @@ 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"]}
@@ -315,6 +460,12 @@ 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"]}
@@ -322,6 +473,24 @@ 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"]}
@@ -359,6 +528,12 @@ 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"]}
@@ -366,6 +541,24 @@ 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"]}
@@ -403,6 +596,12 @@ 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"]}
@@ -410,6 +609,24 @@ 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"]}
@@ -462,7 +679,12 @@ 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"]}
@@ -470,6 +692,24 @@ 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"]}
@@ -519,7 +759,12 @@ 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"]}
@@ -527,6 +772,24 @@ 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"]}
@@ -1765,25 +2028,37 @@ export function ShopInfoResponsibilityCenters({ bodyshop, form }) {
</Form.Item> </Form.Item>
</LayoutFormRow> </LayoutFormRow>
<LayoutFormRow> <LayoutFormRow>
<Form.Item label={t("jobs.fields.tax_tow_rt")} name="tax_tow_rt"> <Form.Item label={t("jobs.fields.tax_tow_rt")} name={["md_responsibility_centers", "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="tax_str_rt"> <Form.Item label={t("jobs.fields.tax_str_rt")} name={["md_responsibility_centers", "tax_str_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_paint_mat_rt")} name="tax_paint_mat_rt"> {InstanceRenderManager({ imex: true, rome: false, promanager: "USE_ROME" }) ? (
<>
<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} /> <InputNumber min={0} max={100} precision={4} />
</Form.Item> </Form.Item>
<Form.Item label={t("jobs.fields.tax_shop_mat_rt")} name="tax_shop_mat_rt"> <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} /> <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}
<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>
<Form.Item label={t("jobs.fields.tax_lbr_rt")} name="tax_lbr_rt"> {InstanceRenderManager({ imex: true, rome: false, promanager: "USE_ROME" }) ? (
<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_levies_rt")} name="tax_levies_rt"> ) : null}
<Form.Item label={t("jobs.fields.tax_levies_rt")} name={["md_responsibility_centers", "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_BILLS_BY_JOBID = gql` export const QUERY_PARTS_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

@@ -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,13 +159,6 @@ 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,
@@ -261,6 +254,14 @@ 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,
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
},
rome: { rome: {
cieca_pft: { cieca_pft: {
...bodyshop.md_responsibility_centers.taxes.tax_ty1, ...bodyshop.md_responsibility_centers.taxes.tax_ty1,
@@ -271,9 +272,16 @@ function JobsCreateContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
}, },
materials: bodyshop.md_responsibility_centers.cieca_pfm, materials: bodyshop.md_responsibility_centers.cieca_pfm,
cieca_pfl: bodyshop.md_responsibility_centers.cieca_pfl, cieca_pfl: bodyshop.md_responsibility_centers.cieca_pfl,
parts_tax_rates: bodyshop.md_responsibility_centers.parts_tax_rates 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 { Badge, Button, Divider, Form, notification, Space, Tabs } from "antd";
import { PageHeader } from "@ant-design/pro-layout"; import { PageHeader } from "@ant-design/pro-layout";
import { useQuery } from "@apollo/client";
import { Badge, Button, Divider, Form, notification, Space, Tabs } from "antd";
import Axios from "axios"; import Axios from "axios";
import dayjs from "../../utils/day"; import _ from "lodash";
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,11 +20,13 @@ 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";
@@ -42,19 +44,18 @@ 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 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 { DateTimeFormat } from "../../utils/DateFormatter";
import dayjs from "../../utils/day";
import InstanceRenderManager from "../../utils/instanceRenderMgr"; import InstanceRenderManager from "../../utils/instanceRenderMgr";
import { HasFeatureAccess } from "../../components/feature-wrapper/feature-wrapper.component"; import UndefinedToNull from "../../utils/undefinedtonull";
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,
@@ -95,6 +96,11 @@ 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));
@@ -103,6 +109,42 @@ 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);
@@ -302,7 +344,18 @@ 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: <JobsLinesContainer job={job} joblines={job.joblines} refetch={refetch} form={form} /> children: (
<JobsLinesContainer
job={job}
joblines={job.joblines}
billsQuery={billsQuery}
handleBillOnRowClick={handleBillOnRowClick}
handlePartsOrderOnRowClick={handlePartsOrderOnRowClick}
handlePartsDispatchOnRowClick={handlePartsDispatchOnRowClick}
refetch={refetch}
form={form}
/>
)
}, },
{ {
key: "rates", key: "rates",
@@ -326,7 +379,15 @@ 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: <JobsDetailPliContainer job={job} /> children: (
<JobsDetailPliContainer
job={job}
billsQuery={billsQuery}
handleBillOnRowClick={handleBillOnRowClick}
handlePartsOrderOnRowClick={handlePartsOrderOnRowClick}
handlePartsDispatchOnRowClick={handlePartsDispatchOnRowClick}
/>
)
}, },
...(InstanceRenderManager({ ...(InstanceRenderManager({
imex: true, imex: true,

View File

@@ -230,7 +230,7 @@
"markexported": "Mark Exported", "markexported": "Mark Exported",
"markforreexport": "Mark for Re-export", "markforreexport": "Mark for Re-export",
"new": "New Bill", "new": "New Bill",
"nobilllines": "", "nobilllines": "This part has not yet been recieved.",
"noneselected": "No bill selected.", "noneselected": "No bill selected.",
"onlycmforinvoiced": "Only credit memos can be entered for any Job that has been invoiced, exported, or voided.", "onlycmforinvoiced": "Only credit memos can be entered for any Job that has been invoiced, exported, or voided.",
"printlabels": "Print Labels", "printlabels": "Print Labels",
@@ -1392,7 +1392,9 @@
"fields": { "fields": {
"act_price": "Retail Price", "act_price": "Retail Price",
"act_price_before_ppc": "Original Part Price", "act_price_before_ppc": "Original Part Price",
"adjustment": "Adjustment",
"ah_detail_line": "Mark as Detail Labor Line (Autohouse Only)", "ah_detail_line": "Mark as Detail Labor Line (Autohouse Only)",
"amount": "Amount",
"assigned_team": "Team", "assigned_team": "Team",
"assigned_team_name": "Team {{name}}", "assigned_team_name": "Team {{name}}",
"create_ppc": "Create PPC?", "create_ppc": "Create PPC?",
@@ -1601,7 +1603,9 @@
"ccm": "CC Mileage", "ccm": "CC Mileage",
"cieca_id": "CIECA ID", "cieca_id": "CIECA ID",
"cieca_pfl": { "cieca_pfl": {
"lbr_adjp": "Labor Adjustment",
"lbr_tax_in": "Tax Labor Indicator", "lbr_tax_in": "Tax Labor Indicator",
"lbr_taxp": "Labor Tax Rate",
"lbr_tx_in1": "Tax 1 Indicator", "lbr_tx_in1": "Tax 1 Indicator",
"lbr_tx_in2": "Tax 2 Indicator", "lbr_tx_in2": "Tax 2 Indicator",
"lbr_tx_in3": "Tax 3 Indicator", "lbr_tx_in3": "Tax 3 Indicator",
@@ -1741,6 +1745,8 @@
"MASH": "Shop Materials", "MASH": "Shop Materials",
"cal_maxdlr": "Threshhold", "cal_maxdlr": "Threshhold",
"cal_opcode": "OP Codes", "cal_opcode": "OP Codes",
"mat_adjp": "Material Adjustment",
"mat_taxp": "Material Tax Rate",
"mat_tx_in1": "Tax 1 Indicator", "mat_tx_in1": "Tax 1 Indicator",
"mat_tx_in2": "Tax 2 Indicator", "mat_tx_in2": "Tax 2 Indicator",
"mat_tx_in3": "Tax 3 Indicator", "mat_tx_in3": "Tax 3 Indicator",
@@ -1776,6 +1782,7 @@
"prt_tx_in3": "Tax 3 Indicator", "prt_tx_in3": "Tax 3 Indicator",
"prt_tx_in4": "Tax 4 Indicator", "prt_tx_in4": "Tax 4 Indicator",
"prt_tx_in5": "Tax 5 Indicator", "prt_tx_in5": "Tax 5 Indicator",
"prt_tx_ty1": "Parts Tax Type 1",
"prt_type": "Part Type" "prt_type": "Part Type"
}, },
"partsstatus": "Parts Status", "partsstatus": "Parts Status",

View File

@@ -1392,7 +1392,9 @@
"fields": { "fields": {
"act_price": "Precio actual", "act_price": "Precio actual",
"act_price_before_ppc": "", "act_price_before_ppc": "",
"adjustment": "",
"ah_detail_line": "", "ah_detail_line": "",
"amount": "",
"assigned_team": "", "assigned_team": "",
"assigned_team_name": "", "assigned_team_name": "",
"create_ppc": "", "create_ppc": "",
@@ -1601,7 +1603,9 @@
"ccm": "", "ccm": "",
"cieca_id": "CIECA ID", "cieca_id": "CIECA ID",
"cieca_pfl": { "cieca_pfl": {
"lbr_adjp": "",
"lbr_tax_in": "", "lbr_tax_in": "",
"lbr_taxp": "",
"lbr_tx_in1": "", "lbr_tx_in1": "",
"lbr_tx_in2": "", "lbr_tx_in2": "",
"lbr_tx_in3": "", "lbr_tx_in3": "",
@@ -1741,6 +1745,8 @@
"MASH": "", "MASH": "",
"cal_maxdlr": "", "cal_maxdlr": "",
"cal_opcode": "", "cal_opcode": "",
"mat_adjp": "",
"mat_taxp": "",
"mat_tx_in1": "", "mat_tx_in1": "",
"mat_tx_in2": "", "mat_tx_in2": "",
"mat_tx_in3": "", "mat_tx_in3": "",
@@ -1776,6 +1782,7 @@
"prt_tx_in3": "", "prt_tx_in3": "",
"prt_tx_in4": "", "prt_tx_in4": "",
"prt_tx_in5": "", "prt_tx_in5": "",
"prt_tx_ty1": "",
"prt_type": "" "prt_type": ""
}, },
"partsstatus": "", "partsstatus": "",

View File

@@ -1392,7 +1392,9 @@
"fields": { "fields": {
"act_price": "Prix actuel", "act_price": "Prix actuel",
"act_price_before_ppc": "", "act_price_before_ppc": "",
"adjustment": "",
"ah_detail_line": "", "ah_detail_line": "",
"amount": "",
"assigned_team": "", "assigned_team": "",
"assigned_team_name": "", "assigned_team_name": "",
"create_ppc": "", "create_ppc": "",
@@ -1601,7 +1603,9 @@
"ccm": "", "ccm": "",
"cieca_id": "CIECA ID", "cieca_id": "CIECA ID",
"cieca_pfl": { "cieca_pfl": {
"lbr_adjp": "",
"lbr_tax_in": "", "lbr_tax_in": "",
"lbr_taxp": "",
"lbr_tx_in1": "", "lbr_tx_in1": "",
"lbr_tx_in2": "", "lbr_tx_in2": "",
"lbr_tx_in3": "", "lbr_tx_in3": "",
@@ -1741,6 +1745,8 @@
"MASH": "", "MASH": "",
"cal_maxdlr": "", "cal_maxdlr": "",
"cal_opcode": "", "cal_opcode": "",
"mat_adjp": "",
"mat_taxp": "",
"mat_tx_in1": "", "mat_tx_in1": "",
"mat_tx_in2": "", "mat_tx_in2": "",
"mat_tx_in3": "", "mat_tx_in3": "",
@@ -1776,6 +1782,7 @@
"prt_tx_in3": "", "prt_tx_in3": "",
"prt_tx_in4": "", "prt_tx_in4": "",
"prt_tx_in5": "", "prt_tx_in5": "",
"prt_tx_ty1": "",
"prt_type": "" "prt_type": ""
}, },
"partsstatus": "", "partsstatus": "",

View File

@@ -664,7 +664,7 @@ exports.default = function ({ bodyshop, jobs_by_pk, qbo = false, items, taxCodes
}); });
} }
} else { } else {
//Handle insurance profile adjustments //Handle insurance profile adjustments for Parts
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,6 +718,67 @@ 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({

View File

@@ -360,12 +360,10 @@ function calculateAllocations(connectionData, job) {
} }
} }
if (InstanceManager({ rome: true })) { if (InstanceManager({ rome: true })) {
//profile level adjustments //profile level adjustments for parts
Object.keys(job.job_totals.parts.adjustments).forEach((key) => { Object.keys(job.job_totals.parts.adjustments).forEach((key) => {
const accountName = selectedDmsAllocationConfig.profits[key]; const accountName = selectedDmsAllocationConfig.profits[key];
const otherAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === accountName); const otherAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === accountName);
if (otherAccount) { if (otherAccount) {
if (!profitCenterHash[accountName]) profitCenterHash[accountName] = Dinero(); if (!profitCenterHash[accountName]) profitCenterHash[accountName] = Dinero();
@@ -380,6 +378,24 @@ function calculateAllocations(connectionData, job) {
); );
} }
}); });
//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 jobAllocations = _.union(Object.keys(profitCenterHash), Object.keys(costCenterHash)).map((key) => {

View File

@@ -1527,6 +1527,8 @@ 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
@@ -1641,6 +1643,8 @@ 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
@@ -1866,6 +1870,8 @@ 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

View File

@@ -286,9 +286,45 @@ function GenerateCostingData(job) {
const rateName = `rate_${(val.mod_lbr_ty || "").toLowerCase()}`; const rateName = `rate_${(val.mod_lbr_ty || "").toLowerCase()}`;
const laborAmount = Dinero({ let 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);
@@ -317,7 +353,7 @@ 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);
const partsAmount = Dinero({ let 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_before_ppc * 100)
: Math.round(val.act_price * 100) : Math.round(val.act_price * 100)
@@ -338,6 +374,33 @@ function GenerateCostingData(job) {
.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);
} }
@@ -413,6 +476,7 @@ 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(
@@ -420,10 +484,26 @@ 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(
@@ -431,6 +511,21 @@ 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,6 +331,8 @@ 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;
@@ -349,13 +351,50 @@ async function CalculateRatesTotals({ job, client }) {
} }
} }
const total = Dinero({ const base = 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);
} }
} }
@@ -703,18 +742,19 @@ 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 statePartsTax = Dinero(); let stateTax = Dinero();
let additionalItemsTax = Dinero(); // let additionalItemsTax = Dinero(); //This is not used.
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(),
@@ -878,6 +918,21 @@ 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["LAU"][`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 === "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}`])) { if (IsTrueOrYes(pfl[key][`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(
@@ -885,6 +940,7 @@ function CalculateTaxesTotals(job, otherTotals) {
); );
} }
} }
}
} else if (key === "TOW") { } else if (key === "TOW") {
for (let tyCounter = 1; tyCounter <= 5; tyCounter++) { for (let tyCounter = 1; tyCounter <= 5; tyCounter++) {
if (IsTrueOrYes(pfo[`tow_t_in${tyCounter}`])) { if (IsTrueOrYes(pfo[`tow_t_in${tyCounter}`])) {
@@ -919,7 +975,6 @@ function CalculateTaxesTotals(job, otherTotals) {
Object.keys(taxableAmountsByTier).forEach((taxTierKey) => { Object.keys(taxableAmountsByTier).forEach((taxTierKey) => {
taxable_adjustment = taxableAmountsByTier[taxTierKey].multiply(percent_of_adjustment); taxable_adjustment = taxableAmountsByTier[taxTierKey].multiply(percent_of_adjustment);
console.log("🚀 ~ taxableAmountsByTier ~ taxable_adjustment:", taxable_adjustment);
if (job.adjustment_bottom_line > 0) { if (job.adjustment_bottom_line > 0) {
taxableAmountsByTier[taxTierKey] = taxableAmountsByTier[taxTierKey].add(taxable_adjustment); taxableAmountsByTier[taxTierKey] = taxableAmountsByTier[taxTierKey].add(taxable_adjustment);
} else { } else {
@@ -937,8 +992,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}`]); const thresholdAmount = parseFloat(job.cieca_pft[`ty${tyCounter}_thres${threshCounter}`]) || 0;
const thresholdTaxRate = parseFloat(job.cieca_pft[`ty${tyCounter}_rate${threshCounter}`]); const thresholdTaxRate = parseFloat(job.cieca_pft[`ty${tyCounter}_rate${threshCounter}`]) || 0;
let taxableAmountInThisThreshold; let taxableAmountInThisThreshold;
if ( if (
@@ -946,7 +1001,7 @@ function CalculateTaxesTotals(job, otherTotals) {
InstanceMgr({ InstanceMgr({
imex: false, imex: false,
rome: thresholdAmount === 0 && parseInt(tyCounter) === 1, rome: thresholdAmount === 0 && parseInt(tyCounter) === 1,
promanager: thresholdAmount === 0 && parseInt(tyCounter) === 1 promanager: "USE_ROME"
}) })
) { ) {
// //
@@ -980,10 +1035,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)));
statePartsTax = statePartsTax stateTax = stateTax
.add(totalTaxByTier.ty1Tax) .add(totalTaxByTier.ty1Tax)
.add(totalTaxByTier.ty2Tax) .add(totalTaxByTier.ty2Tax)
.add(totalTaxByTier.ty3Tax) .add(totalTaxByTier.ty3Tax)
@@ -991,17 +1046,18 @@ 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", statePartsTax.toFormat()); //console.log("Tiered Taxes Total for Parts/Labor", stateTax.toFormat());
let laborTaxTotal = Dinero(); // This is not in use as such commented out.
// 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());
@@ -1010,9 +1066,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)),
statePartsTax, stateTax,
us_sales_tax_breakdown, us_sales_tax_breakdown,
state_tax: statePartsTax, state_tax: stateTax,
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