Added allocation adding + basic pull
This commit is contained in:
@@ -18,6 +18,63 @@
|
||||
<folder_node>
|
||||
<name>translation</name>
|
||||
<children>
|
||||
<folder_node>
|
||||
<name>allocations</name>
|
||||
<children>
|
||||
<folder_node>
|
||||
<name>actions</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>assign</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>fields</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>employee</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>appointments</name>
|
||||
<children>
|
||||
@@ -1456,6 +1513,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>mod_lb_hrs</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>oem_partno</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
import { Select, Button, Popover, InputNumber } from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
null
|
||||
)(function AllocationsAssignmentComponent({
|
||||
bodyshop,
|
||||
handleAssignment,
|
||||
assignment,
|
||||
setAssignment,
|
||||
visibilityState,
|
||||
maxHours
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const onChange = e => {
|
||||
console.log("e", e);
|
||||
setAssignment({ ...assignment, employeeid: e });
|
||||
};
|
||||
|
||||
const [visibility, setVisibility] = visibilityState;
|
||||
|
||||
const popContent = (
|
||||
<div>
|
||||
<Select
|
||||
showSearch
|
||||
style={{ width: 200 }}
|
||||
placeholder="Select a person"
|
||||
optionFilterProp="children"
|
||||
onChange={onChange}
|
||||
filterOption={(input, option) =>
|
||||
option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}
|
||||
>
|
||||
{bodyshop.employees.map(emp => (
|
||||
<Select.Option value={emp.id} key={emp.id}>
|
||||
{`${emp.first_name} ${emp.last_name}`}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
<InputNumber
|
||||
defaultValue={assignment.hours}
|
||||
placeholder={t("joblines.fields.mod_lb_hrs")}
|
||||
max={parseFloat(maxHours)}
|
||||
min={0}
|
||||
onChange={e => setAssignment({ ...assignment, hours: e })}
|
||||
/>
|
||||
|
||||
<Button
|
||||
type="primary"
|
||||
disabled={!assignment.employeeid}
|
||||
onClick={handleAssignment}
|
||||
>
|
||||
Assign
|
||||
</Button>
|
||||
<Button onClick={() => setVisibility(false)}>Close</Button>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<Popover content={popContent} visible={visibility}>
|
||||
<Button onClick={() => setVisibility(true)}>
|
||||
{t("allocations.actions.assign")}
|
||||
</Button>
|
||||
</Popover>
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,38 @@
|
||||
import React, { useState } from "react";
|
||||
import AllocationsAssignmentComponent from "./allocations-assignment.component";
|
||||
import { useMutation } from "react-apollo";
|
||||
import { INSERT_ALLOCATION } from "../../graphql/allocations.queries";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { notification } from "antd";
|
||||
|
||||
export default function AllocationsAssignmentContainer({ jobLineId, hours }) {
|
||||
const visibilityState = useState(false);
|
||||
const { t } = useTranslation();
|
||||
const [assignment, setAssignment] = useState({
|
||||
joblineid: jobLineId,
|
||||
hours: parseFloat(hours),
|
||||
employeeid: null
|
||||
});
|
||||
const [insertAllocation] = useMutation(INSERT_ALLOCATION);
|
||||
|
||||
const handleAssignment = () => {
|
||||
insertAllocation({ variables: { alloc: { ...assignment } } }).then(r => {
|
||||
notification["success"]({
|
||||
message: t("employees.successes.save")
|
||||
});
|
||||
//TODO: Better way to reset the field decorators?
|
||||
visibilityState[1](false);
|
||||
//refetch().then(r => form.resetFields());
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<AllocationsAssignmentComponent
|
||||
handleAssignment={handleAssignment}
|
||||
maxHours={hours}
|
||||
assignment={assignment}
|
||||
setAssignment={setAssignment}
|
||||
visibilityState={visibilityState}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import { useTranslation } from "react-i18next";
|
||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
//import EditableCell from "./job-lines-cell.component";
|
||||
import AllocationsAssignmentContainer from "../allocations-assignment/allocations-assignment.container";
|
||||
|
||||
export default function JobLinesComponent({
|
||||
jobLines,
|
||||
@@ -97,6 +98,38 @@ export default function JobLinesComponent({
|
||||
render: (text, record) => (
|
||||
<CurrencyFormatter>{record.act_price}</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
|
||||
},
|
||||
{
|
||||
title: t("allocations.fields.employee"),
|
||||
dataIndex: "employee",
|
||||
key: "employee",
|
||||
sorter: (a, b) => a.act_price - b.act_price, //TODO Fix employee sorting.
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "employee" && state.sortedInfo.order,
|
||||
render: (text, record) => (
|
||||
<span>
|
||||
{record.allocations && record.allocations.length > 0
|
||||
? record.allocations.map(item => (
|
||||
<div
|
||||
key={item.id}
|
||||
>{`${item.employee.first_name} ${item.employee.last_name} (${item.hours})`}</div>
|
||||
))
|
||||
: null}
|
||||
<AllocationsAssignmentContainer
|
||||
key={record.id}
|
||||
jobLineId={record.id}
|
||||
hours={record.mod_lb_hrs}
|
||||
/>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
11
client/src/graphql/allocations.queries.js
Normal file
11
client/src/graphql/allocations.queries.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import { gql } from "apollo-boost";
|
||||
|
||||
export const INSERT_ALLOCATION = gql`
|
||||
mutation INSERT_ALLOCATION($alloc: [allocations_insert_input!]!) {
|
||||
insert_allocations(objects: $alloc) {
|
||||
returning {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -20,6 +20,13 @@ export const QUERY_BODYSHOP = gql`
|
||||
updated_at
|
||||
zip_post
|
||||
region_config
|
||||
employees {
|
||||
id
|
||||
first_name
|
||||
last_name
|
||||
employee_number
|
||||
cost_center
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -18,6 +18,15 @@ export const GET_JOB_LINES_BY_PK = gql`
|
||||
lbr_op
|
||||
lbr_amt
|
||||
op_code_desc
|
||||
allocations {
|
||||
id
|
||||
hours
|
||||
employee {
|
||||
id
|
||||
first_name
|
||||
last_name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
{
|
||||
"translation": {
|
||||
"allocations": {
|
||||
"actions": {
|
||||
"assign": "Assign"
|
||||
},
|
||||
"fields": {
|
||||
"employee": "Allocated To"
|
||||
}
|
||||
},
|
||||
"appointments": {
|
||||
"actions": {
|
||||
"cancel": "Cancel",
|
||||
@@ -116,6 +124,7 @@
|
||||
"act_price": "Actual Price",
|
||||
"db_price": "Database Price",
|
||||
"line_desc": "Line Description",
|
||||
"mod_lb_hrs": "Labor Hours",
|
||||
"oem_partno": "OEM Part #",
|
||||
"part_type": "Part Type",
|
||||
"unq_seq": "Seq #"
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
{
|
||||
"translation": {
|
||||
"allocations": {
|
||||
"actions": {
|
||||
"assign": "Asignar"
|
||||
},
|
||||
"fields": {
|
||||
"employee": "Asignado a"
|
||||
}
|
||||
},
|
||||
"appointments": {
|
||||
"actions": {
|
||||
"cancel": "Cancelar",
|
||||
@@ -116,6 +124,7 @@
|
||||
"act_price": "Precio actual",
|
||||
"db_price": "Precio de base de datos",
|
||||
"line_desc": "Descripción de línea",
|
||||
"mod_lb_hrs": "Horas laborales",
|
||||
"oem_partno": "OEM parte #",
|
||||
"part_type": "Tipo de parte",
|
||||
"unq_seq": "Seq #"
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
{
|
||||
"translation": {
|
||||
"allocations": {
|
||||
"actions": {
|
||||
"assign": "Attribuer"
|
||||
},
|
||||
"fields": {
|
||||
"employee": "Alloué à"
|
||||
}
|
||||
},
|
||||
"appointments": {
|
||||
"actions": {
|
||||
"cancel": "annuler",
|
||||
@@ -116,6 +124,7 @@
|
||||
"act_price": "Prix actuel",
|
||||
"db_price": "Prix de la base de données",
|
||||
"line_desc": "Description de la ligne",
|
||||
"mod_lb_hrs": "Heures de travail",
|
||||
"oem_partno": "Pièce OEM #",
|
||||
"part_type": "Type de pièce",
|
||||
"unq_seq": "Seq #"
|
||||
|
||||
Reference in New Issue
Block a user