Added multiple labor rates to employees
IO-548
This commit is contained in:
@@ -35,11 +35,9 @@ const EmployeeSearchSelect = (
|
||||
key={o.id}
|
||||
value={o.id}
|
||||
search={`${o.employee_number} ${o.first_name} ${o.last_name}`}
|
||||
discount={o.discount}
|
||||
>
|
||||
<Space>
|
||||
{`${o.employee_number} ${o.first_name} ${o.last_name}`}
|
||||
<Tag color="blue">{o.cost_center}</Tag>
|
||||
|
||||
<Tag color="green">
|
||||
{o.flat_rate
|
||||
|
||||
@@ -87,7 +87,7 @@ export function JobCostingModalComponent({ bodyshop, job }) {
|
||||
].add(
|
||||
Dinero({
|
||||
amount: Math.round((ticket_val.rate || 0) * 100),
|
||||
}).multiply(ticket_val.actualhrs || 0)
|
||||
}).multiply(ticket_val.actualhrs || ticket_val.productivehrs || 0)
|
||||
);
|
||||
|
||||
return ticket_acc;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Button, Form, Input, Select, Switch } from "antd";
|
||||
import { DeleteFilled } from "@ant-design/icons";
|
||||
import { Button, Form, Input, InputNumber, Select, Switch } from "antd";
|
||||
import moment from "moment";
|
||||
import React, { useEffect } from "react";
|
||||
import { useApolloClient } from "react-apollo";
|
||||
@@ -8,7 +9,8 @@ import { createStructuredSelector } from "reselect";
|
||||
import { QUERY_USERS_BY_EMAIL } from "../../graphql/employees.queries";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import FormDatePicker from "../form-date-picker/form-date-picker.component";
|
||||
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
||||
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
|
||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -131,36 +133,74 @@ export function ShopEmployeesFormComponent({
|
||||
<FormDatePicker />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={t("employees.fields.cost_center")}
|
||||
name="cost_center"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t("general.validation.required"),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Select>
|
||||
{bodyshop.md_responsibility_centers.costs.map((c) => (
|
||||
<Select.Option key={c.name} value={c.name}>
|
||||
{c.name}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("employees.fields.base_rate")}
|
||||
name="base_rate"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t("general.validation.required"),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<CurrencyInput />
|
||||
</Form.Item>
|
||||
<Form.List name={["rates"]}>
|
||||
{(fields, { add, remove, move }) => {
|
||||
return (
|
||||
<div>
|
||||
{fields.map((field, index) => (
|
||||
<Form.Item key={field.key} style={{ padding: 0, margin: 2 }}>
|
||||
<LayoutFormRow grow>
|
||||
<Form.Item
|
||||
label={t("employees.fields.cost_center")}
|
||||
key={`${index}`}
|
||||
name={[field.name, "cost_center"]}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t("general.validation.required"),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Select>
|
||||
{bodyshop.md_responsibility_centers.costs.map((c) => (
|
||||
<Select.Option key={c.name} value={c.name}>
|
||||
{c.name}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("employees.fields.rate")}
|
||||
key={`${index}`}
|
||||
name={[field.name, "rate"]}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t("general.validation.required"),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<InputNumber min={0} precision={2} />
|
||||
</Form.Item>
|
||||
<DeleteFilled
|
||||
onClick={() => {
|
||||
remove(field.name);
|
||||
}}
|
||||
/>
|
||||
<FormListMoveArrows
|
||||
move={move}
|
||||
index={index}
|
||||
total={fields.length}
|
||||
/>
|
||||
</LayoutFormRow>
|
||||
</Form.Item>
|
||||
))}
|
||||
<Form.Item>
|
||||
<Button
|
||||
type="dashed"
|
||||
onClick={() => {
|
||||
add();
|
||||
}}
|
||||
style={{ width: "100%" }}
|
||||
>
|
||||
{t("employees.actions.newrate")}
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</Form.List>
|
||||
|
||||
<Form.Item
|
||||
label={t("employees.fields.user_email")}
|
||||
name="user_email"
|
||||
|
||||
@@ -13,7 +13,6 @@ export default function TimeTicketModalComponent({
|
||||
employeeAutoCompleteOptions,
|
||||
loadLineTicketData,
|
||||
lineTicketData,
|
||||
responsibilityCenters,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -92,21 +91,38 @@ export default function TimeTicketModalComponent({
|
||||
>
|
||||
<InputNumber min={0} precision={1} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="cost_center"
|
||||
label={t("timetickets.fields.cost_center")}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t("general.validation.required"),
|
||||
},
|
||||
]}
|
||||
shouldUpdate={(prev, cur) => prev.employeeid !== cur.employeeid}
|
||||
>
|
||||
<Select>
|
||||
{responsibilityCenters.costs.map((item) => (
|
||||
<Select.Option key={item.name}>{item.name}</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
{() => {
|
||||
const employeeId = form.getFieldValue("employeeid");
|
||||
const emps =
|
||||
employeeAutoCompleteOptions &&
|
||||
employeeAutoCompleteOptions.filter((e) => e.id === employeeId)[0];
|
||||
|
||||
return (
|
||||
<Form.Item
|
||||
name="cost_center"
|
||||
label={t("timetickets.fields.cost_center")}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t("general.validation.required"),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Select>
|
||||
{emps &&
|
||||
emps.rates.map((item) => (
|
||||
<Select.Option key={item.cost_center}>
|
||||
{item.cost_center}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
);
|
||||
}}
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="ciecacode"
|
||||
|
||||
@@ -44,24 +44,42 @@ export function TimeTicketModalContainer({
|
||||
);
|
||||
|
||||
const handleFinish = (values) => {
|
||||
const emps = EmployeeAutoCompleteData.employees.filter(
|
||||
(e) => e.id === values.employeeid
|
||||
);
|
||||
if (timeTicketModal.context.id) {
|
||||
updateTicket({
|
||||
variables: {
|
||||
timeticketId: timeTicketModal.context.id,
|
||||
timeticket: values,
|
||||
timeticket: {
|
||||
...values,
|
||||
rate:
|
||||
emps.length === 1
|
||||
? emps[0].rates.filter(
|
||||
(r) => r.cost_center === values.cost_center
|
||||
)[0].rate
|
||||
: null,
|
||||
},
|
||||
},
|
||||
})
|
||||
.then(handleMutationSuccess)
|
||||
.catch(handleMutationError);
|
||||
} else {
|
||||
//Get selected employee rate.
|
||||
const rate = EmployeeAutoCompleteData.employees.filter(
|
||||
(i) => i.id === values.employeeid
|
||||
)[0].base_rate;
|
||||
|
||||
insertTicket({
|
||||
variables: {
|
||||
timeTicketInput: [{ ...values, rate, bodyshopid: bodyshop.id }],
|
||||
timeTicketInput: [
|
||||
{
|
||||
...values,
|
||||
rate:
|
||||
emps.length === 1
|
||||
? emps[0].rates.filter(
|
||||
(r) => r.cost_center === values.cost_center
|
||||
)[0].rate
|
||||
: null,
|
||||
bodyshopid: bodyshop.id,
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
.then(handleMutationSuccess)
|
||||
@@ -196,7 +214,6 @@ export function TimeTicketModalContainer({
|
||||
employeeAutoCompleteOptions={
|
||||
EmployeeAutoCompleteData && EmployeeAutoCompleteData.employees
|
||||
}
|
||||
responsibilityCenters={bodyshop.md_responsibility_centers || null}
|
||||
loadLineTicketData={loadLineTicketData}
|
||||
lineTicketData={
|
||||
lineTicketData ? lineTicketData : { joblines: [], timetickets: [] }
|
||||
|
||||
Reference in New Issue
Block a user