Updated UI and added tech elements.
This commit is contained in:
@@ -33996,6 +33996,27 @@
|
||||
<folder_node>
|
||||
<name>tech</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>claimtask</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>home</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -46950,6 +46971,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>unassigned</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>zeroactualnegativeprod</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -47149,6 +47191,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>unassignedlines</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>
|
||||
|
||||
@@ -30,10 +30,6 @@ export function JoblineBulkAssign({
|
||||
job,
|
||||
currentUser,
|
||||
}) {
|
||||
console.log(
|
||||
"🚀 ~ file: job-line-bulk-assign.component.jsx:36 ~ selectedLines:",
|
||||
selectedLines
|
||||
);
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [form] = Form.useForm();
|
||||
|
||||
@@ -61,7 +61,11 @@ export function PayrollLaborAllocationsTable({
|
||||
key: "employeeid",
|
||||
render: (text, record) => {
|
||||
if (record.employeeid === undefined) {
|
||||
return "Unassigned";
|
||||
return (
|
||||
<span style={{ color: "tomato", fontWeight: "bolder" }}>
|
||||
{t("timetickets.labels.unassigned")}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
const emp = bodyshop.employees.find((e) => e.id === record.employeeid);
|
||||
return `${emp?.first_name} ${emp?.last_name}`;
|
||||
@@ -71,12 +75,20 @@ export function PayrollLaborAllocationsTable({
|
||||
title: t("joblines.fields.mod_lbr_ty"),
|
||||
dataIndex: "mod_lbr_ty",
|
||||
key: "mod_lbr_ty",
|
||||
render: (text, record) =>
|
||||
record.employeeid === undefined ? (
|
||||
<span style={{ color: "tomato", fontWeight: "bolder" }}>
|
||||
{t("timetickets.labels.unassigned")}
|
||||
</span>
|
||||
) : (
|
||||
t(`joblines.fields.lbr_types.${record.mod_lbr_ty?.toUpperCase()}`)
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("timetickets.fields.rate"),
|
||||
dataIndex: "rate",
|
||||
key: "rate",
|
||||
},
|
||||
// {
|
||||
// title: t("timetickets.fields.rate"),
|
||||
// dataIndex: "rate",
|
||||
// key: "rate",
|
||||
// },
|
||||
{
|
||||
title: t("jobs.labels.hrs_total"),
|
||||
dataIndex: "expectedHours",
|
||||
@@ -251,7 +263,6 @@ export function PayrollLaborAllocationsTable({
|
||||
</Typography.Title>
|
||||
</Table.Summary.Cell>
|
||||
<Table.Summary.Cell></Table.Summary.Cell>
|
||||
<Table.Summary.Cell></Table.Summary.Cell>
|
||||
<Table.Summary.Cell>
|
||||
{summary.hrs_total.toFixed(5)}
|
||||
</Table.Summary.Cell>
|
||||
|
||||
@@ -24,6 +24,8 @@ import ProductionListColumnNote from "./production-list-columns.productionnote.c
|
||||
import ProductionListColumnCategory from "./production-list-columns.status.category";
|
||||
import ProductionListColumnStatus from "./production-list-columns.status.component";
|
||||
import ProductionlistColumnTouchTime from "./prodution-list-columns.touchtime.component";
|
||||
import { store } from "../../redux/store";
|
||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||
|
||||
const r = ({ technician, state, activeStatuses, bodyshop }) => {
|
||||
return [
|
||||
@@ -38,6 +40,29 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => {
|
||||
</Link>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: i18n.t("timetickets.actions.claimtasks"),
|
||||
dataIndex: "claimtasks",
|
||||
key: "claimtasks",
|
||||
ellipsis: true,
|
||||
render: (text, record) => (
|
||||
<div
|
||||
onClick={() => {
|
||||
store.dispatch(
|
||||
setModalContext({
|
||||
context: {
|
||||
actions: {},
|
||||
context: { jobid: record.id },
|
||||
},
|
||||
modal: "timeTicketTask",
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
{i18n.t("timetickets.actions.claimtasks")}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: i18n.t("jobs.fields.ro_number"),
|
||||
dataIndex: "ro_number",
|
||||
|
||||
@@ -11,22 +11,38 @@ import { createStructuredSelector } from "reselect";
|
||||
import { techLogout } from "../../redux/tech/tech.actions";
|
||||
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||
import { BsKanban } from "react-icons/bs";
|
||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||
|
||||
const { Sider } = Layout;
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
technician: selectTechnician,
|
||||
bodyshop: selectBodyshop,
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
techLogout: () => dispatch(techLogout()),
|
||||
setTimeTicketTaskContext: (context) =>
|
||||
dispatch(setModalContext({ context: context, modal: "timeTicketTask" })),
|
||||
});
|
||||
|
||||
export function TechSider({ technician, techLogout }) {
|
||||
export function TechSider({
|
||||
technician,
|
||||
techLogout,
|
||||
bodyshop,
|
||||
setTimeTicketTaskContext,
|
||||
}) {
|
||||
const [collapsed, setCollapsed] = useState(true);
|
||||
const { t } = useTranslation();
|
||||
const onCollapse = (collapsed) => {
|
||||
setCollapsed(collapsed);
|
||||
};
|
||||
const { Enhanced_Payroll } = useTreatments(
|
||||
["Enhanced_Payroll"],
|
||||
{},
|
||||
bodyshop.imexshopid
|
||||
);
|
||||
|
||||
return (
|
||||
<Sider
|
||||
@@ -51,13 +67,29 @@ export function TechSider({ technician, techLogout }) {
|
||||
<Menu.Item key="2" disabled={!!!technician} icon={<SearchOutlined />}>
|
||||
<Link to={`/tech/joblookup`}>{t("menus.tech.joblookup")}</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
key="3"
|
||||
disabled={!!!technician}
|
||||
icon={<Icon component={FaBusinessTime} />}
|
||||
>
|
||||
<Link to={`/tech/jobclock`}>{t("menus.tech.jobclockin")}</Link>
|
||||
</Menu.Item>
|
||||
{Enhanced_Payroll.treatment === "on" ? (
|
||||
<Menu.Item
|
||||
key="3"
|
||||
disabled={!!!technician}
|
||||
icon={<Icon component={FaBusinessTime} />}
|
||||
onClick={() => {
|
||||
setTimeTicketTaskContext({
|
||||
actions: {},
|
||||
context: { jobid: null },
|
||||
});
|
||||
}}
|
||||
>
|
||||
{t("menus.tech.claimtask")}
|
||||
</Menu.Item>
|
||||
) : (
|
||||
<Menu.Item
|
||||
key="3"
|
||||
disabled={!!!technician}
|
||||
icon={<Icon component={FaBusinessTime} />}
|
||||
>
|
||||
<Link to={`/tech/jobclock`}>{t("menus.tech.jobclockin")}</Link>
|
||||
</Menu.Item>
|
||||
)}
|
||||
<Menu.Item
|
||||
key="4"
|
||||
disabled={!!!technician}
|
||||
|
||||
@@ -34,7 +34,12 @@ export function TimeTicketTaskModalComponent({
|
||||
form,
|
||||
loading,
|
||||
completedTasks,
|
||||
unassignedHours,
|
||||
}) {
|
||||
console.log(
|
||||
"🚀 ~ file: time-ticket-task-modal.component.jsx:39 ~ unassignedHours:",
|
||||
unassignedHours
|
||||
);
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
@@ -80,7 +85,7 @@ export function TimeTicketTaskModalComponent({
|
||||
|
||||
if (!task) return null;
|
||||
return (
|
||||
<table className="bill-inventory-table">
|
||||
<table className="task-tickets-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{t("bodyshop.fields.md_tasks_presets.percent")}</td>
|
||||
@@ -116,7 +121,7 @@ export function TimeTicketTaskModalComponent({
|
||||
<Typography.Title level={4}>
|
||||
{t("timetickets.labels.claimtaskpreview")}
|
||||
</Typography.Title>
|
||||
<table className="bill-cm-returns-table">
|
||||
<table className="task-tickets-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{t("timetickets.fields.employee")}</th>
|
||||
@@ -173,6 +178,14 @@ export function TimeTicketTaskModalComponent({
|
||||
}}
|
||||
</Form.List>
|
||||
)}
|
||||
{unassignedHours > 0 && (
|
||||
<Alert
|
||||
type="error"
|
||||
message={t("timetickets.validation.unassignedlines", {
|
||||
unassignedHours: unassignedHours,
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import TimeTicketTaskModalComponent from "./time-ticket-task-modal.component";
|
||||
import { useApolloClient } from "@apollo/client";
|
||||
import { QUERY_COMPLETED_TASKS } from "../../graphql/jobs.queries";
|
||||
import "./time-ticket-task-modal.styles.scss";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
timeTicketTasksModal: selectTimeTicketTasks,
|
||||
@@ -32,6 +33,7 @@ export function TimeTickeTaskModalContainer({
|
||||
const [form] = Form.useForm();
|
||||
const { context, visible } = timeTicketTasksModal;
|
||||
const [completedTasks, setCompletedTasks] = useState([]);
|
||||
const [unassignedHours, setUnassignedHours] = useState(0);
|
||||
const { t } = useTranslation();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const client = useApolloClient();
|
||||
@@ -83,7 +85,8 @@ export function TimeTickeTaskModalContainer({
|
||||
//Close the modal
|
||||
toggleModalVisible();
|
||||
} else if (handleFinish === false) {
|
||||
form.setFieldsValue({ timetickets: data });
|
||||
form.setFieldsValue({ timetickets: data.ticketsToInsert });
|
||||
setUnassignedHours(data.unassignedHours);
|
||||
} else {
|
||||
notification.open({
|
||||
type: "error",
|
||||
@@ -125,6 +128,7 @@ export function TimeTickeTaskModalContainer({
|
||||
form={form}
|
||||
loading={loading}
|
||||
completedTasks={completedTasks}
|
||||
unassignedHours={unassignedHours}
|
||||
/>
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
.task-tickets-table {
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: 8px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #ddd;
|
||||
|
||||
.ant-form-item {
|
||||
margin-bottom: 0px !important;
|
||||
}
|
||||
}
|
||||
|
||||
tr:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,11 @@ const TechJobClock = lazy(() =>
|
||||
const TechShiftClock = lazy(() =>
|
||||
import("../tech-shift-clock/tech-shift-clock.component")
|
||||
);
|
||||
|
||||
const TimeTicketModalTask = lazy(() =>
|
||||
import(
|
||||
"../../components/time-ticket-task-modal/time-ticket-task-modal.container"
|
||||
)
|
||||
);
|
||||
const { Content } = Layout;
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
@@ -70,6 +74,7 @@ export function TechPage({ technician, match }) {
|
||||
<FeatureWrapper featureName="tech-console">
|
||||
<TimeTicketModalContainer />
|
||||
<PrintCenterModalContainer />
|
||||
<TimeTicketModalTask />
|
||||
<Switch>
|
||||
<Route
|
||||
exact
|
||||
|
||||
@@ -1995,6 +1995,7 @@
|
||||
"shops": "My Shops"
|
||||
},
|
||||
"tech": {
|
||||
"claimtask": "Claim Task",
|
||||
"home": "Home",
|
||||
"jobclockin": "Job Clock In",
|
||||
"jobclockout": "Job Clock Out",
|
||||
@@ -2781,6 +2782,7 @@
|
||||
"straight_time": "Straight Time",
|
||||
"task": "Task",
|
||||
"timetickets": "Time Tickets",
|
||||
"unassigned": "Unassigned",
|
||||
"zeroactualnegativeprod": "Actual hours must be 0 if entering negative productive hours."
|
||||
},
|
||||
"successes": {
|
||||
@@ -2793,7 +2795,8 @@
|
||||
"validation": {
|
||||
"clockoffmustbeafterclockon": "Clock off time must be the same or after clock in time.",
|
||||
"clockoffwithoutclockon": "Clock off time cannot be set without a clock in time.",
|
||||
"hoursenteredmorethanavailable": "The number of hours entered is more than what is available for this cost center."
|
||||
"hoursenteredmorethanavailable": "The number of hours entered is more than what is available for this cost center.",
|
||||
"unassignedlines": "There are currently {{unassignedHours}} hours of repair lines that are unassigned. These hours are not including in the above calculations and must be paid manually."
|
||||
}
|
||||
},
|
||||
"titles": {
|
||||
|
||||
@@ -1995,6 +1995,7 @@
|
||||
"shops": "Mis tiendas"
|
||||
},
|
||||
"tech": {
|
||||
"claimtask": "",
|
||||
"home": "",
|
||||
"jobclockin": "",
|
||||
"jobclockout": "",
|
||||
@@ -2781,6 +2782,7 @@
|
||||
"straight_time": "",
|
||||
"task": "",
|
||||
"timetickets": "",
|
||||
"unassigned": "",
|
||||
"zeroactualnegativeprod": ""
|
||||
},
|
||||
"successes": {
|
||||
@@ -2793,7 +2795,8 @@
|
||||
"validation": {
|
||||
"clockoffmustbeafterclockon": "",
|
||||
"clockoffwithoutclockon": "",
|
||||
"hoursenteredmorethanavailable": ""
|
||||
"hoursenteredmorethanavailable": "",
|
||||
"unassignedlines": ""
|
||||
}
|
||||
},
|
||||
"titles": {
|
||||
|
||||
@@ -1995,6 +1995,7 @@
|
||||
"shops": "Mes boutiques"
|
||||
},
|
||||
"tech": {
|
||||
"claimtask": "",
|
||||
"home": "",
|
||||
"jobclockin": "",
|
||||
"jobclockout": "",
|
||||
@@ -2781,6 +2782,7 @@
|
||||
"straight_time": "",
|
||||
"task": "",
|
||||
"timetickets": "",
|
||||
"unassigned": "",
|
||||
"zeroactualnegativeprod": ""
|
||||
},
|
||||
"successes": {
|
||||
@@ -2793,7 +2795,8 @@
|
||||
"validation": {
|
||||
"clockoffmustbeafterclockon": "",
|
||||
"clockoffwithoutclockon": "",
|
||||
"hoursenteredmorethanavailable": ""
|
||||
"hoursenteredmorethanavailable": "",
|
||||
"unassignedlines": ""
|
||||
}
|
||||
},
|
||||
"titles": {
|
||||
|
||||
@@ -33,7 +33,7 @@ exports.claimtask = async function (req, res) {
|
||||
);
|
||||
|
||||
//Get all of the assignments that are filtered.
|
||||
const { employeeHash } = CalculateExpectedHoursForJob(
|
||||
const { assignmentHash, employeeHash } = CalculateExpectedHoursForJob(
|
||||
job,
|
||||
theTaskPreset.hourstype
|
||||
);
|
||||
@@ -83,7 +83,7 @@ exports.claimtask = async function (req, res) {
|
||||
},
|
||||
});
|
||||
}
|
||||
res.json(ticketsToInsert);
|
||||
res.json({ unassignedHours: assignmentHash.unassigned, ticketsToInsert });
|
||||
} catch (error) {
|
||||
logger.log("job-payroll-claim-task-error", "ERROR", req.user.email, jobid, {
|
||||
jobid: jobid,
|
||||
|
||||
@@ -62,7 +62,7 @@ exports.payall = async function (req, res) {
|
||||
cost_center:
|
||||
job.bodyshop.md_responsibility_centers.defaults.costs[key],
|
||||
flat_rate: true,
|
||||
memo: "*System* Hours added during Pay All function. (multi)",
|
||||
memo: `*SYS-PAY* Add unclaimed hours. (${req.user.email})`,
|
||||
});
|
||||
});
|
||||
} else {
|
||||
@@ -79,7 +79,7 @@ exports.payall = async function (req, res) {
|
||||
job.bodyshop.md_responsibility_centers.defaults.costs[
|
||||
path.mod_lbr_ty
|
||||
],
|
||||
memo: "*System* Hours added during Pay All function.",
|
||||
memo: `*SYS-PAY* Add unclaimed hours. (${req.user.email})`,
|
||||
});
|
||||
}
|
||||
} else if (diff.op === "update") {
|
||||
@@ -97,7 +97,7 @@ exports.payall = async function (req, res) {
|
||||
job.bodyshop.md_responsibility_centers.defaults.costs[
|
||||
path.mod_lbr_ty
|
||||
],
|
||||
memo: "*System* Hours adjustment during Pay All function. (Update)",
|
||||
memo: `*SYS-PAY* Adjust claimed hours per assignment. (${req.user.email})`,
|
||||
});
|
||||
} else {
|
||||
//Has to be a delete
|
||||
@@ -123,7 +123,7 @@ exports.payall = async function (req, res) {
|
||||
cost_center:
|
||||
job.bodyshop.md_responsibility_centers.defaults.costs[key],
|
||||
flat_rate: true,
|
||||
memo: "*System* Hours removed during Pay All function. (Change in rate, unassignment, etc.) *multi*",
|
||||
memo: `*SYS-PAY* Remove claimed hours per assignment. (${req.user.email})`,
|
||||
});
|
||||
});
|
||||
} else {
|
||||
@@ -140,7 +140,7 @@ exports.payall = async function (req, res) {
|
||||
path.mod_lbr_ty
|
||||
],
|
||||
flat_rate: true,
|
||||
memo: "*System* Hours removed during Pay All function. (Change in rate, unassignment, etc.)",
|
||||
memo: `*SYS-PAY* Remove claimed hours per assignment. (${req.user.email})`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user