Job costing improvements. IO-527
This commit is contained in:
@@ -8,7 +8,7 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
|
|||||||
import JobCostingPartsTable from "../job-costing-parts-table/job-costing-parts-table.component";
|
import JobCostingPartsTable from "../job-costing-parts-table/job-costing-parts-table.component";
|
||||||
import JobCostingStatistics from "../job-costing-statistics/job-costing-statistics.component";
|
import JobCostingStatistics from "../job-costing-statistics/job-costing-statistics.component";
|
||||||
import JobCostingPie from "./job-costing-modal.pie.component";
|
import JobCostingPie from "./job-costing-modal.pie.component";
|
||||||
|
import _ from "lodash";
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
});
|
});
|
||||||
@@ -18,6 +18,11 @@ const mapDispatchToProps = (dispatch) => ({
|
|||||||
|
|
||||||
export function JobCostingModalComponent({ bodyshop, job }) {
|
export function JobCostingModalComponent({ bodyshop, job }) {
|
||||||
const defaultProfits = bodyshop.md_responsibility_centers.defaults.profits;
|
const defaultProfits = bodyshop.md_responsibility_centers.defaults.profits;
|
||||||
|
const allProfitCenters = _.union(
|
||||||
|
bodyshop.md_responsibility_centers.profits.map((p) => p.name),
|
||||||
|
bodyshop.md_responsibility_centers.costs.map((p) => p.name)
|
||||||
|
);
|
||||||
|
|
||||||
// const defaultCosts = bodyshop.md_responsibility_centers.defaults.costs;
|
// const defaultCosts = bodyshop.md_responsibility_centers.defaults.costs;
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const jobLineTotalsByProfitCenter =
|
const jobLineTotalsByProfitCenter =
|
||||||
@@ -71,6 +76,7 @@ export function JobCostingModalComponent({ bodyshop, job }) {
|
|||||||
.multiply(line_val.quantity)
|
.multiply(line_val.quantity)
|
||||||
.multiply(bill_val.is_credit_memo ? -1 : 1)
|
.multiply(bill_val.is_credit_memo ? -1 : 1)
|
||||||
);
|
);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
return bill_acc;
|
return bill_acc;
|
||||||
@@ -107,8 +113,8 @@ export function JobCostingModalComponent({ bodyshop, job }) {
|
|||||||
gppercentFormatted: null,
|
gppercentFormatted: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
const costCenterData = Object.keys(defaultProfits).map((key, idx) => {
|
const costCenterData = allProfitCenters.map((key, idx) => {
|
||||||
const ccVal = defaultProfits[key];
|
const ccVal = key; // defaultProfits[key];
|
||||||
const sale_labor =
|
const sale_labor =
|
||||||
jobLineTotalsByProfitCenter.labor[ccVal] || Dinero({ amount: 0 });
|
jobLineTotalsByProfitCenter.labor[ccVal] || Dinero({ amount: 0 });
|
||||||
const sale_parts =
|
const sale_parts =
|
||||||
@@ -178,7 +184,11 @@ export function JobCostingModalComponent({ bodyshop, job }) {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<JobCostingStatistics job={job} summaryData={summaryData} />
|
<JobCostingStatistics job={job} summaryData={summaryData} />
|
||||||
<JobCostingPartsTable job={job} data={costCenterData} />
|
<JobCostingPartsTable
|
||||||
|
job={job}
|
||||||
|
data={costCenterData}
|
||||||
|
summaryData={summaryData}
|
||||||
|
/>
|
||||||
<div className="imex-flex-row">
|
<div className="imex-flex-row">
|
||||||
<div style={{ flex: 1 }}>
|
<div style={{ flex: 1 }}>
|
||||||
<Typography.Title level={4}>
|
<Typography.Title level={4}>
|
||||||
|
|||||||
@@ -37,7 +37,9 @@ export function JobCostingModalContainer({
|
|||||||
<Modal
|
<Modal
|
||||||
visible={visible}
|
visible={visible}
|
||||||
title={t("jobs.labels.jobcosting")}
|
title={t("jobs.labels.jobcosting")}
|
||||||
|
onOk={() => toggleModalVisible()}
|
||||||
onCancel={() => toggleModalVisible()}
|
onCancel={() => toggleModalVisible()}
|
||||||
|
cancelButtonProps={{ style: { display: "none" } }}
|
||||||
width="90%"
|
width="90%"
|
||||||
destroyOnClose
|
destroyOnClose
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -44,8 +44,6 @@ export default function JobCostingPieComponent({
|
|||||||
Calculatedata,
|
Calculatedata,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
console.log(type, memoizedData);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ResponsiveContainer width="100%" height={175}>
|
<ResponsiveContainer width="100%" height={175}>
|
||||||
<PieChart>
|
<PieChart>
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { Table } from "antd";
|
import { Input, Table, Typography } from "antd";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { alphaSort } from "../../utils/sorters";
|
import { alphaSort } from "../../utils/sorters";
|
||||||
|
|
||||||
export default function JobCostingPartsTable({ job, data }) {
|
export default function JobCostingPartsTable({ job, data, summaryData }) {
|
||||||
|
const [searchText, setSearchText] = useState("");
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
sortedInfo: {},
|
sortedInfo: {},
|
||||||
});
|
});
|
||||||
@@ -59,16 +60,61 @@ export default function JobCostingPartsTable({ job, data }) {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const filteredData =
|
||||||
|
searchText === ""
|
||||||
|
? data
|
||||||
|
: data.filter((d) =>
|
||||||
|
(d.cost_center || "")
|
||||||
|
.toString()
|
||||||
|
.toLowerCase()
|
||||||
|
.includes(searchText.toLowerCase())
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Table
|
<Table
|
||||||
size="small"
|
size="small"
|
||||||
|
title={() => {
|
||||||
|
return (
|
||||||
|
<div className="imex-table-header">
|
||||||
|
<div className="imex-table-header__search">
|
||||||
|
<Input.Search
|
||||||
|
placeholder={t("general.labels.search")}
|
||||||
|
value={searchText}
|
||||||
|
onChange={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setSearchText(e.target.value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
scroll={{ x: "50%", y: "40rem" }}
|
scroll={{ x: "50%", y: "40rem" }}
|
||||||
onChange={handleTableChange}
|
onChange={handleTableChange}
|
||||||
pagination={{ position: "top", defaultPageSize: 25 }}
|
pagination={{ position: "top", defaultPageSize: 25 }}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
dataSource={data}
|
dataSource={filteredData}
|
||||||
|
summary={() => (
|
||||||
|
<Table.Summary.Row>
|
||||||
|
<Table.Summary.Cell>
|
||||||
|
<Typography.Title level={4}>
|
||||||
|
{t("general.labels.totals")}
|
||||||
|
</Typography.Title>
|
||||||
|
</Table.Summary.Cell>
|
||||||
|
<Table.Summary.Cell>
|
||||||
|
{summaryData.totalSales.toFormat()}
|
||||||
|
</Table.Summary.Cell>
|
||||||
|
<Table.Summary.Cell>
|
||||||
|
{summaryData.totalCost.toFormat()}
|
||||||
|
</Table.Summary.Cell>
|
||||||
|
<Table.Summary.Cell>
|
||||||
|
{summaryData.gpdollars.toFormat()}
|
||||||
|
</Table.Summary.Cell>
|
||||||
|
<Table.Summary.Cell></Table.Summary.Cell>
|
||||||
|
</Table.Summary.Row>
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -37,13 +37,6 @@ export default function ReportCenterModalComponent({ context }) {
|
|||||||
autoComplete={"off"}
|
autoComplete={"off"}
|
||||||
layout="vertical"
|
layout="vertical"
|
||||||
form={form}
|
form={form}
|
||||||
initialValues={{
|
|
||||||
to: [
|
|
||||||
"allan.carr@thinkimex.com",
|
|
||||||
"allanlcarr@outlook.com",
|
|
||||||
"allanlcarr@icloud.com",
|
|
||||||
],
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="key"
|
name="key"
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ export function ReportCenterModalContainer({
|
|||||||
visible={visible}
|
visible={visible}
|
||||||
title={t("printcenter.labels.reportcentermodal")}
|
title={t("printcenter.labels.reportcentermodal")}
|
||||||
onOk={() => toggleModalVisible()}
|
onOk={() => toggleModalVisible()}
|
||||||
|
onCancel={() => toggleModalVisible()}
|
||||||
cancelButtonProps={{ style: { display: "none" } }}
|
cancelButtonProps={{ style: { display: "none" } }}
|
||||||
destroyOnClose
|
destroyOnClose
|
||||||
>
|
>
|
||||||
|
|||||||
Reference in New Issue
Block a user