- Merge client update into test-beta

Signed-off-by: Dave Richer <dave@imexsystems.ca>
This commit is contained in:
Dave Richer
2024-01-18 19:20:08 -05:00
696 changed files with 92291 additions and 107075 deletions

View File

@@ -1,12 +1,12 @@
import { Card, Col, Collapse, Result, Row } from "antd";
import {Card, Col, Collapse, Result, Row} from "antd";
//import { JsonEditor as Editor } from "jsoneditor-react";
//import "jsoneditor-react/es/editor.min.css";
import React from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectJobReadOnly } from "../../redux/application/application.selectors";
import { selectCurrentUser } from "../../redux/user/user.selectors";
import {useTranslation} from "react-i18next";
import {connect} from "react-redux";
import {createStructuredSelector} from "reselect";
import {selectJobReadOnly} from "../../redux/application/application.selectors";
import {selectCurrentUser} from "../../redux/user/user.selectors";
import JobCalculateTotals from "../job-calculate-totals/job-calculate-totals.component";
import "./job-totals-table.styles.scss";
import JobTotalsTableLabor from "./job-totals.table.labor.component";
@@ -15,87 +15,88 @@ import JobTotalsTableParts from "./job-totals.table.parts.component";
import JobTotalsTableTotals from "./job-totals.table.totals.component";
const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser,
jobRO: selectJobReadOnly,
currentUser: selectCurrentUser,
jobRO: selectJobReadOnly,
});
const colSpan = {
md: { span: 24 },
lg: { span: 12 },
md: {span: 24},
lg: {span: 12},
};
export function JobsTotalsTableComponent({ jobRO, currentUser, job }) {
const { t } = useTranslation();
export function JobsTotalsTableComponent({jobRO, currentUser, job}) {
const {t} = useTranslation();
if (!!!job.job_totals) {
return (
<Card>
<Result
title={t("jobs.errors.nofinancial")}
extra={<JobCalculateTotals job={job} disabled={jobRO}/>}
/>
</Card>
);
}
if (!!!job.job_totals) {
return (
<Card>
<Result
title={t("jobs.errors.nofinancial")}
extra={<JobCalculateTotals job={job} disabled={jobRO} />}
/>
</Card>
);
}
return (
<div>
<Row gutter={[16, 16]}>
<Col {...colSpan}>
<Card title={t("jobs.labels.labortotals")}>
<JobTotalsTableLabor job={job} />
</Card>
</Col>
<Col {...colSpan}>
<Row gutter={[16, 16]}>
<Col {...colSpan}>
<Row gutter={[16, 16]}>
<Col span={24}>
<Card title={t("jobs.labels.partstotal")}>
<JobTotalsTableParts job={job} />
</Card>
<div>
<Row gutter={[16, 16]}>
<Col {...colSpan}>
<Card title={t("jobs.labels.labortotals")}>
<JobTotalsTableLabor job={job}/>
</Card>
</Col>
<Col span={24}>
<Card title={t("jobs.labels.othertotal")}>
<JobTotalsTableOther job={job} />
</Card>
</Col>
</Row>
</Col>
<Col {...colSpan}>
<Card title={t("jobs.labels.jobtotals")}>
<JobTotalsTableTotals job={job} />
</Card>
</Col>
{(currentUser.email.includes("@imex.") ||
currentUser.email.includes("@rome.")) && (
<Col span={24}>
<Card title="DEVELOPMENT USE ONLY">
<JobCalculateTotals job={job} disabled={jobRO} />
<Collapse>
<Collapse.Panel header="JSON Tree Totals">
<div>
<Col {...colSpan}>
<Row gutter={[16, 16]}>
<Col {...colSpan}>
<Row gutter={[16, 16]}>
<Col span={24}>
<Card title={t("jobs.labels.partstotal")}>
<JobTotalsTableParts job={job}/>
</Card>
</Col>
<Col span={24}>
<Card title={t("jobs.labels.othertotal")}>
<JobTotalsTableOther job={job}/>
</Card>
</Col>
</Row>
</Col>
<Col {...colSpan}>
<Card title={t("jobs.labels.jobtotals")}>
<JobTotalsTableTotals job={job}/>
</Card>
</Col>
{(currentUser.email.includes("@imex.") ||
currentUser.email.includes("@rome.")) && (
<Col span={24}>
<Card title="DEVELOPMENT USE ONLY">
<JobCalculateTotals job={job} disabled={jobRO}/>
<Collapse>
<Collapse.Panel header="JSON Tree Totals">
<div>
<pre>
{JSON.stringify(
{
CIECA: job.cieca_ttl && job.cieca_ttl.data,
CIECASTL: job.cieca_stl && job.cieca_stl.data,
ImEXCalc: job.job_totals,
},
null,
2
{
CIECA: job.cieca_ttl && job.cieca_ttl.data,
CIECASTL: job.cieca_stl && job.cieca_stl.data,
ImEXCalc: job.job_totals,
},
null,
2
)}
</pre>
</div>
</Collapse.Panel>
</Collapse>
</Card>
</Col>
)}
</Row>
</Col>
</Row>
</div>
);
</div>
</Collapse.Panel>
</Collapse>
</Card>
</Col>
)}
</Row>
</Col>
</Row>
</div>
);
}
export default connect(mapStateToProps, null)(JobsTotalsTableComponent);

