Compare commits

...

17 Commits

Author SHA1 Message Date
Patrick Fic
4043bd3d33 Merged in feature/IO-3722-disable-contact-fortellis (pull request #3286)
IO-3722 Remove delivery date for bypass vehicles.

Approved-by: Dave Richer
2026-05-28 18:33:50 +00:00
Patrick Fic
c1c0b35c8f IO-3722 Remove delivery date for bypass vehicles. 2026-05-28 11:32:23 -07:00
Patrick Fic
4fd2f034a3 Merged in feature/IO-3722-disable-contact-fortellis (pull request #3283)
IO-3722 Remove customer lookup by Vehicle Owner.

Approved-by: Dave Richer
2026-05-28 16:55:21 +00:00
Patrick Fic
aa3b303fe9 IO-3722 Remove customer lookup by Vehicle Owner. 2026-05-28 09:53:40 -07:00
Patrick Fic
bd25245290 Merged in feature/IO-3722-disable-contact-fortellis (pull request #3281)
IO-3722 Fix undefined customer ref.
2026-05-27 21:19:02 +00:00
Patrick Fic
468ed23f73 IO-3722 Fix undefined customer ref. 2026-05-27 14:18:31 -07:00
Patrick Fic
6472b053ed Merged in feature/IO-3722-disable-contact-fortellis (pull request #3280)
Resolve inversed if statement.
2026-05-27 19:54:30 +00:00
Patrick Fic
322ebd3bc7 Resolve inversed if statement. 2026-05-27 12:46:09 -07:00
Patrick Fic
169070594c Merged in feature/IO-3722-disable-contact-fortellis (pull request #3279)
IO-3722 Add additional await.
2026-05-27 19:42:38 +00:00
Patrick Fic
0f800c5a4c IO-3722 Add additional await. 2026-05-27 12:40:41 -07:00
Dave Richer
0974e69a50 Merged in feature/IO-3722-disable-contact-fortellis (pull request #3277)
IO-3722 Disable contact API calls for Fortellis.
2026-05-27 18:36:51 +00:00
Patrick FIc
345a470731 IO-3722 Disable contact API calls for Fortellis. 2026-05-27 10:31:33 -07:00
Dave Richer
ebde2f1581 Merged in release/2026-05-22 (pull request #3257)
Release/2026 05 22
2026-05-25 12:45:19 +00:00
Allan Carr
a45808eb94 Merged in feature/IO-3710-Visual-Board-Vehicle-Color (pull request #3255)
IO-3710 Visual Board Vehicle Color

Approved-by: Dave Richer
2026-05-20 23:57:28 +00:00
Allan Carr
a2389b1f26 IO-3710 Visual Board Vehicle Color
Signed-off-by: Allan Carr <allan@imexsystems.ca>
2026-05-20 13:42:35 -07:00
Dave
ab606a4266 release/2026-05-22 - Remove uncessary require 2026-05-20 14:46:52 -04:00
Patrick Fic
da317704c4 Merged in feature/IO-3712-disable-analytics (pull request #3252)
IO-3712 Disable analytics in client side.

Approved-by: Dave Richer
2026-05-20 18:10:39 +00:00
7 changed files with 163 additions and 112 deletions

View File

@@ -157,36 +157,36 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
</Col> </Col>
{HasFeatureAccess({ featureName: "export", bodyshop }) && {HasFeatureAccess({ featureName: "export", bodyshop }) &&
ClosingPeriod.treatment === "on" && ( ClosingPeriod.treatment === "on" && (
<Col xs={24} sm={12} xl={8}> <Col xs={24} sm={12} xl={8}>
<Form.Item <Form.Item
key="ClosingPeriod" key="ClosingPeriod"
name={["accountingconfig", "ClosingPeriod"]} name={["accountingconfig", "ClosingPeriod"]}
label={t("bodyshop.fields.closingperiod")} label={t("bodyshop.fields.closingperiod")}
> >
<DatePicker.RangePicker format="MM/DD/YYYY" presets={DatePickerRanges} /> <DatePicker.RangePicker format="MM/DD/YYYY" presets={DatePickerRanges} />
</Form.Item> </Form.Item>
</Col> </Col>
)} )}
{HasFeatureAccess({ featureName: "export", bodyshop }) && {HasFeatureAccess({ featureName: "export", bodyshop }) &&
ADPPayroll.treatment === "on" && ( ADPPayroll.treatment === "on" && (
<Col xs={24} sm={12} xl={8}> <Col xs={24} sm={12} xl={8}>
<Form.Item <Form.Item
key="companyCode" key="companyCode"
name={["accountingconfig", "companyCode"]} name={["accountingconfig", "companyCode"]}
label={t("bodyshop.fields.companycode")} label={t("bodyshop.fields.companycode")}
> >
<Input /> <Input />
</Form.Item> </Form.Item>
</Col> </Col>
)} )}
{HasFeatureAccess({ featureName: "export", bodyshop }) && {HasFeatureAccess({ featureName: "export", bodyshop }) &&
ADPPayroll.treatment === "on" && ( ADPPayroll.treatment === "on" && (
<Col xs={24} sm={12} xl={8}> <Col xs={24} sm={12} xl={8}>
<Form.Item key="batchID" name={["accountingconfig", "batchID"]} label={t("bodyshop.fields.batchid")}> <Form.Item key="batchID" name={["accountingconfig", "batchID"]} label={t("bodyshop.fields.batchid")}>
<Input /> <Input />
</Form.Item> </Form.Item>
</Col> </Col>
)} )}
{HasFeatureAccess({ featureName: "export", bodyshop }) && !hasDMSKey && ( {HasFeatureAccess({ featureName: "export", bodyshop }) && !hasDMSKey && (
<> <>
<Col xs={24} sm={12} xl={8}> <Col xs={24} sm={12} xl={8}>
@@ -512,6 +512,15 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
> >
<InputNumber min={0} max={100} suffix="%" /> <InputNumber min={0} max={100} suffix="%" />
</Form.Item> </Form.Item>
{bodyshop.cdk_dealerid && (
<Form.Item
label={t("bodyshop.fields.dms.disablecontact")}
valuePropName="checked"
name={["cdk_configuration", "disablecontact"]}
>
<Switch />
</Form.Item>
)}
{bodyshop.pbs_serialnumber && ( {bodyshop.pbs_serialnumber && (
<Form.Item <Form.Item
label={t("bodyshop.fields.dms.disablecontactvehiclecreation")} label={t("bodyshop.fields.dms.disablecontactvehiclecreation")}

View File

@@ -44,9 +44,7 @@ export default function VehiclesListComponent({ loading, vehicles, total, refetc
key: "description", key: "description",
render: (text, record) => { render: (text, record) => {
return ( return (
<span>{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${ <span>{`${record.v_model_yr || ""} ${record.v_color || ""} ${record.v_make_desc || ""} ${record.v_model_desc || ""} `}</span>
record.v_model_desc || ""
} ${record.v_color || ""}`}</span>
); );
} }
}, },
@@ -111,7 +109,13 @@ export default function VehiclesListComponent({ loading, vehicles, total, refetc
> >
<ResponsiveTable <ResponsiveTable
loading={loading} loading={loading}
pagination={{ placement: "top", pageSize: currentPageSize, current: currentPage, showSizeChanger: true, total: total }} pagination={{
placement: "top",
pageSize: currentPageSize,
current: currentPage,
showSizeChanger: true,
total: total
}}
columns={columns} columns={columns}
mobileColumnKeys={["v_vin", "description", "plate_no"]} mobileColumnKeys={["v_vin", "description", "plate_no"]}
rowKey="id" rowKey="id"

View File

@@ -9,14 +9,13 @@ import {
} from "@firebase/auth"; } from "@firebase/auth";
import { arrayUnion, doc, getDoc, setDoc, updateDoc } from "@firebase/firestore"; import { arrayUnion, doc, getDoc, setDoc, updateDoc } from "@firebase/firestore";
import { getToken } from "@firebase/messaging"; import { getToken } from "@firebase/messaging";
import * as Sentry from "@sentry/react"; // import * as Sentry from "@sentry/react";
import { notification } from "antd"; import { notification } from "antd";
import axios from "axios"; import axios from "axios";
import i18next from "i18next"; import i18next from "i18next";
//import LogRocket from "logrocket"; //import LogRocket from "logrocket";
import { all, call, delay, put, select, takeLatest } from "redux-saga/effects"; import { all, call, delay, put, select, takeLatest } from "redux-saga/effects";
import { import {
//analytics,
auth, auth,
firestore, firestore,
getCurrentUser, getCurrentUser,

View File

@@ -370,6 +370,7 @@
"cashierid": "Cashier ID", "cashierid": "Cashier ID",
"default_journal": "Default Journal", "default_journal": "Default Journal",
"disablebillwip": "Disable bill WIP for A/P Posting", "disablebillwip": "Disable bill WIP for A/P Posting",
"disablecontact": "Disable Contact Updates/Creation",
"disablecontactvehiclecreation": "Disable Contact & Vehicle Updates/Creation", "disablecontactvehiclecreation": "Disable Contact & Vehicle Updates/Creation",
"dms_acctnumber": "DMS Account #", "dms_acctnumber": "DMS Account #",
"dms_control_override": "Static Control # Override", "dms_control_override": "Static Control # Override",

View File

@@ -370,6 +370,7 @@
"cashierid": "", "cashierid": "",
"default_journal": "", "default_journal": "",
"disablebillwip": "", "disablebillwip": "",
"disablecontact": "",
"disablecontactvehiclecreation": "", "disablecontactvehiclecreation": "",
"dms_acctnumber": "", "dms_acctnumber": "",
"dms_control_override": "", "dms_control_override": "",

View File

@@ -370,6 +370,7 @@
"cashierid": "", "cashierid": "",
"default_journal": "", "default_journal": "",
"disablebillwip": "", "disablebillwip": "",
"disablecontact": "",
"disablecontactvehiclecreation": "", "disablecontactvehiclecreation": "",
"dms_acctnumber": "", "dms_acctnumber": "",
"dms_control_override": "", "dms_control_override": "",

View File

@@ -15,7 +15,7 @@ const _ = require("lodash");
const moment = require("moment-timezone"); const moment = require("moment-timezone");
const replaceSpecialRegex = /[^a-zA-Z0-9 ]+/g; const replaceSpecialRegex = /[^a-zA-Z0-9 ]+/g;
const bypassCustomerId = "bypass";
// Helper function to handle FortellisApiError logging // Helper function to handle FortellisApiError logging
function handleFortellisApiError(socket, error, functionName, additionalDetails = {}) { function handleFortellisApiError(socket, error, functionName, additionalDetails = {}) {
if (error instanceof FortellisApiError) { if (error instanceof FortellisApiError) {
@@ -95,7 +95,8 @@ async function FortellisJobExport({ socket, redisHelpers, txEnvelope, jobid }) {
defaultFortellisTTL defaultFortellisTTL
); );
let DMSVehCustomer; let DMSVehCustomerFromVehicle;
//let DMSVehCustomer;
if (!DMSVid.newId) { if (!DMSVid.newId) {
CreateFortellisLogEvent(socket, "DEBUG", `{2.1} Querying the Vehicle using the DMSVid: ${DMSVid.vehiclesVehId}`); CreateFortellisLogEvent(socket, "DEBUG", `{2.1} Querying the Vehicle using the DMSVid: ${DMSVid.vehiclesVehId}`);
const DMSVeh = await QueryDmsVehicleById({ socket, redisHelpers, JobData, DMSVid }); const DMSVeh = await QueryDmsVehicleById({ socket, redisHelpers, JobData, DMSVid });
@@ -106,46 +107,66 @@ async function FortellisJobExport({ socket, redisHelpers, txEnvelope, jobid }) {
DMSVeh, DMSVeh,
defaultFortellisTTL defaultFortellisTTL
); );
DMSVehCustomerFromVehicle = DMSVeh?.owners && DMSVeh.owners.find((o) => o.id.assigningPartyId === "CURRENT");
const DMSVehCustomerFromVehicle = // //Add in contact bypass for Fortellis.
DMSVeh?.owners && DMSVeh.owners.find((o) => o.id.assigningPartyId === "CURRENT"); // if (!JobData.bodyshop.cdk_configuration.disablecontact) {
// const DMSVehCustomerFromVehicle =
// DMSVeh?.owners && DMSVeh.owners.find((o) => o.id.assigningPartyId === "CURRENT");
if (DMSVehCustomerFromVehicle?.id && DMSVehCustomerFromVehicle.id.value) { // if (DMSVehCustomerFromVehicle?.id && DMSVehCustomerFromVehicle.id.value) {
CreateFortellisLogEvent( // CreateFortellisLogEvent(
socket, // socket,
"DEBUG", // "DEBUG",
`{2.2} Querying the Customer using the ID from DMSVeh: ${DMSVehCustomerFromVehicle.id.value}` // `{2.2} Querying the Customer using the ID from DMSVeh: ${DMSVehCustomerFromVehicle.id.value}`
); // );
DMSVehCustomer = await QueryDmsCustomerById({ // DMSVehCustomer = await QueryDmsCustomerById({
socket, // socket,
redisHelpers, // redisHelpers,
JobData, // JobData,
CustomerId: DMSVehCustomerFromVehicle.id.value // CustomerId: DMSVehCustomerFromVehicle.id.value
}); // });
await setSessionTransactionData( // await setSessionTransactionData(
socket.id, // socket.id,
getTransactionType(jobid), // getTransactionType(jobid),
FortellisCacheEnums.DMSVehCustomer, // FortellisCacheEnums.DMSVehCustomer,
DMSVehCustomer, // DMSVehCustomer,
defaultFortellisTTL // defaultFortellisTTL
); // );
} // }
// }
} }
CreateFortellisLogEvent(socket, "DEBUG", `{2.3} Querying the Customer using the name.`); CreateFortellisLogEvent(socket, "DEBUG", `{2.3} Querying the Customer using the name.`);
if (JobData.bodyshop.cdk_configuration.disablecontact) {
//Just go straight to posting.
await FortellisSelectedCustomer({ socket, redisHelpers, selectedCustomerId: bypassCustomerId, jobid });
} else {
const DMSCustList = await QueryDmsCustomerByName({ socket, redisHelpers, JobData });
await setSessionTransactionData(
socket.id,
getTransactionType(jobid),
FortellisCacheEnums.DMSCustList,
DMSCustList,
defaultFortellisTTL
);
const DMSCustList = await QueryDmsCustomerByName({ socket, redisHelpers, JobData }); socket.emit("fortellis-select-customer",
await setSessionTransactionData( //Removed to save one one API call while disputing with fortellis.
socket.id, // [
getTransactionType(jobid), // // ...(DMSVehCustomer ? [{ ...DMSVehCustomer, vinOwner: true }] : []),
FortellisCacheEnums.DMSCustList, // ...DMSCustList
DMSCustList, // ]
defaultFortellisTTL DMSVehCustomerFromVehicle ?
); DMSCustList.map(c => {
//if customer id is the same as the current assigned owner on the vehicle id, set it as vinowner true. )
socket.emit("fortellis-select-customer", [ if (DMSVehCustomerFromVehicle?.id?.value === c.customerId) {
...(DMSVehCustomer ? [{ ...DMSVehCustomer, vinOwner: true }] : []), return { ...c, vinOwner: true }
...DMSCustList } else {
]); return c
}
}) : DMSCustList
);
}
} catch (error) { } catch (error) {
CreateFortellisLogEvent(socket, "ERROR", `Error in FortellisJobExport - ${error} `, { CreateFortellisLogEvent(socket, "ERROR", `Error in FortellisJobExport - ${error} `, {
error: error.message, error: error.message,
@@ -218,36 +239,40 @@ async function FortellisSelectedCustomer({ socket, redisHelpers, selectedCustome
}); });
return; return;
} }
//Bypass only the customer creation. We still need to create the vehicle and update it to post the service history later on.
let DMSCust; let DMSCust;
if (selectedCustomerId) { if (!JobData.bodyshop.cdk_configuration.disablecontact) {
CreateFortellisLogEvent(socket, "DEBUG", `{3.1} Querying the Customer using Customer ID: ${selectedCustomerId}`); if (selectedCustomerId) {
CreateFortellisLogEvent(socket, "DEBUG", `{3.1} Querying the Customer using Customer ID: ${selectedCustomerId}`);
//Get cust list from Redis. Return the item //Get cust list from Redis. Return the item
const DMSCustList = const DMSCustList =
(await getSessionTransactionData(socket.id, getTransactionType(jobid), FortellisCacheEnums.DMSCustList)) || []; (await getSessionTransactionData(socket.id, getTransactionType(jobid), FortellisCacheEnums.DMSCustList)) || [];
const existingCustomerInDMSCustList = DMSCustList.find((c) => c.customerId === selectedCustomerId); const existingCustomerInDMSCustList = DMSCustList.find((c) => c.customerId === selectedCustomerId);
DMSCust = existingCustomerInDMSCustList || { DMSCust = existingCustomerInDMSCustList || {
customerId: selectedCustomerId //This is the fall back in case it is the generic customer. customerId: selectedCustomerId //This is the fall back in case it is the generic customer.
}; };
await setSessionTransactionData( await setSessionTransactionData(
socket.id, socket.id,
getTransactionType(jobid), getTransactionType(jobid),
FortellisCacheEnums.DMSCust, FortellisCacheEnums.DMSCust,
DMSCust, DMSCust,
defaultFortellisTTL defaultFortellisTTL
); );
} else { } else {
CreateFortellisLogEvent(socket, "DEBUG", `{3.2} Creating new customer.`); CreateFortellisLogEvent(socket, "DEBUG", `{3.2} Creating new customer.`);
const DMSCustomerInsertResponse = await InsertDmsCustomer({ socket, redisHelpers, JobData }); const DMSCustomerInsertResponse = await InsertDmsCustomer({ socket, redisHelpers, JobData });
DMSCust = { customerId: DMSCustomerInsertResponse.data }; DMSCust = { customerId: DMSCustomerInsertResponse.data };
await setSessionTransactionData( await setSessionTransactionData(
socket.id, socket.id,
getTransactionType(jobid), getTransactionType(jobid),
FortellisCacheEnums.DMSCust, FortellisCacheEnums.DMSCust,
DMSCust, DMSCust,
defaultFortellisTTL defaultFortellisTTL
); );
}
}else{
DMSCust = { customerId: bypassCustomerId };
} }
let DMSVeh; let DMSVeh;
@@ -258,8 +283,12 @@ async function FortellisSelectedCustomer({ socket, redisHelpers, selectedCustome
DMSVeh = await getSessionTransactionData(socket.id, getTransactionType(jobid), FortellisCacheEnums.DMSVeh); DMSVeh = await getSessionTransactionData(socket.id, getTransactionType(jobid), FortellisCacheEnums.DMSVeh);
CreateFortellisLogEvent(socket, "DEBUG", `{4.3} Updating Existing Vehicle to associate to owner.`); CreateFortellisLogEvent(socket, "DEBUG", `{4.3} Updating Existing Vehicle to associate to owner.`);
//If it's a bypass scenario, skip this all.
//Check to see if the vehicle needs to be updated - i.e. the owner is not the selected customer. //Check to see if the vehicle needs to be updated - i.e. the owner is not the selected customer.
if (!DMSVeh?.owners.find((o) => o.id.value === DMSCust.customerId && o.id.assigningPartyId === "CURRENT")) { if (
selectedCustomerId !== bypassCustomerId &&
!DMSVeh?.owners.find((o) => o.id.value === DMSCust.customerId && o.id.assigningPartyId === "CURRENT")
) {
DMSVeh = await UpdateDmsVehicle({ DMSVeh = await UpdateDmsVehicle({
socket, socket,
redisHelpers, redisHelpers,
@@ -782,12 +811,14 @@ async function InsertDmsVehicle({ socket, redisHelpers, JobData, txEnvelope, DMS
// "chassis": "", // "chassis": "",
// "color": "", // "color": "",
// "dealerBodyStyle": "", // "dealerBodyStyle": "",
deliveryDate: ...(DMSCust?.customerId !== bypassCustomerId && {
txEnvelope.dms_unsold === true deliveryDate:
? "" txEnvelope.dms_unsold === true
: moment() ? ""
: moment()
// .tz(JobData.bodyshop.timezone) // .tz(JobData.bodyshop.timezone)
.format("YYYY-MM-DD"), .format("YYYY-MM-DD"),
}),
// "deliveryMileage": 4, // "deliveryMileage": 4,
// "doorsQuantity": 4, // "doorsQuantity": 4,
// "engineNumber": "", // "engineNumber": "",
@@ -902,14 +933,17 @@ async function InsertDmsVehicle({ socket, redisHelpers, JobData, txEnvelope, DMS
// "warrantyExpDate": "2015-01-12", // "warrantyExpDate": "2015-01-12",
// "wheelbase": "" // "wheelbase": ""
}, },
owners: [ // Owners is not required. Exclude it if we are bypassing.
{ ...(DMSCust?.customerId !== bypassCustomerId && {
id: { owners: [
assigningPartyId: "CURRENT", {
value: DMSCust.customerId id: {
assigningPartyId: "CURRENT",
value: DMSCust.customerId
}
} }
} ]
] })
//"inventoryAccount": "237" //"inventoryAccount": "237"
} }
}); });
@@ -1009,12 +1043,14 @@ async function UpdateDmsVehicle({ socket, redisHelpers, JobData, DMSVeh, DMSCust
modelAbrev: txEnvelope.dms_model modelAbrev: txEnvelope.dms_model
} }
: {}), : {}),
deliveryDate: ...(DMSCust?.customerId !== bypassCustomerId && {
txEnvelope.dms_unsold === true deliveryDate:
? "" txEnvelope.dms_unsold === true
: moment(DMSVehToSend.vehicle.deliveryDate) ? ""
: moment(DMSVehToSend.vehicle.deliveryDate)
//.tz(JobData.bodyshop.timezone) //.tz(JobData.bodyshop.timezone)
.toISOString() .toISOString()
})
}, },
owners: ids owners: ids
} }