237 lines
7.8 KiB
JavaScript
237 lines
7.8 KiB
JavaScript
import { useQuery } from "@apollo/client";
|
|
import { Button, Form, InputNumber, Modal, Radio, Select, Space, Table, Typography } from "antd";
|
|
import Dinero from "dinero.js";
|
|
import React, { useState } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import { connect } from "react-redux";
|
|
import { createStructuredSelector } from "reselect";
|
|
import { GET_JOB_INFO_DRAW_CALCULATIONS } from "../../graphql/jobs-lines.queries";
|
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
|
import JobSearchSelectComponent from "../job-search-select/job-search-select.component";
|
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
|
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
|
|
|
|
const mapStateToProps = createStructuredSelector({
|
|
bodyshop: selectBodyshop
|
|
});
|
|
const mapDispatchToProps = (dispatch) => ({});
|
|
export default connect(mapStateToProps, mapDispatchToProps)(TimeTicketListTeamPay);
|
|
|
|
export function TimeTicketListTeamPay({ bodyshop, context, actions }) {
|
|
//const { refetch } = actions;
|
|
const { jobId } = context;
|
|
const [visible, setVisible] = useState(false);
|
|
const [form] = Form.useForm();
|
|
const { t } = useTranslation();
|
|
const {
|
|
//loading,
|
|
data: lineTicketData
|
|
} = useQuery(GET_JOB_INFO_DRAW_CALCULATIONS, {
|
|
variables: { id: jobId },
|
|
skip: !jobId,
|
|
fetchPolicy: "network-only",
|
|
nextFetchPolicy: "network-only"
|
|
});
|
|
|
|
const handleOk = () => {
|
|
setVisible(false);
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<Modal width={"80%"} open={visible} destroyOnClose onOk={handleOk} onCancel={() => setVisible(false)}>
|
|
<Form layout="vertical" form={form} initialValues={{ jobid: jobId }}>
|
|
<LayoutFormRow grow noDivider>
|
|
<Form.Item shouldUpdate>
|
|
{() => (
|
|
<Form.Item
|
|
name="jobid"
|
|
label={t("timetickets.fields.ro_number")}
|
|
rules={[
|
|
{
|
|
required: !(form.getFieldValue("cost_center") === "timetickets.labels.shift")
|
|
//message: t("general.validation.required"),
|
|
}
|
|
]}
|
|
>
|
|
<JobSearchSelectComponent
|
|
convertedOnly={!bodyshop.tt_allow_post_to_invoiced}
|
|
notExported={!bodyshop.tt_allow_post_to_invoiced}
|
|
/>
|
|
</Form.Item>
|
|
)}
|
|
</Form.Item>
|
|
<Form.Item
|
|
label={t("timetickets.fields.date")}
|
|
name="date"
|
|
rules={[
|
|
{
|
|
required: true
|
|
//message: t("general.validation.required"),
|
|
}
|
|
]}
|
|
>
|
|
<DateTimePicker isDateOnly />
|
|
</Form.Item>
|
|
</LayoutFormRow>
|
|
|
|
<LayoutFormRow grow noDivider>
|
|
<Form.Item name="team" label="Team">
|
|
<Select
|
|
options={Teams.map((team) => ({
|
|
value: team.name,
|
|
label: team.name
|
|
}))}
|
|
/>
|
|
</Form.Item>
|
|
|
|
<Form.Item name="hourstype">
|
|
<Radio.Group>
|
|
<Radio value="LAB">Body</Radio>
|
|
<Radio value="LAR">Refinish</Radio>
|
|
<Radio value="LAM">Mechanical</Radio>
|
|
<Radio value="LAF">Frame</Radio>
|
|
<Radio value="LAG">Glass</Radio>
|
|
</Radio.Group>
|
|
</Form.Item>
|
|
|
|
<Form.Item name="percent">
|
|
<InputNumber min={0} max={100} precision={1} addonAfter="%" />
|
|
</Form.Item>
|
|
</LayoutFormRow>
|
|
|
|
<Form.Item shouldUpdate noStyle>
|
|
{({ getFieldsValue }) => {
|
|
const formData = getFieldsValue();
|
|
|
|
let data = [];
|
|
let eligibleHours = 0;
|
|
const theTeam = Teams.find((team) => team.name === formData.team);
|
|
if (theTeam) {
|
|
eligibleHours =
|
|
lineTicketData.joblines.reduce(
|
|
(acc, val) => acc + (formData.hourstype === val.mod_lbr_ty ? val.mod_lb_hrs : 0),
|
|
0
|
|
) * (formData.percent / 100 || 0);
|
|
|
|
data = theTeam.employees.map((e) => {
|
|
return {
|
|
employeeid: e.employeeid,
|
|
percentage: e.percentage,
|
|
rate: e.rates[formData.hourstype],
|
|
cost_center: bodyshop.md_responsibility_centers.defaults.costs[formData.hourstype],
|
|
productivehrs: Math.round(eligibleHours * 100 * (e.percentage / 100)) / 100,
|
|
pay: Dinero({
|
|
amount: Math.round((e.rates[formData.hourstype] || 0) * 100)
|
|
})
|
|
.multiply(Math.round(eligibleHours * 100 * (e.percentage / 100)) / 100)
|
|
.toFormat("$0.00")
|
|
};
|
|
});
|
|
}
|
|
|
|
return (
|
|
<Table
|
|
dataSource={data}
|
|
rowKey={"employeeid"}
|
|
title={() => (
|
|
<Space>
|
|
<Typography.Title level={4}>Tickets to be Created</Typography.Title>
|
|
<span>{`(${eligibleHours} hours to split)`}</span>
|
|
</Space>
|
|
)}
|
|
columns={[
|
|
{
|
|
title: t("timetickets.fields.employee"),
|
|
dataIndex: "employee",
|
|
key: "employee",
|
|
render: (text, record) => {
|
|
const emp = bodyshop.employees.find((e) => e.id === record.employeeid);
|
|
return `${emp?.first_name} ${emp?.last_name}`;
|
|
}
|
|
},
|
|
{
|
|
title: t("timetickets.fields.cost_center"),
|
|
dataIndex: "cost_center",
|
|
key: "cost_center",
|
|
|
|
render: (text, record) =>
|
|
record.cost_center === "timetickets.labels.shift" ? t(record.cost_center) : record.cost_center
|
|
},
|
|
{
|
|
title: t("timetickets.fields.productivehrs"),
|
|
dataIndex: "productivehrs",
|
|
key: "productivehrs"
|
|
},
|
|
{
|
|
title: "Percentage",
|
|
dataIndex: "percentage",
|
|
key: "percentage"
|
|
},
|
|
{
|
|
title: "Rate",
|
|
dataIndex: "rate",
|
|
key: "rate"
|
|
},
|
|
{
|
|
title: "Pay",
|
|
dataIndex: "pay",
|
|
key: "pay"
|
|
}
|
|
]}
|
|
/>
|
|
);
|
|
}}
|
|
</Form.Item>
|
|
</Form>
|
|
</Modal>
|
|
<Button onClick={() => setVisible(true)}>Assign Team Pay </Button>
|
|
</>
|
|
);
|
|
}
|
|
|
|
const Teams = [
|
|
{
|
|
name: "Team A",
|
|
employees: [
|
|
{
|
|
employeeid: "9f1bdc23-8dc2-4b6a-8ca1-5f83a6fdcc22",
|
|
percentage: 50,
|
|
rates: {
|
|
LAB: 10,
|
|
LAR: 15
|
|
}
|
|
},
|
|
{
|
|
employeeid: "201db66c-96c7-41ec-bed4-76842ba93087",
|
|
percentage: 50,
|
|
rates: {
|
|
LAB: 20,
|
|
LAR: 25
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: "Team B",
|
|
employees: [
|
|
{
|
|
employeeid: "9f1bdc23-8dc2-4b6a-8ca1-5f83a6fdcc22",
|
|
percentage: 75,
|
|
rates: {
|
|
LAB: 100,
|
|
LAR: 150
|
|
}
|
|
},
|
|
{
|
|
employeeid: "201db66c-96c7-41ec-bed4-76842ba93087",
|
|
percentage: 25,
|
|
rates: {
|
|
LAB: 200,
|
|
LAR: 250
|
|
}
|
|
}
|
|
]
|
|
}
|
|
];
|