From 73ba95a240c05f00219fe725cbcdf4cc662d9211 Mon Sep 17 00:00:00 2001 From: Dave Date: Tue, 17 Mar 2026 10:50:22 -0400 Subject: [PATCH] feature/IO-3587-Commision-Cut - rebuild from master-AIO --- .../read-only-form-item.component.jsx | 18 +- .../form-list-move-arrows.component.jsx | 4 +- ...or-allocations-table.payroll.component.jsx | 54 +- .../shop-info.task-presets.component.jsx | 55 +- .../shop-employee-teams.form.component.jsx | 513 +++++++++--------- .../time-ticket-task-modal.component.jsx | 88 ++- .../time-ticket-task-modal.container.jsx | 27 +- .../tt-approvals-list.component.jsx | 18 +- .../tt-approve-button.component.jsx | 18 +- client/src/graphql/bodyshop.queries.js | 4 + client/src/graphql/employee_teams.queries.js | 12 + client/src/graphql/timetickets.queries.js | 4 + client/src/graphql/tt-approvals.queries.js | 19 + client/src/translations/en_us/common.json | 27 +- client/src/translations/es/common.json | 27 +- client/src/translations/fr/common.json | 27 +- server/graphql-client/queries.js | 6 + server/payroll/calculate-totals.js | 66 +-- server/payroll/claim-task.js | 99 +++- server/payroll/pay-all.js | 501 ++++++++++------- server/payroll/payroll.test.js | 465 ++++++++++++++++ 21 files changed, 1473 insertions(+), 579 deletions(-) create mode 100644 server/payroll/payroll.test.js diff --git a/client/src/components/form-items-formatted/read-only-form-item.component.jsx b/client/src/components/form-items-formatted/read-only-form-item.component.jsx index 786d6a1a0..fc4490528 100644 --- a/client/src/components/form-items-formatted/read-only-form-item.component.jsx +++ b/client/src/components/form-items-formatted/read-only-form-item.component.jsx @@ -10,8 +10,13 @@ const mapDispatchToProps = () => ({ //setUserLanguage: language => dispatch(setUserLanguage(language)) }); +const toFiniteNumber = (value) => { + const parsed = Number(value); + return Number.isFinite(parsed) ? parsed : null; +}; + const ReadOnlyFormItem = ({ bodyshop, value, type = "text" }) => { - if (!value) return null; + if (value === null || value === undefined || value === "") return null; switch (type) { case "employee": { const emp = bodyshop.employees.find((e) => e.id === value); @@ -20,8 +25,15 @@ const ReadOnlyFormItem = ({ bodyshop, value, type = "text" }) => { case "text": return
{value}
; - case "currency": - return
{Dinero({ amount: Math.round(value * 100) }).toFormat()}
; + case "currency": { + const numericValue = toFiniteNumber(value); + + if (numericValue === null) { + return null; + } + + return
{Dinero({ amount: Math.round(numericValue * 100) }).toFormat()}
; + } default: return
{value}
; } diff --git a/client/src/components/form-list-move-arrows/form-list-move-arrows.component.jsx b/client/src/components/form-list-move-arrows/form-list-move-arrows.component.jsx index 75047277d..3c2e6a239 100644 --- a/client/src/components/form-list-move-arrows/form-list-move-arrows.component.jsx +++ b/client/src/components/form-list-move-arrows/form-list-move-arrows.component.jsx @@ -1,7 +1,7 @@ import { DownOutlined, UpOutlined } from "@ant-design/icons"; import { Space } from "antd"; -export default function FormListMoveArrows({ move, index, total }) { +export default function FormListMoveArrows({ move, index, total, orientation = "vertical" }) { const upDisabled = index === 0; const downDisabled = index === total - 1; @@ -14,7 +14,7 @@ export default function FormListMoveArrows({ move, index, total }) { }; return ( - + diff --git a/client/src/components/labor-allocations-table/labor-allocations-table.payroll.component.jsx b/client/src/components/labor-allocations-table/labor-allocations-table.payroll.component.jsx index 3bcc32f14..02a9366f6 100644 --- a/client/src/components/labor-allocations-table/labor-allocations-table.payroll.component.jsx +++ b/client/src/components/labor-allocations-table/labor-allocations-table.payroll.component.jsx @@ -21,6 +21,8 @@ const mapStateToProps = createStructuredSelector({ technician: selectTechnician }); +const getRequestErrorMessage = (error) => error?.response?.data?.error || error?.message || ""; + export function PayrollLaborAllocationsTable({ jobId, joblines, @@ -43,16 +45,23 @@ export function PayrollLaborAllocationsTable({ }); const notification = useNotification(); - useEffect(() => { - async function CalculateTotals() { + const loadTotals = async () => { + try { const { data } = await axios.post("/payroll/calculatelabor", { jobid: jobId }); setTotals(data); + } catch (error) { + setTotals([]); + notification.error({ + title: getRequestErrorMessage(error) + }); } + }; + useEffect(() => { if (!!joblines && !!timetickets && !!bodyshop) { - CalculateTotals(); + loadTotals(); } if (!jobId) setTotals([]); }, [joblines, timetickets, bodyshop, adjustments, jobId]); @@ -210,28 +219,36 @@ export function PayrollLaborAllocationsTable({