From c29ac5f711cc61e5e52dfd2b32e710ac6aee97ba Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Thu, 22 Jan 2026 15:52:20 -0800 Subject: [PATCH 1/5] IO-3503 Job Costing Fixes Correction to handle CAD Signed-off-by: Allan Carr --- server/job/job-costing.js | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/server/job/job-costing.js b/server/job/job-costing.js index 674d6346e..729fa2112 100644 --- a/server/job/job-costing.js +++ b/server/job/job-costing.js @@ -267,7 +267,6 @@ function GenerateCostingData(job) { const materialsHours = { mapaHrs: 0, mashHrs: 0 }; let mashOpCodes = InstanceManager({ - imex: [], rome: ParseCalopCode(job.materials["MASH"]?.cal_opcode) }); let hasMapaLine = false; @@ -356,8 +355,14 @@ function GenerateCostingData(job) { if (val.mod_lbr_ty === "LAR") { materialsHours.mapaHrs += val.mod_lb_hrs || 0; } - if (val.mod_lbr_ty !== "LAR" && mashOpCodes.includes(val.lbr_op)) { - materialsHours.mashHrs += val.mod_lb_hrs || 0; + if (InstanceManager({ imex: true, rome: false })) { + if (val.mod_lbr_ty !== "LAR") { + materialsHours.mashHrs += val.mod_lb_hrs || 0; + } + } else { + if (val.mod_lbr_ty !== "LAR" && mashOpCodes.includes(val.lbr_op)) { + materialsHours.mashHrs += val.mod_lb_hrs || 0; + } } } @@ -535,7 +540,11 @@ function GenerateCostingData(job) { if (!hasMapaLine) { let threshold; - if (job.materials["MAPA"].cal_maxdlr !== undefined && job.materials["MAPA"].cal_maxdlr >= 0) { + if ( + job.materials["MAPA"] && + job.materials["MAPA"].cal_maxdlr !== undefined && + job.materials["MAPA"].cal_maxdlr >= 0 + ) { //It has an upper threshhold. threshold = Dinero({ amount: Math.round(job.materials["MAPA"].cal_maxdlr * 100) @@ -581,7 +590,11 @@ function GenerateCostingData(job) { } if (!hasMashLine) { let threshold; - if (job.materials["MASH"].cal_maxdlr !== undefined && job.materials["MASH"].cal_maxdlr >= 0) { + if ( + job.materials["MASH"] && + job.materials["MASH"].cal_maxdlr !== undefined && + job.materials["MASH"].cal_maxdlr >= 0 + ) { //It has an upper threshhold. threshold = Dinero({ amount: Math.round(job.materials["MASH"].cal_maxdlr * 100) From e1666baddd28b9bb60a9606a3f408f83d553ce2e Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Fri, 23 Jan 2026 14:17:03 -0800 Subject: [PATCH 2/5] IO-3503 Job Costing Fixes for CAD Signed-off-by: Allan Carr --- server/job/job-costing.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/server/job/job-costing.js b/server/job/job-costing.js index 729fa2112..6e3f30214 100644 --- a/server/job/job-costing.js +++ b/server/job/job-costing.js @@ -522,10 +522,7 @@ function GenerateCostingData(job) { } } - if (InstanceManager({ imex: true, rome: false })) { - //this might need to be removed for ImEX - jobLineTotalsByProfitCenter.parts[key] = jobLineTotalsByProfitCenter.parts[key].add(disc).add(markup); - } else { + if (InstanceManager({ rome: true })) { const correspondingCiecaStlTotalLine = job.cieca_stl?.data.find( (c) => c.ttl_typecd === convertedKey.toUpperCase() ); From ff57592c128dc73dcdcecc389a9d84465d42db64 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Fri, 23 Jan 2026 20:02:19 -0800 Subject: [PATCH 3/5] IO-3512 Page Title Fix Search UI to be consistent across product Signed-off-by: Allan Carr --- .../accounting-payables-table.component.jsx | 8 +++- .../accounting-payments-table.component.jsx | 8 +++- ...accounting-receivables-table.component.jsx | 1 + .../bills-list-table.component.jsx | 1 + .../contract-cars/contract-cars.component.jsx | 1 + .../contract-jobs/contract-jobs.component.jsx | 1 + .../contracts-list.component.jsx | 1 + .../job-detail-lines/job-lines.component.jsx | 1 + .../jobs-available-scan.component.jsx | 1 + .../jobs-available-table.component.jsx | 5 ++- .../parts-dispatch-table.component.jsx | 1 + .../parts-order-list-table.component.jsx | 1 + .../parts-queue.list.component.jsx | 1 + .../production-board-filters.component.jsx | 1 + .../profile-shops/profile-shops.component.jsx | 1 + .../shop-info/shop-info.general.component.jsx | 37 ++----------------- ...p-info.responsibilitycenters.component.jsx | 32 ++++++++++++++++ .../export-logs.page.component.jsx | 1 + .../jobs-available.page.container.jsx | 37 +++++++++++-------- .../phonebook/phonebook.page.component.jsx | 1 + 20 files changed, 89 insertions(+), 52 deletions(-) diff --git a/client/src/components/accounting-payables-table/accounting-payables-table.component.jsx b/client/src/components/accounting-payables-table/accounting-payables-table.component.jsx index a2ab52d30..07439658b 100644 --- a/client/src/components/accounting-payables-table/accounting-payables-table.component.jsx +++ b/client/src/components/accounting-payables-table/accounting-payables-table.component.jsx @@ -169,7 +169,13 @@ export function AccountingPayablesTableComponent({ bodyshop, loading, bills, ref refetch={refetch} /> {bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && } - + } > diff --git a/client/src/components/accounting-payments-table/accounting-payments-table.component.jsx b/client/src/components/accounting-payments-table/accounting-payments-table.component.jsx index caf8ae6df..dedeeac1d 100644 --- a/client/src/components/accounting-payments-table/accounting-payments-table.component.jsx +++ b/client/src/components/accounting-payments-table/accounting-payments-table.component.jsx @@ -182,7 +182,13 @@ export function AccountingPayablesTableComponent({ bodyshop, loading, payments, refetch={refetch} /> {bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && } - + } > diff --git a/client/src/components/accounting-receivables-table/accounting-receivables-table.component.jsx b/client/src/components/accounting-receivables-table/accounting-receivables-table.component.jsx index 835a7392a..ce506e3ad 100644 --- a/client/src/components/accounting-receivables-table/accounting-receivables-table.component.jsx +++ b/client/src/components/accounting-receivables-table/accounting-receivables-table.component.jsx @@ -204,6 +204,7 @@ export function AccountingReceivablesTableComponent({ bodyshop, loading, jobs, r onChange={handleSearch} placeholder={t("general.labels.search")} allowClear + enterButton /> } diff --git a/client/src/components/bills-list-table/bills-list-table.component.jsx b/client/src/components/bills-list-table/bills-list-table.component.jsx index 9de0b7b1c..283949d91 100644 --- a/client/src/components/bills-list-table/bills-list-table.component.jsx +++ b/client/src/components/bills-list-table/bills-list-table.component.jsx @@ -232,6 +232,7 @@ export function BillsListTableComponent({ e.preventDefault(); setSearchText(e.target.value); }} + enterButton /> } diff --git a/client/src/components/contract-cars/contract-cars.component.jsx b/client/src/components/contract-cars/contract-cars.component.jsx index 12ed17e89..f43ac2945 100644 --- a/client/src/components/contract-cars/contract-cars.component.jsx +++ b/client/src/components/contract-cars/contract-cars.component.jsx @@ -99,6 +99,7 @@ export default function ContractsCarsComponent({ loading, data, selectedCarId, h placeholder={t("general.labels.search")} value={state.search} onChange={(e) => setState({ ...state, search: e.target.value })} + enterButton /> } > diff --git a/client/src/components/contract-jobs/contract-jobs.component.jsx b/client/src/components/contract-jobs/contract-jobs.component.jsx index 8ed060873..398fcac82 100644 --- a/client/src/components/contract-jobs/contract-jobs.component.jsx +++ b/client/src/components/contract-jobs/contract-jobs.component.jsx @@ -123,6 +123,7 @@ export default function ContractsJobsComponent({ loading, data, selectedJob, han placeholder={t("general.labels.search")} value={state.search} onChange={(e) => setState({ ...state, search: e.target.value })} + enterButton /> } > diff --git a/client/src/components/contracts-list/contracts-list.component.jsx b/client/src/components/contracts-list/contracts-list.component.jsx index 6b7e69dd7..313393245 100644 --- a/client/src/components/contracts-list/contracts-list.component.jsx +++ b/client/src/components/contracts-list/contracts-list.component.jsx @@ -164,6 +164,7 @@ export function ContractsList({ bodyshop, loading, contracts, refetch, total, se const updatedSearch = { ...search, search: value }; history({ search: queryString.stringify(updatedSearch) }); }} + enterButton /> } 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 2675f30cf..735374b11 100644 --- a/client/src/components/job-detail-lines/job-lines.component.jsx +++ b/client/src/components/job-detail-lines/job-lines.component.jsx @@ -682,6 +682,7 @@ export function JobLinesComponent({ e.preventDefault(); setSearchText(e.target.value); }} + enterButton /> } diff --git a/client/src/components/jobs-available-scan/jobs-available-scan.component.jsx b/client/src/components/jobs-available-scan/jobs-available-scan.component.jsx index 23aa15168..763a45d10 100644 --- a/client/src/components/jobs-available-scan/jobs-available-scan.component.jsx +++ b/client/src/components/jobs-available-scan/jobs-available-scan.component.jsx @@ -136,6 +136,7 @@ export function JobsAvailableScan({ partnerVersion, refetch }) { onChange={(e) => { setSearchText(e.currentTarget.value); }} + enterButton /> } diff --git a/client/src/components/jobs-available-table/jobs-available-table.component.jsx b/client/src/components/jobs-available-table/jobs-available-table.component.jsx index 55e8c9152..918f21ec7 100644 --- a/client/src/components/jobs-available-table/jobs-available-table.component.jsx +++ b/client/src/components/jobs-available-table/jobs-available-table.component.jsx @@ -196,13 +196,16 @@ export function JobsAvailableComponent({ bodyshop, loading, data, refetch, addJo > {t("general.actions.deleteall")} - { setSearchText(e.currentTarget.value); }} + enterButton /> + + + } > diff --git a/client/src/components/parts-dispatch-table/parts-dispatch-table.component.jsx b/client/src/components/parts-dispatch-table/parts-dispatch-table.component.jsx index df32c0705..c1fbf51fe 100644 --- a/client/src/components/parts-dispatch-table/parts-dispatch-table.component.jsx +++ b/client/src/components/parts-dispatch-table/parts-dispatch-table.component.jsx @@ -101,6 +101,7 @@ export function PartDispatchTableComponent({ bodyshop, job, billsQuery }) { e.preventDefault(); setSearchText(e.target.value); }} + enterButton /> } diff --git a/client/src/components/parts-order-list-table/parts-order-list-table.component.jsx b/client/src/components/parts-order-list-table/parts-order-list-table.component.jsx index 0def7afd4..55f910f9f 100644 --- a/client/src/components/parts-order-list-table/parts-order-list-table.component.jsx +++ b/client/src/components/parts-order-list-table/parts-order-list-table.component.jsx @@ -295,6 +295,7 @@ export function PartsOrderListTableComponent({ e.preventDefault(); setSearchText(e.target.value); }} + enterButton /> } diff --git a/client/src/components/parts-queue-list/parts-queue.list.component.jsx b/client/src/components/parts-queue-list/parts-queue.list.component.jsx index 1889131fb..6459d7a96 100644 --- a/client/src/components/parts-queue-list/parts-queue.list.component.jsx +++ b/client/src/components/parts-queue-list/parts-queue.list.component.jsx @@ -269,6 +269,7 @@ export function PartsQueueListComponent({ bodyshop }) { return ( - - } - /> + {!partnerVersion && ( + } diff --git a/client/src/pages/phonebook/phonebook.page.component.jsx b/client/src/pages/phonebook/phonebook.page.component.jsx index 98268f8b3..9e7901f89 100644 --- a/client/src/pages/phonebook/phonebook.page.component.jsx +++ b/client/src/pages/phonebook/phonebook.page.component.jsx @@ -167,6 +167,7 @@ export function PhonebookPageComponent({ bodyshop, authLevel }) { searchParams.page = 1; history({ search: queryString.stringify(searchParams) }); }} + enterButton /> } From 2acddcb9ac013750d4a743ced4ce84823222f6a8 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Fri, 23 Jan 2026 22:51:53 -0800 Subject: [PATCH 4/5] IO-3509 Duplicate Job Open Estimate Date Signed-off-by: Allan Carr --- .../jobs-detail-header-actions.duplicate.util.js | 3 +++ server/job/job-totals-USA.js | 4 ++-- server/job/job-totals.js | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.duplicate.util.js b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.duplicate.util.js index 8e0705e79..8edbe1199 100644 --- a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.duplicate.util.js +++ b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.duplicate.util.js @@ -31,9 +31,12 @@ export default async function DuplicateJob({ delete existingJob.updatedat; delete existingJob.cieca_stl; delete existingJob.cieca_ttl; + !keepJobLines && delete existingJob.clm_total; const newJob = { ...existingJob, + date_open: dayjs(), + date_estimated: dayjs(), status: defaultOpenStatus }; diff --git a/server/job/job-totals-USA.js b/server/job/job-totals-USA.js index 27fced83e..a8bd632cc 100644 --- a/server/job/job-totals-USA.js +++ b/server/job/job-totals-USA.js @@ -47,14 +47,14 @@ exports.totalsSsu = async function (req, res) { throw new Error("Failed to update job totals"); } - res.status(200).send(); + res.status(200).json({ success: true }); } catch (error) { logger.log("job-totals-ssu-USA-error", "error", req?.user?.email, id, { jobid: id, error: error.message, stack: error.stack }); - res.status(503).send(); + res.status(503).json({ error: "Failed to calculate totals" }); } }; diff --git a/server/job/job-totals.js b/server/job/job-totals.js index c11d8d7de..35cc4e6c1 100644 --- a/server/job/job-totals.js +++ b/server/job/job-totals.js @@ -47,14 +47,14 @@ exports.totalsSsu = async function (req, res) { throw new Error("Failed to update job totals"); } - res.status(200).send(); + res.status(200).json({ success: true }); } catch (error) { logger.log("job-totals-ssu-error", "error", req.user.email, id, { jobid: id, error: error.message, stack: error.stack }); - res.status(503).send(); + res.status(503).json({ error: "Failed to calculate totals" }); } }; From cca23a5b1133d1fd95172cee0aec940af09615d1 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Fri, 23 Jan 2026 23:07:11 -0800 Subject: [PATCH 5/5] IO-3509 Correction for date_estimate to handle tz correctly Signed-off-by: Allan Carr --- .../job-create-iou/job-create-iou.component.jsx | 3 ++- .../jobs-detail-header-actions.component.jsx | 4 ++-- .../jobs-detail-header-actions.duplicate.util.js | 8 ++++---- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/client/src/components/job-create-iou/job-create-iou.component.jsx b/client/src/components/job-create-iou/job-create-iou.component.jsx index cbe1c570d..d44dfa6ff 100644 --- a/client/src/components/job-create-iou/job-create-iou.component.jsx +++ b/client/src/components/job-create-iou/job-create-iou.component.jsx @@ -50,7 +50,8 @@ export function JobCreateIOU({ bodyshop, currentUser, job, selectedJobLines, tec config: { status: bodyshop.md_ro_statuses.default_open, bodyshopid: bodyshop.id, - useremail: currentUser.email + useremail: currentUser.email, + timezone: bodyshop.timezone }, currentUser }); diff --git a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx index 6855fdfe9..25f9e22a1 100644 --- a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx +++ b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx @@ -264,7 +264,7 @@ export function JobsDetailHeaderActions({ DuplicateJob({ apolloClient: client, jobId: job.id, - config: { defaultOpenStatus: bodyshop.md_ro_statuses.default_imported }, + config: { defaultOpenStatus: bodyshop.md_ro_statuses.default_imported, timezone: bodyshop.timezone }, completionCallback: (newJobId) => { history(`/manage/jobs/${newJobId}`); notification.success({ @@ -279,7 +279,7 @@ export function JobsDetailHeaderActions({ DuplicateJob({ apolloClient: client, jobId: job.id, - config: { defaultOpenStatus: bodyshop.md_ro_statuses.default_imported }, + config: { defaultOpenStatus: bodyshop.md_ro_statuses.default_imported, timezone: bodyshop.timezone }, completionCallback: (newJobId) => { history(`/manage/jobs/${newJobId}`); notification.success({ diff --git a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.duplicate.util.js b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.duplicate.util.js index 8edbe1199..cbc2ed23c 100644 --- a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.duplicate.util.js +++ b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.duplicate.util.js @@ -15,7 +15,7 @@ export default async function DuplicateJob({ }) { logImEXEvent("job_duplicate"); - const { defaultOpenStatus } = config; + const { defaultOpenStatus, timezone } = config; //get a list of all fields on the job const res = await apolloClient.query({ query: QUERY_JOB_FOR_DUPE, @@ -35,8 +35,8 @@ export default async function DuplicateJob({ const newJob = { ...existingJob, + date_estimated: dayjs().tz(timezone, false).format("YYYY-MM-DD"), date_open: dayjs(), - date_estimated: dayjs(), status: defaultOpenStatus }; @@ -73,7 +73,7 @@ export default async function DuplicateJob({ export async function CreateIouForJob({ apolloClient, jobId, config, jobLinesToKeep, currentUser }) { logImEXEvent("job_create_iou"); - const { status } = config; + const { status, timezone } = config; //get a list of all fields on the job const res = await apolloClient.query({ query: QUERY_JOB_FOR_DUPE, @@ -91,10 +91,10 @@ export async function CreateIouForJob({ apolloClient, jobId, config, jobLinesToK const newJob = { ...existingJob, - converted: true, status: status, iouparent: jobId, + date_estimated: dayjs().tz(timezone, false).format("YYYY-MM-DD"), date_open: dayjs(), audit_trails: { data: [