Compare commits
23 Commits
feature/IO
...
feature/IO
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8dd0e12398 | ||
|
|
a8b0931659 | ||
|
|
11a182c68a | ||
|
|
f1940a320c | ||
|
|
49a1f0c42c | ||
|
|
7126cc0d56 | ||
|
|
5cf2345dca | ||
|
|
171f40819c | ||
|
|
01da7fde31 | ||
|
|
3c8234d715 | ||
|
|
866f242465 | ||
|
|
f690596825 | ||
|
|
5f494e4b78 | ||
|
|
2fc0e1cf50 | ||
|
|
3550c97966 | ||
|
|
956c686360 | ||
|
|
508b0d7711 | ||
|
|
abb1464e30 | ||
|
|
704d5415d6 | ||
|
|
6cc1cfd1b0 | ||
|
|
1bf745345d | ||
|
|
63c71ed923 | ||
|
|
93c92e8976 |
@@ -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"
|
||||||
|
|||||||
@@ -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}>
|
||||||
<Space>
|
{line.accepted_at ? (
|
||||||
{t("parts_dispatch_lines.fields.accepted_at")}
|
<Space>
|
||||||
<DateFormatter>{line.accepted_at}</DateFormatter>
|
{t("parts_dispatch_lines.fields.accepted_at")}
|
||||||
</Space>
|
<DateFormatter>{line.accepted_at}</DateFormatter>
|
||||||
|
</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
|
||||||
|
|||||||
@@ -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={
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,16 +56,47 @@ 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({
|
||||||
title: t("joblines.fields.total"),
|
imex: {
|
||||||
dataIndex: "total",
|
title: t("joblines.fields.total"),
|
||||||
key: "total",
|
dataIndex: "total",
|
||||||
align: "right",
|
key: "total",
|
||||||
sorter: (a, b) => a.total.amount - b.total.amount,
|
align: "right",
|
||||||
sortOrder: state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
|
sorter: (a, b) => a.total.amount - b.total.amount,
|
||||||
|
sortOrder: state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
|
||||||
render: (text, record) => Dinero(record.total).toFormat()
|
render: (text, record) => Dinero(record.total).toFormat()
|
||||||
}
|
},
|
||||||
|
rome: [
|
||||||
|
{
|
||||||
|
title: t("joblines.fields.amount"),
|
||||||
|
dataIndex: "base",
|
||||||
|
key: "base",
|
||||||
|
align: "right",
|
||||||
|
sorter: (a, b) => a.base.amount - b.base.amount,
|
||||||
|
sortOrder: state.sortedInfo.columnKey === "base" && state.sortedInfo.order,
|
||||||
|
render: (text, record) => Dinero(record.base).toFormat()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("joblines.fields.adjustment"),
|
||||||
|
dataIndex: "adjustment",
|
||||||
|
key: "adjustment",
|
||||||
|
align: "right",
|
||||||
|
sorter: (a, b) => a.adjustment.amount - b.adjustment.amount,
|
||||||
|
sortOrder: state.sortedInfo.columnKey === "adjustment" && state.sortedInfo.order,
|
||||||
|
render: (text, record) => Dinero(record.adjustment).toFormat()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("joblines.fields.total"),
|
||||||
|
dataIndex: "total",
|
||||||
|
key: "total",
|
||||||
|
align: "right",
|
||||||
|
sorter: (a, b) => a.total.amount - b.total.amount,
|
||||||
|
sortOrder: state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
|
||||||
|
render: (text, record) => Dinero(record.total).toFormat()
|
||||||
|
}
|
||||||
|
],
|
||||||
|
promanager: "USE_ROME"
|
||||||
|
})
|
||||||
];
|
];
|
||||||
|
|
||||||
const handleTableChange = (pagination, filters, sorter) => {
|
const handleTableChange = (pagination, filters, sorter) => {
|
||||||
@@ -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>
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
@@ -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"]}
|
||||||
|
|||||||
@@ -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"]}
|
||||||
|
|||||||
@@ -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>
|
||||||
<Form.Item label={t("jobs.fields.tax_paint_mat_rt")} name="tax_paint_mat_rt">
|
{InstanceRenderManager({ imex: true, rome: false, promanager: "USE_ROME" }) ? (
|
||||||
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
|
<>
|
||||||
</Form.Item>
|
<Form.Item label={t("jobs.fields.tax_paint_mat_rt")} name="tax_paint_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>
|
<Form.Item label={t("jobs.fields.tax_shop_mat_rt")} name="tax_shop_mat_rt">
|
||||||
|
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
|
||||||
|
</Form.Item>{" "}
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
<Form.Item label={t("jobs.fields.tax_sub_rt")} name="tax_sub_rt">
|
<Form.Item label={t("jobs.fields.tax_sub_rt")} name="tax_sub_rt">
|
||||||
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
|
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("jobs.fields.tax_lbr_rt")} name="tax_lbr_rt">
|
{InstanceRenderManager({ imex: true, rome: false, promanager: "USE_ROME" }) ? (
|
||||||
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
|
<Form.Item label={t("jobs.fields.tax_lbr_rt")} name="tax_lbr_rt">
|
||||||
</Form.Item>
|
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
|
||||||
|
</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>
|
||||||
|
|||||||
@@ -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);
|
||||||
@@ -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={{
|
||||||
|
|||||||
@@ -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,23 +56,25 @@ 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()}>
|
||||||
<FormDatePicker
|
<Space direction={"vertical"}>
|
||||||
onClick={(e) => e.stopPropagation()}
|
<FormDatePicker
|
||||||
value={(record[field] && dayjs(record[field])) || null}
|
|
||||||
onChange={handleChange}
|
|
||||||
format="MM/DD/YYYY"
|
|
||||||
isDateOnly={!time}
|
|
||||||
/>
|
|
||||||
{time && (
|
|
||||||
<TimePicker
|
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
value={(record[field] && dayjs(record[field])) || null}
|
value={(record[field] && dayjs(record[field])) || null}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
minuteStep={15}
|
format="MM/DD/YYYY"
|
||||||
format="hh:mm a"
|
isDateOnly={!time}
|
||||||
/>
|
/>
|
||||||
)}
|
{time && (
|
||||||
<Button onClick={() => setOpen(false)}>{t("general.actions.close")}</Button>
|
<TimePicker
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
value={(record[field] && dayjs(record[field])) || null}
|
||||||
|
onChange={handleChange}
|
||||||
|
minuteStep={15}
|
||||||
|
format="hh:mm a"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<Button onClick={() => setOpen(false)}>{t("general.actions.close")}</Button>
|
||||||
|
</Space>
|
||||||
</Card>
|
</Card>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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} />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label={t("jobs.fields.tax_shop_mat_rt")}
|
||||||
|
name={["md_responsibility_centers", "tax_shop_mat_rt"]}
|
||||||
|
>
|
||||||
|
<InputNumber min={0} max={100} precision={4} />
|
||||||
|
</Form.Item>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
<Form.Item label={t("jobs.fields.tax_sub_rt")} name={["md_responsibility_centers", "tax_sub_rt"]}>
|
||||||
<InputNumber min={0} max={100} precision={4} />
|
<InputNumber min={0} max={100} precision={4} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("jobs.fields.tax_shop_mat_rt")} name="tax_shop_mat_rt">
|
{InstanceRenderManager({ imex: true, rome: false, promanager: "USE_ROME" }) ? (
|
||||||
<InputNumber min={0} max={100} precision={4} />
|
<Form.Item label={t("jobs.fields.tax_lbr_rt")} name={["md_responsibility_centers", "tax_lbr_rt"]}>
|
||||||
</Form.Item>
|
<InputNumber min={0} max={100} precision={4} />
|
||||||
<Form.Item label={t("jobs.fields.tax_sub_rt")} name="tax_sub_rt">
|
</Form.Item>
|
||||||
<InputNumber min={0} max={100} precision={4} />
|
) : null}
|
||||||
</Form.Item>
|
<Form.Item label={t("jobs.fields.tax_levies_rt")} name={["md_responsibility_centers", "tax_levies_rt"]}>
|
||||||
<Form.Item label={t("jobs.fields.tax_lbr_rt")} name="tax_lbr_rt">
|
|
||||||
<InputNumber min={0} max={100} precision={4} />
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item label={t("jobs.fields.tax_levies_rt")} name="tax_levies_rt">
|
|
||||||
<InputNumber min={0} max={100} precision={4} />
|
<InputNumber min={0} max={100} precision={4} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,19 +254,34 @@ 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
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
rome: {
|
tax_tow_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||||
cieca_pft: {
|
tax_str_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||||
...bodyshop.md_responsibility_centers.taxes.tax_ty1,
|
tax_paint_mat_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||||
...bodyshop.md_responsibility_centers.taxes.tax_ty2,
|
tax_shop_mat_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||||
...bodyshop.md_responsibility_centers.taxes.tax_ty3,
|
tax_sub_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||||
...bodyshop.md_responsibility_centers.taxes.tax_ty4,
|
tax_lbr_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||||
...bodyshop.md_responsibility_centers.taxes.tax_ty5
|
tax_levies_rt: bodyshop.bill_tax_rates.state_tax_rate / 100
|
||||||
},
|
},
|
||||||
materials: bodyshop.md_responsibility_centers.cieca_pfm,
|
rome: {
|
||||||
cieca_pfl: bodyshop.md_responsibility_centers.cieca_pfl,
|
cieca_pft: {
|
||||||
parts_tax_rates: bodyshop.md_responsibility_centers.parts_tax_rates
|
...bodyshop.md_responsibility_centers.taxes.tax_ty1,
|
||||||
}
|
...bodyshop.md_responsibility_centers.taxes.tax_ty2,
|
||||||
}
|
...bodyshop.md_responsibility_centers.taxes.tax_ty3,
|
||||||
|
...bodyshop.md_responsibility_centers.taxes.tax_ty4,
|
||||||
|
...bodyshop.md_responsibility_centers.taxes.tax_ty5
|
||||||
|
},
|
||||||
|
materials: bodyshop.md_responsibility_centers.cieca_pfm,
|
||||||
|
cieca_pfl: bodyshop.md_responsibility_centers.cieca_pfl,
|
||||||
|
parts_tax_rates: bodyshop.md_responsibility_centers.parts_tax_rates,
|
||||||
|
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"
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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({
|
||||||
|
|||||||
@@ -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) => {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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?
|
||||||
|
|||||||
@@ -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,11 +918,27 @@ 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 (IsTrueOrYes(pfl[key][`lbr_tx_in${tyCounter}`])) {
|
if (key === "LA1" || key === "LA2" || key === "LA3" || key === "LA4") {
|
||||||
//This amount is taxable for this type.
|
if (IsTrueOrYes(pfl["LAU"][`lbr_tx_in${tyCounter}`])) {
|
||||||
taxableAmountsByTier[`ty${tyCounter}Tax`] = taxableAmountsByTier[`ty${tyCounter}Tax`].add(
|
//This amount is taxable for this type.
|
||||||
taxableAmounts[key]
|
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}`])) {
|
||||||
|
//This amount is taxable for this type.
|
||||||
|
taxableAmountsByTier[`ty${tyCounter}Tax`] = taxableAmountsByTier[`ty${tyCounter}Tax`].add(
|
||||||
|
taxableAmounts[key]
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (key === "TOW") {
|
} else if (key === "TOW") {
|
||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user