diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel
index 4c202bbd8..c41c57d59 100644
--- a/bodyshop_translations.babel
+++ b/bodyshop_translations.babel
@@ -1516,6 +1516,27 @@
+
+ assignedlinehours
+ false
+
+
+
+
+
+ en-US
+ false
+
+
+ es-MX
+ false
+
+
+ fr-CA
+ false
+
+
+
billposted
false
@@ -34038,6 +34059,27 @@
tech
+
+ assignedjobs
+ false
+
+
+
+
+
+ en-US
+ false
+
+
+ es-MX
+ false
+
+
+ fr-CA
+ false
+
+
+
claimtask
false
diff --git a/client/src/components/job-detail-lines/job-lines.component.jsx b/client/src/components/job-detail-lines/job-lines.component.jsx
index e34d6a446..c21886af6 100644
--- a/client/src/components/job-detail-lines/job-lines.component.jsx
+++ b/client/src/components/job-detail-lines/job-lines.component.jsx
@@ -301,7 +301,11 @@ export function JobLinesComponent({
dataIndex: "assigned_team",
key: "assigned_team",
render: (text, record) => (
-
+
),
},
]
@@ -442,9 +446,20 @@ export function JobLinesComponent({
{t("joblines.fields.part_types.PAL")}
{t("joblines.fields.part_types.PAS")}
+ {t("joblines.fields.lbr_types.LAA")}
{t("joblines.fields.lbr_types.LAB")}
- {t("joblines.fields.lbr_types.LAR")}
+ {t("joblines.fields.lbr_types.LAD")}
+ {t("joblines.fields.lbr_types.LAE")}
+ {t("joblines.fields.lbr_types.LAF")}
+ {t("joblines.fields.lbr_types.LAG")}
{t("joblines.fields.lbr_types.LAM")}
+ {t("joblines.fields.lbr_types.LAR")}
+ {t("joblines.fields.lbr_types.LAS")}
+ {t("joblines.fields.lbr_types.LAU")}
+ {t("joblines.fields.lbr_types.LA1")}
+ {t("joblines.fields.lbr_types.LA2")}
+ {t("joblines.fields.lbr_types.LA3")}
+ {t("joblines.fields.lbr_types.LA2")}
{t("general.labels.clear")}
diff --git a/client/src/components/job-line-bulk-assign/job-line-bulk-assign.component.jsx b/client/src/components/job-line-bulk-assign/job-line-bulk-assign.component.jsx
index 9b7a3fa8d..5f025abba 100644
--- a/client/src/components/job-line-bulk-assign/job-line-bulk-assign.component.jsx
+++ b/client/src/components/job-line-bulk-assign/job-line-bulk-assign.component.jsx
@@ -11,20 +11,23 @@ import {
selectBodyshop,
selectCurrentUser,
} from "../../redux/user/user.selectors";
+import { insertAuditTrail } from "../../redux/application/application.actions";
+import AuditTrailMapping from "../../utils/AuditTrailMappings";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
jobRO: selectJobReadOnly,
currentUser: selectCurrentUser,
});
const mapDispatchToProps = (dispatch) => ({
- //setUserLanguage: language => dispatch(setUserLanguage(language))
+ insertAuditTrail: ({ jobid, operation }) =>
+ dispatch(insertAuditTrail({ jobid, operation })),
});
export default connect(mapStateToProps, mapDispatchToProps)(JoblineBulkAssign);
export function JoblineBulkAssign({
setSelectedLines,
selectedLines,
-
+ insertAuditTrail,
bodyshop,
jobRO,
job,
@@ -55,8 +58,28 @@ export function JoblineBulkAssign({
error: JSON.stringify(result.errors),
}),
});
+ } else {
+ //Insert the audit trail here.
+
+ const teamName = bodyshop.employee_teams.find(
+ (et) => et.id === values.assigned_team
+ )?.name;
+
+ const hours = selectedLines.reduce(
+ (acc, val) => (acc += val.mod_lb_hrs),
+ 0
+ );
+
+ insertAuditTrail({
+ jobid: job.id,
+ operation: AuditTrailMapping.assignedlinehours(
+ teamName,
+ hours.toFixed(1)
+ ),
+ });
+
+ setVisible(false);
}
- setVisible(false);
} catch (error) {
notification.open({
type: "error",
diff --git a/client/src/components/job-line-team-assignment/job-line-team-assignmnent.component.jsx b/client/src/components/job-line-team-assignment/job-line-team-assignmnent.component.jsx
index 929ec1e5d..a83ec62cb 100644
--- a/client/src/components/job-line-team-assignment/job-line-team-assignmnent.component.jsx
+++ b/client/src/components/job-line-team-assignment/job-line-team-assignmnent.component.jsx
@@ -7,16 +7,25 @@ import { createStructuredSelector } from "reselect";
import { UPDATE_JOB_LINE } from "../../graphql/jobs-lines.queries";
import { selectBodyshop } from "../../redux/user/user.selectors";
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
+import { insertAuditTrail } from "../../redux/application/application.actions";
+import AuditTrailMapping from "../../utils/AuditTrailMappings";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
- //setUserLanguage: language => dispatch(setUserLanguage(language))
+ insertAuditTrail: ({ jobid, operation }) =>
+ dispatch(insertAuditTrail({ jobid, operation })),
});
-export function JoblineTeamAssignment({ bodyshop, jobline, disabled }) {
+export function JoblineTeamAssignment({
+ bodyshop,
+ jobline,
+ disabled,
+ jobId,
+ insertAuditTrail,
+}) {
const [editing, setEditing] = useState(false);
const [loading, setLoading] = useState(false);
const [assignedTeam, setAssignedTeam] = useState(jobline.assigned_team);
@@ -40,16 +49,19 @@ export function JoblineTeamAssignment({ bodyshop, jobline, disabled }) {
},
});
- if (
- assignedTeam === null ||
- assignedTeam === undefined ||
- assignedTeam === ""
- ) {
- alert("TODO - implement calculation to reduce assigned hours if needed.");
- }
-
if (!!!result.errors) {
notification["success"]({ message: t("joblines.successes.saved") });
+ //insert the audit trail here.
+ const teamName = bodyshop.employee_teams.find(
+ (et) => et.id === assignedTeam
+ )?.name;
+ insertAuditTrail({
+ jobid: jobId,
+ operation: AuditTrailMapping.assignedlinehours(
+ teamName,
+ jobline.mod_lb_hrs
+ ),
+ });
} else {
notification["error"]({
message: t("joblines.errors.saving", {
diff --git a/client/src/components/tech-sider/tech-sider.component.jsx b/client/src/components/tech-sider/tech-sider.component.jsx
index 33eae1e0b..aaac65512 100644
--- a/client/src/components/tech-sider/tech-sider.component.jsx
+++ b/client/src/components/tech-sider/tech-sider.component.jsx
@@ -107,6 +107,13 @@ export function TechSider({
>
{t("menus.tech.productionboard")}
+ }
+ >
+ {t("menus.tech.assignedjobs")}
+
({
value: preset.name,
label: preset.name,
- disabled: completedTasks.includes(preset.name),
+ disabled: completedTasks
+ .map((task) => task.name)
+ .includes(preset.name),
}))}
/>
)}
diff --git a/client/src/components/time-ticket-task-modal/time-ticket-task-modal.container.jsx b/client/src/components/time-ticket-task-modal/time-ticket-task-modal.container.jsx
index b7fb53d41..b2a921d02 100644
--- a/client/src/components/time-ticket-task-modal/time-ticket-task-modal.container.jsx
+++ b/client/src/components/time-ticket-task-modal/time-ticket-task-modal.container.jsx
@@ -7,15 +7,21 @@ import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { toggleModalVisible } from "../../redux/modals/modals.actions";
import { selectTimeTicketTasks } from "../../redux/modals/modals.selectors";
-import { selectBodyshop } from "../../redux/user/user.selectors";
+import {
+ selectBodyshop,
+ selectCurrentUser,
+} 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";
+import { selectTechnician } from "../../redux/tech/tech.selectors";
const mapStateToProps = createStructuredSelector({
timeTicketTasksModal: selectTimeTicketTasks,
bodyshop: selectBodyshop,
+ currentUser: selectCurrentUser,
+ technician: selectTechnician,
});
const mapDispatchToProps = (dispatch) => ({
toggleModalVisible: () => dispatch(toggleModalVisible("timeTicketTask")),
@@ -27,6 +33,8 @@ export default connect(
export function TimeTickeTaskModalContainer({
bodyshop,
+ currentUser,
+ technician,
timeTicketTasksModal,
toggleModalVisible,
}) {
@@ -80,6 +88,12 @@ export function TimeTickeTaskModalContainer({
jobid: values.jobid,
task: values.task,
calculateOnly: !handleFinish,
+ employee: technician
+ ? {
+ name: `${technician.first_name} ${technician.last_name}`.trim(),
+ employeeid: technician.id,
+ }
+ : { name: currentUser.displayName, email: currentUser.email },
});
if (response.status === 200 && handleFinish) {
//Close the modal
diff --git a/client/src/graphql/jobs.queries.js b/client/src/graphql/jobs.queries.js
index 2a0529320..b75ad978a 100644
--- a/client/src/graphql/jobs.queries.js
+++ b/client/src/graphql/jobs.queries.js
@@ -2208,3 +2208,28 @@ export const QUERY_COMPLETED_TASKS = gql`
}
}
`;
+
+export const QUERY_JOBS_TECH_ASIGNED_TO_BY_TEAM = gql`
+ query QUERY_JOBS_TECH_ASIGNED_TO_BY_TEAM($teamIds: [uuid!]!) {
+ jobs(
+ where: {
+ inproduction: { _eq: true }
+ joblines: { assigned_team: { _in: $teamIds } }
+ }
+ ) {
+ id
+ v_make_desc
+ v_model_desc
+ v_color
+ v_vin
+ plate_no
+ plate_st
+ clm_no
+ ownr_fn
+ ownr_ln
+ ownr_co_nm
+ status
+ ro_number
+ }
+ }
+`;
diff --git a/client/src/pages/tech-assigned-prod-jobs/tech-assigned-prod-jobs.component.jsx b/client/src/pages/tech-assigned-prod-jobs/tech-assigned-prod-jobs.component.jsx
new file mode 100644
index 000000000..b971bd368
--- /dev/null
+++ b/client/src/pages/tech-assigned-prod-jobs/tech-assigned-prod-jobs.component.jsx
@@ -0,0 +1,261 @@
+import { useQuery } from "@apollo/client";
+import React, { useState } from "react";
+import { Table } from "antd";
+import { connect } from "react-redux";
+import { createStructuredSelector } from "reselect";
+import { QUERY_JOBS_TECH_ASIGNED_TO_BY_TEAM } from "../../graphql/jobs.queries";
+import { selectTechnician } from "../../redux/tech/tech.selectors";
+import { selectBodyshop } from "../../redux/user/user.selectors";
+import { alphaSort } from "../../utils/sorters";
+import { SyncOutlined } from "@ant-design/icons";
+import { Button, Card, Input, Space } from "antd";
+import queryString from "query-string";
+import { useTranslation } from "react-i18next";
+import { useHistory, useLocation } from "react-router-dom";
+import { onlyUnique } from "../../utils/arrayHelper";
+import AlertComponent from "../../components/alert/alert.component";
+import OwnerNameDisplay from "../../components/owner-name-display/owner-name-display.component";
+import { setModalContext } from "../../redux/modals/modals.actions";
+
+const mapStateToProps = createStructuredSelector({
+ //currentUser: selectCurrentUser
+ technician: selectTechnician,
+ bodyshop: selectBodyshop,
+});
+const mapDispatchToProps = (dispatch) => ({
+ setTimeTicketTaskContext: (context) =>
+ dispatch(setModalContext({ context: context, modal: "timeTicketTask" })),
+});
+
+export function TechAssignedProdJobs({
+ setTimeTicketTaskContext,
+ technician,
+ bodyshop,
+}) {
+ const { loading, error, data, refetch } = useQuery(
+ QUERY_JOBS_TECH_ASIGNED_TO_BY_TEAM,
+ {
+ variables: {
+ teamIds: bodyshop.employee_teams
+ .filter((et) =>
+ et.employee_team_members.find(
+ (etm) => etm.employeeid === technician.id
+ )
+ )
+ .map((et) => et.id),
+ },
+ }
+ );
+
+ const searchParams = queryString.parse(useLocation().search);
+ const { selected } = searchParams;
+
+ const [state, setState] = useState({
+ sortedInfo: {},
+ filteredInfo: { text: "" },
+ });
+ const { t } = useTranslation();
+ const history = useHistory();
+ const [searchText, setSearchText] = useState("");
+ if (error) return ;
+
+ const jobs = data
+ ? searchText === ""
+ ? data.jobs
+ : data.jobs.filter(
+ (j) =>
+ (j.ro_number || "")
+ .toString()
+ .toLowerCase()
+ .includes(searchText.toLowerCase()) ||
+ (j.ownr_fn || "")
+ .toLowerCase()
+ .includes(searchText.toLowerCase()) ||
+ (j.ownr_ln || "")
+ .toLowerCase()
+ .includes(searchText.toLowerCase()) ||
+ (j.ownr_co_nm || "")
+ .toLowerCase()
+ .includes(searchText.toLowerCase()) ||
+ (j.clm_no || "").toLowerCase().includes(searchText.toLowerCase()) ||
+ (j.plate_no || "")
+ .toLowerCase()
+ .includes(searchText.toLowerCase()) ||
+ (j.v_model_desc || "")
+ .toLowerCase()
+ .includes(searchText.toLowerCase()) ||
+ (j.v_make_desc || "")
+ .toLowerCase()
+ .includes(searchText.toLowerCase())
+ )
+ : [];
+ const columns = [
+ {
+ title: t("jobs.fields.ro_number"),
+ dataIndex: "ro_number",
+ key: "ro_number",
+ sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
+ sortOrder:
+ state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
+
+ render: (text, record) => record.ro_number || t("general.labels.na"),
+ },
+ {
+ title: t("jobs.fields.owner"),
+ dataIndex: "owner",
+ key: "owner",
+ sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
+ sortOrder:
+ state.sortedInfo.columnKey === "owner" && state.sortedInfo.order,
+ ellipsis: true,
+ render: (text, record) => (
+
+
+
+ ),
+ },
+ {
+ title: t("jobs.fields.status"),
+ dataIndex: "status",
+ key: "status",
+ sorter: (a, b) => alphaSort(a.status, b.status),
+ sortOrder:
+ state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
+ filters:
+ (jobs &&
+ jobs
+ .map((j) => j.status)
+ .filter(onlyUnique)
+ .map((s) => {
+ return {
+ text: s || "No Status*",
+ value: [s],
+ };
+ })) ||
+ [],
+ onFilter: (value, record) => value.includes(record.status),
+ render: (text, record) => {
+ return record.status || t("general.labels.na");
+ },
+ },
+
+ {
+ title: t("jobs.fields.vehicle"),
+ dataIndex: "vehicle",
+ key: "vehicle",
+ ellipsis: true,
+ render: (text, record) => (
+ {`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
+ record.v_model_desc || ""
+ }`}
+ ),
+ },
+ {
+ title: t("vehicles.fields.plate_no"),
+ dataIndex: "plate_no",
+ key: "plate_no",
+ sorter: (a, b) => alphaSort(a.plate_no, b.plate_no),
+ sortOrder:
+ state.sortedInfo.columnKey === "plate_no" && state.sortedInfo.order,
+ render: (text, record) => {
+ return record.plate_no ? record.plate_no : "";
+ },
+ },
+ {
+ title: t("jobs.fields.clm_no"),
+ dataIndex: "clm_no",
+ key: "clm_no",
+ ellipsis: true,
+ sorter: (a, b) => alphaSort(a.clm_no, b.clm_no),
+ sortOrder:
+ state.sortedInfo.columnKey === "clm_no" && state.sortedInfo.order,
+ render: (text, record) => {
+ return record.clm_no ? (
+ {record.clm_no}
+ ) : (
+ t("general.labels.unknown")
+ );
+ },
+ },
+ {
+ title: t("jobs.labels.actions"),
+ dataIndex: "actions",
+ key: "actions",
+ render: (text, record) => (
+
+ ),
+ },
+ ];
+ const handleTableChange = (pagination, filters, sorter) => {
+ setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
+ };
+
+ const handleOnRowClick = (record) => {
+ if (record) {
+ if (record.id) {
+ history.push({
+ search: queryString.stringify({
+ ...searchParams,
+ selected: record.id,
+ }),
+ });
+ }
+ }
+ };
+ return (
+
+
+ {
+ setSearchText(e.target.value);
+ }}
+ value={searchText}
+ enterButton
+ />
+
+ }
+ >
+ {
+ handleOnRowClick(record);
+ },
+ selectedRowKeys: [selected],
+ type: "radio",
+ }}
+ onChange={handleTableChange}
+ // onRow={(record, rowIndex) => {
+ // return {
+ // onClick: (event) => {
+ // handleOnRowClick(record);
+ // },
+ // };
+ // }}
+ />
+
+ );
+}
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(TechAssignedProdJobs);
diff --git a/client/src/pages/tech-lookup/tech-lookup.container.jsx b/client/src/pages/tech-lookup/tech-lookup.container.jsx
index 1297220b9..3368c1325 100644
--- a/client/src/pages/tech-lookup/tech-lookup.container.jsx
+++ b/client/src/pages/tech-lookup/tech-lookup.container.jsx
@@ -1,6 +1,5 @@
import React from "react";
import RbacWrapperComponent from "../../components/rbac-wrapper/rbac-wrapper.component";
-import TechLookupJobsDrawer from "../../components/tech-lookup-jobs-drawer/tech-lookup-jobs-drawer.component";
import TechLookupJobsList from "../../components/tech-lookup-jobs-list/tech-lookup-jobs-list.component";
export default function TechLookupContainer() {
@@ -8,7 +7,6 @@ export default function TechLookupContainer() {
-
);
diff --git a/client/src/pages/tech/tech.page.component.jsx b/client/src/pages/tech/tech.page.component.jsx
index 25b33dc09..078dfca13 100644
--- a/client/src/pages/tech/tech.page.component.jsx
+++ b/client/src/pages/tech/tech.page.component.jsx
@@ -12,6 +12,8 @@ import TechSider from "../../components/tech-sider/tech-sider.component";
import { selectTechnician } from "../../redux/tech/tech.selectors";
import FeatureWrapper from "../../components/feature-wrapper/feature-wrapper.component";
import "./tech.page.styles.scss";
+import TechLookupJobsDrawer from "../../components/tech-lookup-jobs-drawer/tech-lookup-jobs-drawer.component";
+
import UpdateAlert from "../../components/update-alert/update-alert.component";
const TimeTicketModalContainer = lazy(() =>
import("../../components/time-ticket-modal/time-ticket-modal.container")
@@ -40,6 +42,9 @@ const TimeTicketModalTask = lazy(() =>
"../../components/time-ticket-task-modal/time-ticket-task-modal.container"
)
);
+const TechAssignedProdJobs = lazy(() =>
+ import("../tech-assigned-prod-jobs/tech-assigned-prod-jobs.component")
+);
const { Content } = Layout;
const mapStateToProps = createStructuredSelector({
@@ -63,7 +68,7 @@ export function TechPage({ technician, match }) {
{technician ? null : }
-
+
+
diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json
index 586f2d9fc..c42cecf0b 100644
--- a/client/src/translations/en_us/common.json
+++ b/client/src/translations/en_us/common.json
@@ -103,6 +103,7 @@
"admin_jobmarkforreexport": "ADMIN: Job marked for re-export.",
"admin_jobuninvoice": "ADMIN: Job has been uninvoiced.",
"admin_jobunvoid": "ADMIN: Job has been unvoided.",
+ "assignedlinehours": "Assigned job lines totaling {{hours}} units to {{team}}.",
"billposted": "Bill with invoice number {{invoice_number}} posted.",
"billupdated": "Bill with invoice number {{invoice_number}} updated.",
"failedpayment": "Failed payment attempt.",
@@ -346,7 +347,7 @@
"md_payment_types": "Payment Types",
"md_referral_sources": "Referral Sources",
"md_tasks_presets": {
- "enable_tasks": "Enable Task Claiming",
+ "enable_tasks": "Enable Hour Flagging",
"hourstype": "Hour Types",
"memo": "Time Ticket Memo",
"name": "Preset Name",
@@ -1746,7 +1747,7 @@
"federal_tax_amt": "Federal Taxes",
"gpdollars": "$ G.P.",
"gppercent": "% G.P.",
- "hrs_claimed": "Hours Claimed",
+ "hrs_claimed": "Hours Flagged",
"hrs_total": "Hours Total",
"importnote": "The job was initially imported.",
"inproduction": "In Production",
@@ -1997,7 +1998,8 @@
"shops": "My Shops"
},
"tech": {
- "claimtask": "Claim Task",
+ "assignedjobs": "Assigned Jobs",
+ "claimtask": "Flag Hours",
"home": "Home",
"jobclockin": "Job Clock In",
"jobclockout": "Job Clock Out",
@@ -2647,7 +2649,7 @@
"timetickets": "Time Tickets",
"timetickets_employee": "Employee Time Tickets",
"timetickets_summary": "Time Tickets Summary",
- "unclaimed_hrs": "Unclaimed Hours",
+ "unclaimed_hrs": "Unflagged Hours",
"void_ros": "Void ROs",
"work_in_progress_labour": "Work in Progress - Labor",
"work_in_progress_payables": "Work in Progress - Payables"
@@ -2727,7 +2729,7 @@
},
"timetickets": {
"actions": {
- "claimtasks": "Claim Tasks",
+ "claimtasks": "Flag Hours",
"clockin": "Clock In",
"clockout": "Clock Out",
"commit": "Commit Tickets ({{count}})",
@@ -2768,7 +2770,7 @@
"alreadyclockedon": "You are already clocked in to the following job(s):",
"ambreak": "AM Break",
"amshift": "AM Shift",
- "claimtaskpreview": "Claimed Tasks Preview",
+ "claimtaskpreview": "Flagged Hours Preview",
"clockhours": "Shift Clock Hours Summary",
"clockintojob": "Clock In to Job",
"deleteconfirm": "Are you sure you want to delete this time ticket? This cannot be undone.",
diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json
index 2869f12ec..511517aeb 100644
--- a/client/src/translations/es/common.json
+++ b/client/src/translations/es/common.json
@@ -103,6 +103,7 @@
"admin_jobmarkforreexport": "",
"admin_jobuninvoice": "",
"admin_jobunvoid": "",
+ "assignedlinehours": "",
"billposted": "",
"billupdated": "",
"failedpayment": "",
@@ -1997,6 +1998,7 @@
"shops": "Mis tiendas"
},
"tech": {
+ "assignedjobs": "",
"claimtask": "",
"home": "",
"jobclockin": "",
diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json
index 1a2c14ac4..d134b4a6f 100644
--- a/client/src/translations/fr/common.json
+++ b/client/src/translations/fr/common.json
@@ -103,6 +103,7 @@
"admin_jobmarkforreexport": "",
"admin_jobuninvoice": "",
"admin_jobunvoid": "",
+ "assignedlinehours": "",
"billposted": "",
"billupdated": "",
"failedpayment": "",
@@ -1997,6 +1998,7 @@
"shops": "Mes boutiques"
},
"tech": {
+ "assignedjobs": "",
"claimtask": "",
"home": "",
"jobclockin": "",
diff --git a/client/src/utils/AuditTrailMappings.js b/client/src/utils/AuditTrailMappings.js
index 47fdc4535..e96c3f664 100644
--- a/client/src/utils/AuditTrailMappings.js
+++ b/client/src/utils/AuditTrailMappings.js
@@ -42,6 +42,8 @@ const AuditTrailMapping = {
admin_jobmarkexported: () =>
i18n.t("audit_trail.messages.admin_jobmarkexported"),
failedpayment: () => i18n.t("audit_trail.messages.failedpayment"),
+ assignedlinehours: (team, hours) =>
+ i18n.t("audit_trail.messages.assignedlinehours", { team, hours }),
};
export default AuditTrailMapping;
diff --git a/server/payroll/claim-task.js b/server/payroll/claim-task.js
index b88c52c34..e412c374d 100644
--- a/server/payroll/claim-task.js
+++ b/server/payroll/claim-task.js
@@ -6,14 +6,14 @@ const {
CalculateExpectedHoursForJob,
CalculateTicketsHoursForJob,
} = require("./pay-all");
-
+const moment = require("moment");
// Dinero.defaultCurrency = "USD";
// Dinero.globalLocale = "en-CA";
Dinero.globalRoundingMode = "HALF_EVEN";
exports.claimtask = async function (req, res) {
const BearerToken = req.headers.authorization;
- const { jobid, task, calculateOnly } = req.body;
+ const { jobid, task, calculateOnly, employee } = req.body;
logger.log("job-payroll-pay-all", "DEBUG", req.user.email, jobid, null);
const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {
headers: {
@@ -70,7 +70,7 @@ exports.claimtask = async function (req, res) {
job.bodyshop.md_responsibility_centers.defaults.costs[
laborTypeKey
],
- memo: `*Claimed Task* ${theTaskPreset.memo}`,
+ memo: `*Flagged Task* ${theTaskPreset.memo}`,
});
}
);
@@ -86,7 +86,16 @@ exports.claimtask = async function (req, res) {
const updateResult = await client.request(queries.UPDATE_JOB, {
jobId: job.id,
job: {
- completed_tasks: [...job.completed_tasks, task],
+ status: theTaskPreset.nextstatus,
+ completed_tasks: [
+ ...job.completed_tasks,
+ {
+ name: task,
+ completedat: moment(),
+ completed_by: employee,
+ useremail: req.user.email,
+ },
+ ],
},
});
}
diff --git a/server/payroll/pay-all.js b/server/payroll/pay-all.js
index 99f9f9b98..81f8ff9d5 100644
--- a/server/payroll/pay-all.js
+++ b/server/payroll/pay-all.js
@@ -46,7 +46,9 @@ exports.payall = async function (req, res) {
//Every iteration is what we would need to insert into the time ticket hash
//so that it would match the employee hash exactly.
const path = diffParser(diff);
+
if (diff.op === "add") {
+ console.log(Object.keys(diff.val));
if (typeof diff.val === "object" && Object.keys(diff.val).length > 1) {
//Multiple values to add.
Object.keys(diff.val).forEach((key) => {
@@ -63,7 +65,7 @@ exports.payall = async function (req, res) {
cost_center:
job.bodyshop.md_responsibility_centers.defaults.costs[key],
flat_rate: true,
- memo: `*SYS-PAY* Add unclaimed hours. (${req.user.email})`,
+ memo: `*SYS-PAY* Add unflagged hours. (${req.user.email})`,
});
});
} else {
@@ -81,7 +83,7 @@ exports.payall = async function (req, res) {
job.bodyshop.md_responsibility_centers.defaults.costs[
path.mod_lbr_ty
],
- memo: `*SYS-PAY* Add unclaimed hours. (${req.user.email})`,
+ memo: `*SYS-PAY* Add unflagged hours. (${req.user.email})`,
});
}
} else if (diff.op === "update") {
@@ -100,7 +102,7 @@ exports.payall = async function (req, res) {
job.bodyshop.md_responsibility_centers.defaults.costs[
path.mod_lbr_ty
],
- memo: `*SYS-PAY* Adjust claimed hours per assignment. (${req.user.email})`,
+ memo: `*SYS-PAY* Adjust flagged hours per assignment. (${req.user.email})`,
});
} else {
//Has to be a delete
@@ -122,7 +124,7 @@ exports.payall = async function (req, res) {
cost_center:
job.bodyshop.md_responsibility_centers.defaults.costs[key],
flat_rate: true,
- memo: `*SYS-PAY* Remove claimed hours per assignment. (${req.user.email})`,
+ memo: `*SYS-PAY* Remove flagged hours per assignment. (${req.user.email})`,
});
});
} else {
@@ -140,7 +142,7 @@ exports.payall = async function (req, res) {
path.mod_lbr_ty
],
flat_rate: true,
- memo: `*SYS-PAY* Remove claimed hours per assignment. (${req.user.email})`,
+ memo: `*SYS-PAY* Remove flagged hours per assignment. (${req.user.email})`,
});
}
}
@@ -203,7 +205,14 @@ function diffParser(diff) {
) {
hours = diff.val;
} else if (diff.val !== null && diff.val !== undefined) {
- hours = diff.val[Object.keys(diff.val)[0]];
+ if (diff.path.length === 1) {
+ hours =
+ diff.val[Object.keys(diff.val)[0]][
+ Object.keys(diff.val[Object.keys(diff.val)[0]])
+ ];
+ } else {
+ hours = diff.val[Object.keys(diff.val)[0]];
+ }
} else if (
typeof diff.oldVal === "number" &&
diff.oldVal !== null &&