View File

@@ -1,185 +1,185 @@
import { Space, Table } from "antd";
import {Space, Table} from "antd";
import Dinero from "dinero.js";
import React, { useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import React, {useMemo, useState} from "react";
import {useTranslation} from "react-i18next";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { alphaSort } from "../../utils/sorters";
import {alphaSort} from "../../utils/sorters";
export default function JobTotalsTableLabor({ job }) {
const { t } = useTranslation();
const [state, setState] = useState({
sortedInfo: {
columnKey: "profitcenter_labor",
field: "profitcenter_labor",
order: "ascend",
},
filteredInfo: {},
});
export default function JobTotalsTableLabor({job}) {
const {t} = useTranslation();
const [state, setState] = useState({
sortedInfo: {
columnKey: "profitcenter_labor",
field: "profitcenter_labor",
order: "ascend",
},
filteredInfo: {},
});
const data = useMemo(() => {
return Object.keys(job.job_totals.rates)
.filter(
(key) =>
key !== "mapa" &&
key !== "mash" &&
key !== "subtotal" &&
key !== "rates_subtotal"
)
.map((key) => {
return {
id: key,
...job.job_totals.rates[key],
};
});
}, [job.job_totals.rates]);
const data = useMemo(() => {
return Object.keys(job.job_totals.rates)
.filter(
(key) =>
key !== "mapa" &&
key !== "mash" &&
key !== "subtotal" &&
key !== "rates_subtotal"
)
.map((key) => {
return {
id: key,
...job.job_totals.rates[key],
};
});
}, [job.job_totals.rates]);
const columns = [
{
title: t("joblines.fields.profitcenter_labor"),
dataIndex: "profitcenter_labor",
key: "profitcenter_labor",
defaultSortOrder: "ascend",
sorter: (a, b) =>
alphaSort(
t(`jobs.fields.rate_${a.id.toLowerCase()}`),
t(`jobs.fields.rate_${b.id.toLowerCase()}`)
),
sortOrder:
state.sortedInfo.columnKey === "profitcenter_labor" &&
state.sortedInfo.order,
render: (text, record) =>
t(`jobs.fields.rate_${record.id.toLowerCase()}`),
},
{
title: t("jobs.labels.rates"),
dataIndex: "rate",
key: "rate",
align: "right",
sorter: (a, b) => a.rate - b.rate,
sortOrder:
state.sortedInfo.columnKey === "rate" && state.sortedInfo.order,
render: (text, record) => (
<CurrencyFormatter>{record.rate}</CurrencyFormatter>
),
},
{
title: t("joblines.fields.mod_lb_hrs"),
dataIndex: "mod_lb_hrs",
const columns = [
{
title: t("joblines.fields.profitcenter_labor"),
dataIndex: "profitcenter_labor",
key: "profitcenter_labor",
defaultSortOrder: "ascend",
sorter: (a, b) =>
alphaSort(
t(`jobs.fields.rate_${a.id.toLowerCase()}`),
t(`jobs.fields.rate_${b.id.toLowerCase()}`)
),
sortOrder:
state.sortedInfo.columnKey === "profitcenter_labor" &&
state.sortedInfo.order,
render: (text, record) =>
t(`jobs.fields.rate_${record.id.toLowerCase()}`),
},
{
title: t("jobs.labels.rates"),
dataIndex: "rate",
key: "rate",
align: "right",
sorter: (a, b) => a.rate - b.rate,
sortOrder:
state.sortedInfo.columnKey === "rate" && state.sortedInfo.order,
render: (text, record) => (
<CurrencyFormatter>{record.rate}</CurrencyFormatter>
),
},
{
title: t("joblines.fields.mod_lb_hrs"),
dataIndex: "mod_lb_hrs",
key: "mod_lb_hrs",
sorter: (a, b) => a.mod_lb_hrs - b.mod_lb_hrs,
sortOrder:
state.sortedInfo.columnKey === "mod_lb_hrs" && state.sortedInfo.order,
key: "mod_lb_hrs",
sorter: (a, b) => a.mod_lb_hrs - b.mod_lb_hrs,
sortOrder:
state.sortedInfo.columnKey === "mod_lb_hrs" && state.sortedInfo.order,
render: (text, record) => record.hours.toFixed(1),
},
{
title: t("joblines.fields.total"),
dataIndex: "total",
key: "total",
align: "right",
sorter: (a, b) => a.total.amount - b.total.amount,
sortOrder:
state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
render: (text, record) => record.hours.toFixed(1),
},
{
title: t("joblines.fields.total"),
dataIndex: "total",
key: "total",
align: "right",
sorter: (a, b) => a.total.amount - b.total.amount,
sortOrder:
state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
render: (text, record) => Dinero(record.total).toFormat(),
},
];
render: (text, record) => Dinero(record.total).toFormat(),
},
];
const handleTableChange = (pagination, filters, sorter) => {
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
};
return (
<Table
columns={columns}
rowKey="id"
pagination={false}
onChange={handleTableChange}
dataSource={data}
scroll={{
x: true,
}}
summary={() => (
<>
<Table.Summary.Row>
<Table.Summary.Cell>
<strong>{t("jobs.labels.labor_rates_subtotal")}</strong>
</Table.Summary.Cell>
<Table.Summary.Cell />
<Table.Summary.Cell>
{(
job.job_totals.rates.mapa.hours +
job.job_totals.rates.mash.hours
).toFixed(1)}
</Table.Summary.Cell>
<Table.Summary.Cell align="right">
<strong>
{Dinero(job.job_totals.rates.rates_subtotal).toFormat()}
</strong>
</Table.Summary.Cell>
</Table.Summary.Row>
<Table.Summary.Row>
<Table.Summary.Cell>
<Space>
{t("jobs.labels.mapa")}
{job.materials &&
job.materials.MAPA &&
job.materials.MAPA.cal_maxdlr !== undefined &&
t("jobs.labels.threshhold", {
amount: job.materials.MAPA.cal_maxdlr,
})}
</Space>
</Table.Summary.Cell>
<Table.Summary.Cell align="right">
<CurrencyFormatter>
{job.job_totals.rates.mapa.rate}
</CurrencyFormatter>
</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>
</Table.Summary.Row>
<Table.Summary.Row>
<Table.Summary.Cell>
<Space wrap>
{t("jobs.labels.mash")}
{job.materials &&
job.materials.MASH &&
job.materials.MASH.cal_maxdlr !== undefined &&
t("jobs.labels.threshhold", {
amount: job.materials.MASH.cal_maxdlr,
})}
</Space>
</Table.Summary.Cell>
<Table.Summary.Cell align="right">
<CurrencyFormatter>
{job.job_totals.rates.mash.rate}
</CurrencyFormatter>
</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>
</Table.Summary.Row>
<Table.Summary.Row>
<Table.Summary.Cell>
<strong>{t("jobs.labels.rates_subtotal")}</strong>
</Table.Summary.Cell>
<Table.Summary.Cell />
<Table.Summary.Cell />
<Table.Summary.Cell align="right">
<strong>
{Dinero(job.job_totals.rates.subtotal).toFormat()}
</strong>
</Table.Summary.Cell>
</Table.Summary.Row>
</>
)}
/>
);
const handleTableChange = (pagination, filters, sorter) => {
setState({...state, filteredInfo: filters, sortedInfo: sorter});
};
return (
<Table
columns={columns}
rowKey="id"
pagination={false}
onChange={handleTableChange}
dataSource={data}
scroll={{
x: true,
}}
summary={() => (
<>
<Table.Summary.Row>
<Table.Summary.Cell>
<strong>{t("jobs.labels.labor_rates_subtotal")}</strong>
</Table.Summary.Cell>
<Table.Summary.Cell/>
<Table.Summary.Cell>
{(
job.job_totals.rates.mapa.hours +
job.job_totals.rates.mash.hours
).toFixed(1)}
</Table.Summary.Cell>
<Table.Summary.Cell align="right">
<strong>
{Dinero(job.job_totals.rates.rates_subtotal).toFormat()}
</strong>
</Table.Summary.Cell>
</Table.Summary.Row>
<Table.Summary.Row>
<Table.Summary.Cell>
<Space>
{t("jobs.labels.mapa")}
{job.materials &&
job.materials.MAPA &&
job.materials.MAPA.cal_maxdlr !== undefined &&
t("jobs.labels.threshhold", {
amount: job.materials.MAPA.cal_maxdlr,
})}
</Space>
</Table.Summary.Cell>
<Table.Summary.Cell align="right">
<CurrencyFormatter>
{job.job_totals.rates.mapa.rate}
</CurrencyFormatter>
</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>
</Table.Summary.Row>
<Table.Summary.Row>
<Table.Summary.Cell>
<Space wrap>
{t("jobs.labels.mash")}
{job.materials &&
job.materials.MASH &&
job.materials.MASH.cal_maxdlr !== undefined &&
t("jobs.labels.threshhold", {
amount: job.materials.MASH.cal_maxdlr,
})}
</Space>
</Table.Summary.Cell>
<Table.Summary.Cell align="right">
<CurrencyFormatter>
{job.job_totals.rates.mash.rate}
</CurrencyFormatter>
</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>
</Table.Summary.Row>
<Table.Summary.Row>
<Table.Summary.Cell>
<strong>{t("jobs.labels.rates_subtotal")}</strong>
</Table.Summary.Cell>
<Table.Summary.Cell/>
<Table.Summary.Cell/>
<Table.Summary.Cell align="right">
<strong>
{Dinero(job.job_totals.rates.subtotal).toFormat()}
</strong>
</Table.Summary.Cell>
</Table.Summary.Row>
</>
)}
/>
);
}

View File

@@ -1,106 +1,106 @@
import { Table } from "antd";
import {Table} from "antd";
import Dinero from "dinero.js";
import React, { useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { alphaSort } from "../../utils/sorters";
import React, {useMemo, useState} from "react";
import {useTranslation} from "react-i18next";
import {alphaSort} from "../../utils/sorters";
export default function JobTotalsTableOther({ job }) {
const { t } = useTranslation();
const [state, setState] = useState({
sortedInfo: {},
filteredInfo: {},
});
export default function JobTotalsTableOther({job}) {
const {t} = useTranslation();
const [state, setState] = useState({
sortedInfo: {},
filteredInfo: {},
});
const data = useMemo(() => {
return [
...((job.job_totals.additional.additionalCostItems &&
job.job_totals.additional.additionalCostItems.map((i) => {
return {
key: i.key,
total: i.total,
};
})) ||
[]),
{
key: t("jobs.fields.adjustment_bottom_line"),
total: job.job_totals.additional.adjustments,
},
{
key: t("jobs.fields.towing_payable"),
total: job.job_totals.additional.towing,
},
{
key: t("jobs.fields.storage_payable"),
total: job.job_totals.additional.storage,
},
// {
// key: t("jobs.fields.ca_bc_pvrt"),
// total: job.job_totals.additional.pvrt,
// },
const data = useMemo(() => {
return [
...((job.job_totals.additional.additionalCostItems &&
job.job_totals.additional.additionalCostItems.map((i) => {
return {
key: i.key,
total: i.total,
};
})) ||
[]),
{
key: t("jobs.fields.adjustment_bottom_line"),
total: job.job_totals.additional.adjustments,
},
{
key: t("jobs.fields.towing_payable"),
total: job.job_totals.additional.towing,
},
{
key: t("jobs.fields.storage_payable"),
total: job.job_totals.additional.storage,
},
// {
// key: t("jobs.fields.ca_bc_pvrt"),
// total: job.job_totals.additional.pvrt,
// },
];
}, [job.job_totals, t]);
const columns = [
{
title: t("general.labels.item"),
dataIndex: "key",
key: "key",
sorter: (a, b) => alphaSort(a.key, b.key),
sortOrder: state.sortedInfo.columnKey === "key" && state.sortedInfo.order,
width: "0%",
},
{
title: t("joblines.fields.total"),
dataIndex: "total",
key: "total",
sorter: (a, b) => a.total.amount - b.total.amount,
sortOrder:
state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
width: "20%",
align: "right",
render: (text, record) => Dinero(record.total).toFormat(),
},
];
}, [job.job_totals, t]);
const columns = [
{
title: t("general.labels.item"),
dataIndex: "key",
key: "key",
sorter: (a, b) => alphaSort(a.key, b.key),
sortOrder: state.sortedInfo.columnKey === "key" && state.sortedInfo.order,
width: "0%",
},
{
title: t("joblines.fields.total"),
dataIndex: "total",
key: "total",
sorter: (a, b) => a.total.amount - b.total.amount,
sortOrder:
state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
width: "20%",
align: "right",
render: (text, record) => Dinero(record.total).toFormat(),
},
];
const handleTableChange = (pagination, filters, sorter) => {
setState({...state, filteredInfo: filters, sortedInfo: sorter});
};
return (
<Table
columns={columns}
rowKey="key"
pagination={false}
onChange={handleTableChange}
dataSource={data}
scroll={{
x: true,
}}
summary={() => (
<>
<Table.Summary.Row>
<Table.Summary.Cell>
<strong>{t("jobs.labels.additionaltotal")}</strong>
</Table.Summary.Cell>
const handleTableChange = (pagination, filters, sorter) => {
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
};
return (
<Table
columns={columns}
rowKey="key"
pagination={false}
onChange={handleTableChange}
dataSource={data}
scroll={{
x: true,
}}
summary={() => (
<>
<Table.Summary.Row>
<Table.Summary.Cell>
<strong>{t("jobs.labels.additionaltotal")}</strong>
</Table.Summary.Cell>
<Table.Summary.Cell align="right">
<strong>
{Dinero(job.job_totals.additional.total).toFormat()}
</strong>
</Table.Summary.Cell>
</Table.Summary.Row>
<Table.Summary.Row>
<Table.Summary.Cell>
<strong>{t("jobs.labels.subletstotal")}</strong>
</Table.Summary.Cell>
<Table.Summary.Cell align="right">
<strong>
{Dinero(job.job_totals.additional.total).toFormat()}
</strong>
</Table.Summary.Cell>
</Table.Summary.Row>
<Table.Summary.Row>
<Table.Summary.Cell>
<strong>{t("jobs.labels.subletstotal")}</strong>
</Table.Summary.Cell>
<Table.Summary.Cell align="right">
<strong>
{Dinero(job.job_totals.parts.sublets.total).toFormat()}
</strong>
</Table.Summary.Cell>
</Table.Summary.Row>
</>
)}
/>
);
<Table.Summary.Cell align="right">
<strong>
{Dinero(job.job_totals.parts.sublets.total).toFormat()}
</strong>
</Table.Summary.Cell>
</Table.Summary.Row>
</>
)}
/>
);
}

View File

@@ -1,131 +1,131 @@
import { Table } from "antd";
import {Table} from "antd";
import Dinero from "dinero.js";
import React, { useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { alphaSort } from "../../utils/sorters";
import React, {useMemo, useState} from "react";
import {useTranslation} from "react-i18next";
import {alphaSort} from "../../utils/sorters";
export default function JobTotalsTableParts({ job }) {
const { t } = useTranslation();
const [state, setState] = useState({
sortedInfo: {},
filteredInfo: {},
});
const insuranceAdjustments = useMemo(() => {
if (!job.job_totals) return [];
if (!job.job_totals?.parts?.adjustments) return [];
const adjs = [];
Object.keys(job.job_totals?.parts?.adjustments).forEach((key) => {
if (Dinero(job.job_totals?.parts?.adjustments[key]).getAmount() !== 0) {
adjs.push({
id: key,
amount: Dinero(job.job_totals.parts.adjustments[key]),
});
}
export default function JobTotalsTableParts({job}) {
const {t} = useTranslation();
const [state, setState] = useState({
sortedInfo: {},
filteredInfo: {},
});
return adjs;
}, [job.job_totals]);
const insuranceAdjustments = useMemo(() => {
if (!job.job_totals) return [];
if (!job.job_totals?.parts?.adjustments) return [];
const adjs = [];
Object.keys(job.job_totals?.parts?.adjustments).forEach((key) => {
if (Dinero(job.job_totals?.parts?.adjustments[key]).getAmount() !== 0) {
adjs.push({
id: key,
amount: Dinero(job.job_totals.parts.adjustments[key]),
});
}
});
const data = useMemo(() => {
return Object.keys(job.job_totals.parts.parts.list)
.filter(
(key) =>
key !== "mapa" &&
key !== "mash" &&
key !== "subtotal" &&
key !== "rates_subtotal"
)
.map((key) => {
return {
id: key,
...job.job_totals.parts.parts.list[key],
};
});
}, [job.job_totals.parts.parts.list]);
return adjs;
}, [job.job_totals]);
const columns = [
{
title: t("joblines.fields.part_type"),
dataIndex: "id",
key: "id",
sorter: (a, b) =>
alphaSort(
t(`jobs.fields.${a.id.toLowerCase()}`),
t(`jobs.fields.${b.id.toLowerCase()}`)
),
width: "80%",
sortOrder: state.sortedInfo.columnKey === "id" && state.sortedInfo.order,
render: (text, record) => t(`jobs.fields.${record.id.toLowerCase()}`),
},
{
title: t("joblines.fields.total"),
dataIndex: "total",
key: "total",
sorter: (a, b) => a.total.amount - b.total.amount,
sortOrder:
state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
width: "20%",
align: "right",
render: (text, record) => Dinero(record.total).toFormat(),
},
];
const data = useMemo(() => {
return Object.keys(job.job_totals.parts.parts.list)
.filter(
(key) =>
key !== "mapa" &&
key !== "mash" &&
key !== "subtotal" &&
key !== "rates_subtotal"
)
.map((key) => {
return {
id: key,
...job.job_totals.parts.parts.list[key],
};
});
}, [job.job_totals.parts.parts.list]);
const handleTableChange = (pagination, filters, sorter) => {
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
};
return (
<Table
columns={columns}
rowKey="id"
pagination={false}
onChange={handleTableChange}
dataSource={data}
scroll={{
x: true,
}}
summary={() => (
<>
<Table.Summary.Row>
<Table.Summary.Cell>
{t("jobs.labels.prt_dsmk_total")}
</Table.Summary.Cell>
<Table.Summary.Cell align="right">
{Dinero(job.job_totals.parts.parts.prt_dsmk_total).toFormat()}
</Table.Summary.Cell>
</Table.Summary.Row>
const columns = [
{
title: t("joblines.fields.part_type"),
dataIndex: "id",
key: "id",
sorter: (a, b) =>
alphaSort(
t(`jobs.fields.${a.id.toLowerCase()}`),
t(`jobs.fields.${b.id.toLowerCase()}`)
),
width: "80%",
sortOrder: state.sortedInfo.columnKey === "id" && state.sortedInfo.order,
render: (text, record) => t(`jobs.fields.${record.id.toLowerCase()}`),
},
{
title: t("joblines.fields.total"),
dataIndex: "total",
key: "total",
sorter: (a, b) => a.total.amount - b.total.amount,
sortOrder:
state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
width: "20%",
align: "right",
render: (text, record) => Dinero(record.total).toFormat(),
},
];
<Table.Summary.Row>
<Table.Summary.Cell>
<strong>{t("jobs.labels.partstotal")}</strong>
</Table.Summary.Cell>
const handleTableChange = (pagination, filters, sorter) => {
setState({...state, filteredInfo: filters, sortedInfo: sorter});
};
return (
<Table
columns={columns}
rowKey="id"
pagination={false}
onChange={handleTableChange}
dataSource={data}
scroll={{
x: true,
}}
summary={() => (
<>
<Table.Summary.Row>
<Table.Summary.Cell>
{t("jobs.labels.prt_dsmk_total")}
</Table.Summary.Cell>
<Table.Summary.Cell align="right">
{Dinero(job.job_totals.parts.parts.prt_dsmk_total).toFormat()}
</Table.Summary.Cell>
</Table.Summary.Row>
<Table.Summary.Cell align="right">
<strong>
{Dinero(job.job_totals.parts.parts.total).toFormat()}
</strong>
</Table.Summary.Cell>
</Table.Summary.Row>
{insuranceAdjustments.length > 0 && (
<Table.Summary.Row>
<Table.Summary.Cell colSpan={24}>
{t("jobs.labels.profileadjustments")}
</Table.Summary.Cell>
</Table.Summary.Row>
)}
{insuranceAdjustments.map((adj, idx) => (
<Table.Summary.Row key={idx}>
<Table.Summary.Cell>
{t(`jobs.fields.${adj.id.toLowerCase()}`)}
</Table.Summary.Cell>
<Table.Summary.Row>
<Table.Summary.Cell>
<strong>{t("jobs.labels.partstotal")}</strong>
</Table.Summary.Cell>
<Table.Summary.Cell align="right">
{adj.amount.toFormat()}
</Table.Summary.Cell>
</Table.Summary.Row>
))}
</>
)}
/>
);
<Table.Summary.Cell align="right">
<strong>
{Dinero(job.job_totals.parts.parts.total).toFormat()}
</strong>
</Table.Summary.Cell>
</Table.Summary.Row>
{insuranceAdjustments.length > 0 && (
<Table.Summary.Row>
<Table.Summary.Cell colSpan={24}>
{t("jobs.labels.profileadjustments")}
</Table.Summary.Cell>
</Table.Summary.Row>
)}
{insuranceAdjustments.map((adj, idx) => (
<Table.Summary.Row key={idx}>
<Table.Summary.Cell>
{t(`jobs.fields.${adj.id.toLowerCase()}`)}
</Table.Summary.Cell>
<Table.Summary.Cell align="right">
{adj.amount.toFormat()}
</Table.Summary.Cell>
</Table.Summary.Row>
))}
</>
)}
/>
);
}

View File

@@ -1,204 +1,205 @@
import { Table } from "antd";
import {Table} from "antd";
import Dinero from "dinero.js";
import React, { useMemo } from "react";
import { useTranslation } from "react-i18next";
import React, {useMemo} from "react";
import {useTranslation} from "react-i18next";
import {connect} from "react-redux";
import {createStructuredSelector} from "reselect";
import {selectBodyshop} from "../../redux/user/user.selectors";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
bodyshop: selectBodyshop,
//currentUser: selectCurrentUser
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(
mapStateToProps,
mapDispatchToProps
mapStateToProps,
mapDispatchToProps
)(JobTotalsTableTotals);
export function JobTotalsTableTotals({ bodyshop, job }) {
const { t } = useTranslation();
export function JobTotalsTableTotals({bodyshop, job}) {
const {t} = useTranslation();
const data = useMemo(() => {
return [
{
key: t("jobs.labels.subtotal"),
total: job.job_totals.totals.subtotal,
bold: true,
},
const data = useMemo(() => {
return [
{
key: t("jobs.labels.subtotal"),
total: job.job_totals.totals.subtotal,
bold: true,
},
...(job.job_totals.totals.us_sales_tax_breakdown
? [
{
key: `${
bodyshop.md_responsibility_centers.taxes.tax_ty1?.tax_type1 ||
"T1"
} - ${[
job.cieca_pft.ty1_rate1,
job.cieca_pft.ty1_rate2,
job.cieca_pft.ty1_rate3,
job.cieca_pft.ty1_rate4,
job.cieca_pft.ty1_rate5,
]
.filter((i) => i > 0)
.join(", ")}%`,
total: job.job_totals.totals.us_sales_tax_breakdown.ty1Tax,
},
{
key: `${
bodyshop.md_responsibility_centers.taxes.tax_ty2?.tax_type2 ||
"T2"
} - ${[
job.cieca_pft.ty2_rate1,
job.cieca_pft.ty2_rate2,
job.cieca_pft.ty2_rate3,
job.cieca_pft.ty2_rate4,
job.cieca_pft.ty2_rate5,
]
.filter((i) => i > 0)
.join(", ")}%`,
total: job.job_totals.totals.us_sales_tax_breakdown.ty2Tax,
},
{
key: `${
bodyshop.md_responsibility_centers.taxes.tax_ty3?.tax_type3 ||
"T3"
} - ${[
job.cieca_pft.ty3_rate1,
job.cieca_pft.ty3_rate2,
job.cieca_pft.ty3_rate3,
job.cieca_pft.ty3_rate4,
job.cieca_pft.ty3_rate5,
]
.filter((i) => i > 0)
.join(", ")}%`,
total: job.job_totals.totals.us_sales_tax_breakdown.ty3Tax,
},
{
key: `${
bodyshop.md_responsibility_centers.taxes.tax_ty4?.tax_type4 ||
"T4"
} - ${[
job.cieca_pft.ty4_rate1,
job.cieca_pft.ty4_rate2,
job.cieca_pft.ty4_rate3,
job.cieca_pft.ty4_rate4,
job.cieca_pft.ty4_rate5,
]
.filter((i) => i > 0)
.join(", ")}%`,
total: job.job_totals.totals.us_sales_tax_breakdown.ty4Tax,
},
{
key: `${
bodyshop.md_responsibility_centers.taxes.tax_ty5?.tax_type5 ||
"TT"
} - ${[
job.cieca_pft.ty5_rate1,
job.cieca_pft.ty5_rate2,
job.cieca_pft.ty5_rate3,
job.cieca_pft.ty5_rate4,
job.cieca_pft.ty5_rate5,
]
.filter((i) => i > 0)
.join(", ")}%`,
total: job.job_totals.totals.us_sales_tax_breakdown.ty5Tax,
},
{
key: t("jobs.labels.total_sales_tax"),
bold: true,
total: Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty1Tax)
.add(
Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty2Tax)
)
.add(
Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty3Tax)
)
.add(
Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty4Tax)
)
.add(
Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty5Tax)
).toJSON(),
},
].filter((item) => item.total.amount !== 0)
: [
{
key: t("jobs.labels.state_tax_amt"),
total: job.job_totals.totals.state_tax,
},
]),
...(job.job_totals.totals.us_sales_tax_breakdown
? [
{
key: `${
bodyshop.md_responsibility_centers.taxes.tax_ty1?.tax_type1 ||
"T1"
} - ${[
job.cieca_pft.ty1_rate1,
job.cieca_pft.ty1_rate2,
job.cieca_pft.ty1_rate3,
job.cieca_pft.ty1_rate4,
job.cieca_pft.ty1_rate5,
]
.filter((i) => i > 0)
.join(", ")}%`,
total: job.job_totals.totals.us_sales_tax_breakdown.ty1Tax,
},
{
key: `${
bodyshop.md_responsibility_centers.taxes.tax_ty2?.tax_type2 ||
"T2"
} - ${[
job.cieca_pft.ty2_rate1,
job.cieca_pft.ty2_rate2,
job.cieca_pft.ty2_rate3,
job.cieca_pft.ty2_rate4,
job.cieca_pft.ty2_rate5,
]
.filter((i) => i > 0)
.join(", ")}%`,
total: job.job_totals.totals.us_sales_tax_breakdown.ty2Tax,
},
{
key: `${
bodyshop.md_responsibility_centers.taxes.tax_ty3?.tax_type3 ||
"T3"
} - ${[
job.cieca_pft.ty3_rate1,
job.cieca_pft.ty3_rate2,
job.cieca_pft.ty3_rate3,
job.cieca_pft.ty3_rate4,
job.cieca_pft.ty3_rate5,
]
.filter((i) => i > 0)
.join(", ")}%`,
total: job.job_totals.totals.us_sales_tax_breakdown.ty3Tax,
},
{
key: `${
bodyshop.md_responsibility_centers.taxes.tax_ty4?.tax_type4 ||
"T4"
} - ${[
job.cieca_pft.ty4_rate1,
job.cieca_pft.ty4_rate2,
job.cieca_pft.ty4_rate3,
job.cieca_pft.ty4_rate4,
job.cieca_pft.ty4_rate5,
]
.filter((i) => i > 0)
.join(", ")}%`,
total: job.job_totals.totals.us_sales_tax_breakdown.ty4Tax,
},
{
key: `${
bodyshop.md_responsibility_centers.taxes.tax_ty5?.tax_type5 ||
"TT"
} - ${[
job.cieca_pft.ty5_rate1,
job.cieca_pft.ty5_rate2,
job.cieca_pft.ty5_rate3,
job.cieca_pft.ty5_rate4,
job.cieca_pft.ty5_rate5,
]
.filter((i) => i > 0)
.join(", ")}%`,
total: job.job_totals.totals.us_sales_tax_breakdown.ty5Tax,
},
{
key: t("jobs.labels.total_sales_tax"),
bold: true,
total: Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty1Tax)
.add(
Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty2Tax)
)
.add(
Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty3Tax)
)
.add(
Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty4Tax)
)
.add(
Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty5Tax)
).toJSON(),
},
].filter((item) => item.total.amount !== 0)
: [
{
key: t("jobs.labels.state_tax_amt"),
total: job.job_totals.totals.state_tax,
},
]),
{
key: t("jobs.labels.total_repairs"),
total: job.job_totals.totals.total_repairs,
bold: true,
},
{
key: t("jobs.fields.ded_amt"),
total: job.job_totals.totals.custPayable.deductible,
},
// {
// key: t("jobs.fields.federal_tax_payable"),
// total: job.job_totals.totals.custPayable.federal_tax,
// },
{
key: t("jobs.fields.other_amount_payable"),
total: job.job_totals.totals.custPayable.other_customer_amount,
},
{
key: t("jobs.fields.depreciation_taxes"),
total: job.job_totals.totals.custPayable.dep_taxes,
},
{
key: t("jobs.labels.total_repairs"),
total: job.job_totals.totals.total_repairs,
bold: true,
},
{
key: t("jobs.fields.ded_amt"),
total: job.job_totals.totals.custPayable.deductible,
},
// {
// key: t("jobs.fields.federal_tax_payable"),
// total: job.job_totals.totals.custPayable.federal_tax,
// },
{
key: t("jobs.fields.other_amount_payable"),
total: job.job_totals.totals.custPayable.other_customer_amount,
},
{
key: t("jobs.fields.depreciation_taxes"),
total: job.job_totals.totals.custPayable.dep_taxes,
},
{
key: t("jobs.labels.total_cust_payable"),
total: job.job_totals.totals.custPayable.total,
bold: true,
},
{
key: t("jobs.labels.net_repairs"),
total: job.job_totals.totals.net_repairs,
bold: true,
},
{
key: t("jobs.labels.total_cust_payable"),
total: job.job_totals.totals.custPayable.total,
bold: true,
},
{
key: t("jobs.labels.net_repairs"),
total: job.job_totals.totals.net_repairs,
bold: true,
},
];
}, [job.job_totals, job.cieca_pft, t, bodyshop.md_responsibility_centers]);
const columns = [
{
//title: t("joblines.fields.part_type"),
dataIndex: "key",
key: "key",
width: "80%",
onCell: (record, rowIndex) => {
return {style: {fontWeight: record.bold && "bold"}};
},
},
{
title: t("joblines.fields.total"),
dataIndex: "total",
key: "total",
align: "right",
render: (text, record) => Dinero(record.total).toFormat(),
width: "20%",
onCell: (record, rowIndex) => {
return {style: {fontWeight: record.bold && "bold"}};
},
},
];
}, [job.job_totals, job.cieca_pft, t, bodyshop.md_responsibility_centers]);
const columns = [
{
//title: t("joblines.fields.part_type"),
dataIndex: "key",
key: "key",
width: "80%",
onCell: (record, rowIndex) => {
return { style: { fontWeight: record.bold && "bold" } };
},
},
{
title: t("joblines.fields.total"),
dataIndex: "total",
key: "total",
align: "right",
render: (text, record) => Dinero(record.total).toFormat(),
width: "20%",
onCell: (record, rowIndex) => {
return { style: { fontWeight: record.bold && "bold" } };
},
},
];
return (
<Table
columns={columns}
rowKey="key"
showHeader={false}
pagination={false}
dataSource={data}
scroll={{
x: true,
}}
/>
);
return (
<Table
columns={columns}
rowKey="key"
showHeader={false}
pagination={false}
dataSource={data}
scroll={{
x: true,
}}
/>
);
}